![](/img/trans.png)
[英]Spring Boot shows the String instead of the HTML file from an Angular2 Single Page app
[英]Spring Boot with redirecting with single page angular2
我有一個帶有 Spring 引導的單頁 Angular 應用程序。 它如下所示:
src
main
java
controller
HomeController
CustomerController
OtherController
webapp
js/angular-files.js
index.html
Spring 引導正確默認為 webapp 文件夾並提供 index.html 文件。
我想做的是:
對於每個不以/api
開頭的本地 REST 請求覆蓋並重定向到默認 webapp/index.html。 我計划為 spring 控制器提供任何/api
服務。
有沒有辦法給所有控制器加上 API 前綴,這樣我就不必每次都寫 API 了? 例如
@RequestMapping("/api/home") 可以在代碼中寫速記 @RequestMapping("/home")
或者
@RequestMapping("/api/other-controller/:id") can write shorthand @RequestMapping("/other-controller/:id")
I'm looking for every API request, eg 1) http://localhost:8080/api/home keep API with API and resolve to correct controller and return JSON, however if someone enters a URL like http:///localhost/ some-url或http:///localhost/some-other/123/url然后它將提供 index.html 頁面並保留 URL。
替代方法:嘗試添加 #ErrorViewResolver: Springboot/Angular2 - How to handle HTML5 urls?
經過幾個小時的努力,我試圖遵循來自數十篇堆棧溢出和博客文章的所有分散的建議,我終於找到了最小的 PURE spring boot + angular 6 應用程序,在非根頁面上刷新后總是重定向到 index.html同時維護所有REST API
端點路徑。 沒有@EnableWebMvc
,沒有@ControllerAdvice
,沒有改變application.properties
,沒有自定義ResourceHandlerRegistry
修改,只是簡單:
您*必須*將ng build
的輸出包含到 Spring 的resources/static
文件夾中。 您可以通過maven-resources-plugin
完成此操作。 在此處學習: 使用 maven 將多個資源目錄復制到獨立的目標目錄
@Controller
@SpringBootApplication
public class MyApp implements ErrorController {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
private static final String PATH = "/error";
@RequestMapping(value = PATH)
public String error() {
return "forward:/index.html";
}
@Override
public String getErrorPath() {
return PATH;
}
}
resources/static
中可以使 spring 視圖重定向( "forward:/index.html"
)成功。 似乎 spring 無法重定向到資源文件夾之外的任何內容,因此如果您嘗試訪問站點根目錄下的頁面,它將無法正常工作。@EnableWebMvc
或更改application.properties
)導航到/
自動提供 index.html (如果它包含在resources/static
文件夾中),因此無需在那里進行更改。/error
並且實現ErrorController
會覆蓋該行為 - 你猜對了 - 路由到index.html
,它允許Angular
接管路由。HashLocationStrategy
來解決這個問題,因為 Angular 不推薦它: https : HashLocationStrategy
對於每個不以 /api 開頭的本地 REST 請求,覆蓋並重定向到默認的 webapp/index.html。 我計划為 spring 控制器提供任何/api。
2017 年 5 月 15 日更新
讓我重新表述您對其他讀者的查詢。 (如果誤解了,請糾正我)
背景
使用 Spring Boot 和從類路徑提供靜態資源
要求
所有404
非 api請求都應重定向到index.html
。
非 API - 表示 URL 不以/api
開頭的請求。
API - 404 應該像往常一樣拋出404
。
樣本響應
/api/something
- 會拋出404
/index.html
- 將服務器 index.html
/something
- 將重定向到index.html
我的解決方案
如果給定資源沒有可用的處理程序,則讓 Spring MVC 拋出異常。
將以下內容添加到application.properties
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
添加ControllerAdvice
如下
@ControllerAdvice
public class RedirectOnResourceNotFoundException {
@ExceptionHandler(value = NoHandlerFoundException.class)
public Object handleStaticResourceNotFound(final NoHandlerFoundException ex, HttpServletRequest req, RedirectAttributes redirectAttributes) {
if (req.getRequestURI().startsWith("/api"))
return this.getApiResourceNotFoundBody(ex, req);
else {
redirectAttributes.addFlashAttribute("errorMessage", "My Custom error message");
return "redirect:/index.html";
}
}
private ResponseEntity<String> getApiResourceNotFoundBody(NoHandlerFoundException ex, HttpServletRequest req) {
return new ResponseEntity<>("Not Found !!", HttpStatus.NOT_FOUND);
}
}
您可以根據需要自定義錯誤消息。
有沒有辦法用 api 為所有控制器添加前綴,這樣我就不必每次都編寫 api。
為此,您可以創建一個BaseController
並將 RequestMapping 路徑設置為/api
例子
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api")
public abstract class BaseController {}
並擴展此BaseController
並確保您沒有使用@RequestMapping
注釋子類
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FirstTestController extends BaseController {
@RequestMapping(path = "/something")
public String sayHello() {
return "Hello World !!";
}
}
上一個答案
如果請求路徑不是 startsWith /api
您可以創建一個重定向到/index.html
的Filter
。
// CODE REMOVED. Check Edit History If you want.
試試這個
@SpringBootApplication
@Controller
class YourSpringBootApp {
// Match everything without a suffix (so not a static resource)
@RequestMapping(value = "/**/{path:[^.]*}")
public String redirect() {
// Forward to home page so that route is preserved.(i.e forward:/intex.html)
return "forward:/";
}
}
@Controller
public class RedirectController {
/*
* Redirects all routes to FrontEnd except: '/', '/index.html', '/api', '/api/**'
*/
@RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
public String redirectApi() {
return "forward:/";
}
}
對我有用的解決方案是覆蓋 Spring Boot 的BasicErrorController :
@Component
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes, new ErrorProperties());
}
@RequestMapping(produces = "text/html")
@Override
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NOT_FOUND) {
return new ModelAndView("forward:/");
} else {
return super.errorHtml(request, response);
}
}
}
方法errorHtml僅攔截未找到的請求,並且對於來自 api 的響應 404(未找到)是透明的。
最合理的解決方案,恕我直言,適用於Spring Boot 2+ (代碼在 Kotlin 中):
@Component
class ForwardErrorsToIndex : ErrorViewResolver {
override fun resolveErrorView(request: HttpServletRequest?,
status: HttpStatus?,
model: MutableMap<String, Any>?): ModelAndView {
return ModelAndView("forward:/index.html")
}
}
在這個線程上為時已晚,但認為它可能會幫助某人
嘗試了很多解決方案,但這看起來很簡單,對我來說很棒
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
import java.io.IOException;
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
@Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
學分: https : //keeprising.in/java/springboot/make-spring-boot-surrender-routing-control-to-angular/
對於整個應用程序,您可以在 application.properties 中添加上下文路徑
server.contextPath=/api
它將在http://localhost:8080/api/home之后的每個請求的 URL 附加“/api”
對於重定向,
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/home");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
把這堆代碼放在 WebMVCConfig.java 中
在@Configuration bean 中,您可以添加一個 ServletRegistrationBean 來為 /api/* resquest 制作 spring 服務器,然后在控制器中您不需要添加它。
@Bean
public ServletRegistrationBean dispatcherRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet());
registration.addUrlMappings("/api/*");
registration.setLoadOnStartup(1);
registration.setName("mvc-dispatcher");
return registration;
}
我不知道為什么,但是如果不添加更多代碼,根 url "/" 將無法解析。 這就是我最終的結果。
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.CacheControl;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
@EnableWebMvc
@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
@Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
@Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
好的,讓我們從您問題的簡單部分開始:
有沒有辦法用 api 為所有控制器添加前綴,這樣我就不必每次都編寫 api?
答案是肯定的,只需用“全局” @RequestMapping
注釋標記您的控制器,例如:
@RestController
@RequestMapping("/api")
public class ApiController{
@RequestMapping("/hello")
public String hello(){
return "hello simple controller";
}
@RequestMapping("/hello2")
public String hello2(){
return "hello2 simple controller";
}
}
在上面的示例中,您可以使用以下 URL 調用 hello 方法: /api/hello
以及帶有此 URL 的第二種方法: /api/hello2
這就是我不必用/api
前綴標記每個方法的方式。
現在,對於您問題的更復雜部分:
如果請求不以/api
前綴開頭,如何實現重定向?
您可以通過返回重定向的 HTTP 狀態代碼 (302) 來實現,畢竟 angularJs 本身就“說”REST,因此您不能像以前那樣強制從 Java/Spring 代碼進行重定向。
然后只返回一個狀態碼為 302 的 HTTP 消息,並在你的 angularJS 上進行實際的重定向。
例如:
在 AngularJS 上:
var headers = {'Content-Type':'application/json', 'Accept':'application/json'}
var config = {
method:'GET'
url:'http://localhost:8080/hello',
headers:headers
};
http(config).then(
function onSuccess(response){
if(response.status == 302){
console.log("Redirect");
$location("/")
}
}, function onError(response){
console.log("An error occured while trying to open a new game room...");
});
春天:
@RestController
@RequestMapping("/api")
public class ApiController{
@RequestMapping("/hello")
public ResponseEntity<String> hello(){
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "application/json");
return new ResponseEntity<String>("", header, HttpStatus.FOUND);
}
}
當然,您需要根據您的項目對其進行自定義。
您需要嘗試的只是將index.html
放到src/main/resources/static/
參見示例: https : //github.com/reflexdemon/shop/tree/master/src/main/resources/static
在我的package.josn
我嘗試將其復制到此位置。
參見 PackageJSON: https : //github.com/reflexdemon/shop/blob/master/package.json#L14
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.