Java 带单页角度重定向的弹簧靴2
我有一个带有Spring Boot的单页Angular应用程序。如下所示:Java 带单页角度重定向的弹簧靴2,java,spring,angular,spring-mvc,spring-boot,Java,Spring,Angular,Spring Mvc,Spring Boot,我有一个带有Spring Boot的单页Angular应用程序。如下所示: src main java controller HomeController CustomerController OtherController webapp js/angular-files.js index.html Spring boot正确默认为webapp文件夹,并提供index.html文件 我希望做的是: 对于不是以/api
src
main
java
controller
HomeController
CustomerController
OtherController
webapp
js/angular-files.js
index.html
Spring boot正确默认为webapp文件夹,并提供index.html文件
我希望做的是:
/api
开头的每个本地REST请求,覆盖并重定向到默认的webapp/index.html。我计划为spring控制器提供任何/api
对于整个应用程序,您可以在application.properties中添加上下文路径 server.contextPath=/api 之后,它将向每个请求的URL追加“/api” 对于重定向
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/home");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
将这组代码放在WebMVCConfig.java中,试试这个
@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:/";
}
}
对于每个不以/api开头的本地REST请求,覆盖并重定向到默认的webapp/index.html。我计划为spring控制器提供任何东西/api
2017年5月15日更新
让我为其他读者重新表述一下你的疑问。(如果误解,请纠正我)
背景使用Spring引导并从类路径提供静态资源 要求
所有
404
非api请求都应重定向到index.html
非API-表示URL不以/API
开头的请求API-404应该像往常一样抛出
404
样本响应/api/something
-将抛出404
/index.html
-将服务器index.html/something
-将重定向到index.html
我的解决方案
如果给定资源没有可用的处理程序,让SpringMVC抛出异常
将以下内容添加到应用程序属性中
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);
}
}
并扩展此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 !!";
}
}
先前的答案
如果请求路径未通过/api
启动,您可以创建一个过滤器,该过滤器将重定向到/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消息,在AngularJ上执行实际的重定向
例如:
@RestController
@RequestMapping("/api")
public class ApiController{
@RequestMapping("/hello")
public String hello(){
return "hello simple controller";
}
@RequestMapping("/hello2")
public String hello2(){
return "hello2 simple controller";
}
}
关于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);
}
}
在春天:
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);
}
}
@RestController
@请求映射(“/api”)
公共类ApiController{
@请求映射(“/hello”)
公共响应你好{
HttpHeaders header=新的HttpHeaders();
添加(“内容类型”、“应用程序/json”);
返回新的ResponseEntity(“,header,HttpStatus.FOUND);
}
}
当然,您需要为您的项目定制它。您只需将index.html
放到src/main/resources/static/
参见示例:
在我的package.josn
中,我尝试将它复制到这个位置
请参见PackageJSON:在@Configuration bean中,您可以添加一个ServletRegistrationBean,使spring服务器仅用于/api/*resquest,然后在控制器中,您无需添加它
@Bean
public ServletRegistrationBean dispatcherRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet());
registration.addUrlMappings("/api/*");
registration.setLoadOnStartup(1);
registration.setName("mvc-dispatcher");
return registration;
}
如果你厌倦了通过遵循这么多相互冲突的解决方案来解决这个问题,请看这里!!
经过数小时的努力,我终于找到了一个最小的纯spring boot+angular 6应用程序,它可以在非根页面刷新后始终重定向到index.html,同时维护所有REST API
端点路径。没有@EnableWebMvc
,没有@ControllerAdvice
,没有更改应用程序。属性
,没有自定义ResourceHandlerRegistry
修改,只是简单:
非常重要的先决条件
您*必须*将ng build
的输出包含在Spring的resources/static
文件夹中。您可以通过maven资源插件
实现这一点。在这里学习:
代码
推理
- 在构建时将ng build的输出包含到
资源/static
中,可以使spring视图重定向(“forward:/index.html”
)成功。spring似乎无法重定向到resources文件夹之外的任何内容,因此如果您试图访问站点根目录下的页面,它将无法工作
- 具有默认功能(即不添加
@EnableWebMvc
或更改应用程序.属性
)navi
@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;
}
}
@Controller
public class RedirectController {
/*
* Redirects all routes to FrontEnd except: '/', '/index.html', '/api', '/api/**'
*/
@RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
public String redirectApi() {
return "forward:/";
}
}
@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);
}
}
}
@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");
}
});
}
}