SpringBoot WebMvcConfigurer详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot WebMvcConfigurer详解相关的知识,希望对你有一定的参考价值。
参考技术AWebMvcConfigurer配置类其实是 Spring 内部的一种配置方式,采用 JavaBean 的形式来代替传统的 xml 配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。基于java-based方式的spring mvc配置,需要创建一个 配置 类并实现 WebMvcConfigurer 接口;
在Spring Boot 1.5版本都是靠重写 WebMvcConfigurerAdapter 的方法来添加自定义拦截器,消息转换器等。SpringBoot 2.0 后,该类被标记为@Deprecated(弃用)。官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport,方式一实现WebMvcConfigurer接口(推荐),方式二继承WebMvcConfigurationSupport类,具体实现可看这篇文章。 https://blog.csdn.net/fmwind/article/details/82832758
常用的方法:
以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个方法跳转到页面,感觉好麻烦,其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了
值的指出的是,在这里重写addViewControllers方法,并不会覆盖 WebMvcAutoConfiguration (Springboot自动配置)中的addViewControllers(在此方法中,Spring Boot将“/”映射至index.html),这也就意味着自己的配置和Spring Boot的自动配置同时有效,这也是我们推荐添加自己的MVC配置的方式。
比如,我们想自定义静态资源映射目录的话,只需重写addResourceHandlers方法即可。
注:如果继承WebMvcConfigurationSupport类实现配置时必须要重写该方法,具体见其它文章
此时会注册一个默认的Handler:DefaultServletHttpRequestHandler,这个Handler也是用来处理静态文件的,它会尝试映射/。当DispatcherServelt映射/时(/ 和/ 是有区别的),并且没有找到合适的Handler来处理请求时,就会交给DefaultServletHttpRequestHandler 来处理。注意:这里的静态资源是放置在web根目录下,而非WEB-INF 下。
可能这里的描述有点不好懂(我自己也这么觉得),所以简单举个例子,例如:在webroot目录下有一个图片:1.png 我们知道Servelt规范中web根目录(webroot)下的文件可以直接访问的,但是由于DispatcherServlet配置了映射路径是:/ ,它几乎把所有的请求都拦截了,从而导致1.png 访问不到,这时注册一个DefaultServletHttpRequestHandler 就可以解决这个问题。其实可以理解为DispatcherServlet破坏了Servlet的一个特性(根目录下的文件可以直接访问),DefaultServletHttpRequestHandler是帮助回归这个特性的。
这个方法是用来配置视图解析器的,该方法的参数ViewResolverRegistry 是一个注册器,用来注册你想自定义的视图解析器等。ViewResolverRegistry 常用的几个方法: https://blog.csdn.net/fmwind/article/details/81235401
跨域资源共享向来都是热门的需求,我们可以使用 CORS 来快速实现 跨域访问,只需要在服务端进行授权即可,无需在前端添加额外的设置
简单说,CORS是一种访问机制,英文全称: Cross-Origin Resource Sharing,即我们说的跨域资源共享。当一个资源从与该资源本身所在服务器不同的域或端口请求一个资源时,资源会发起一个跨域HTTP请求。比如,在一个域名下的网页中,调用另一个域名中的资源。
对于 CORS的跨域请求,上面的方式是重写webMvcConfigurer实现全局配置,这里展开一下,主要有以下几种方式可供选择:
在任意配置类,返回一个 新的 CorsFIlter Bean ,并添加映射路径和具体的CORS配置路径。
参考上面,此处省略
在控制器上使用注解 @CrossOrigin :
在Controller方法上使用注解 @CrossOrigin :
使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权原始域,这里 Origin的值也可以设置为 "*",表示全部放行。
如何在本地主机上启用 Spring 和 Angular 2 之间的 CORS
【中文标题】如何在本地主机上启用 Spring 和 Angular 2 之间的 CORS【英文标题】:How to enable CORS between Spring and Angular 2 on localhost 【发布时间】:2021-02-14 15:43:48 【问题描述】:我在 Spring 4.3.4.RELEASE 和 Spring 安全版本 4.2.2.RELEASE 上有一个 Java 后端的旧项目。没有办法更新库,我必须使用现有的。该项目不是 REST API,没有 RestController 也没有 WebMvcConfigurer。所以,我按照here 的建议配置了 cors:
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
protected SecurityConfiguration()
super();
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers(HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
.anyRequest().permitAll();
httpSecurity.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
Cors 过滤器:
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter extends OncePerRequestFilter
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CorsFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
logger.error("CORS filter: " + request.getMethod());
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With, xsrf-token");
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
if ("OPTIONS".equals(request.getMethod()))
response.setStatus(HttpServletResponse.SC_OK);
else
filterChain.doFilter(request, response);
在 web.xml 中所有 context-param 之后和 listeners 之前(这是应用程序中的唯一过滤器):
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>web.servlet.response.CorsFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我在 localhost:8080 上运行后端,在 localhost:8081 上运行前端 但是,当我尝试发送带有 application/json 的 POST 请求时,浏览器控制台中出现错误
Access to XMLHttpRequest at 'http://localhost:8080/rpc' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
另外,我希望在后端看到日志“CORS filter: POST”,我把它放在那里检查它是否会进入过滤器,但没有这样的日志。
请,关于为什么它不起作用的任何建议?我需要在请求中坚持 application/json ,并且有时在应用程序中还有一个 Authorization 标头,因此无法完全避免 cors。这可能是 Angular 2 的问题吗?
【问题讨论】:
【参考方案1】:我不熟悉spring或java,但我想我理解这个问题。
我假设您的日志过滤器不起作用,因为 spring 框架在您的过滤器执行之前短路了该请求。
这里的问题可能在配置中的某个地方,但我认为解决给定问题的方法通常是不正确的。
CORS 是出于某些目的而创建的,并且通过允许来自所有其他来源的浏览器请求,您实际上会产生一些潜在的安全问题。
理想情况下,如果服务器和客户端都是您的应用程序,则从客户端您应该只向托管客户端应用程序的同一源发出请求。因此,在您的本地情况下,它应该向localhost:8081
发出请求,您可以通过在发出请求时省略客户端的主机基地址来做到这一点。
要让它工作,对于开发环境,最好的选择是为 Angular 设置代理(代理从 localhost:8081
到 localhost:8080
的请求),详细的设置信息是 here。
对于生产环境,您需要在同一源上托管后端服务器/客户端应用程序。您可以通过在后端服务器/客户端 Web 服务器前面放置一些代理服务器,或者直接在后端服务器上托管客户端应用程序(角度静态输出文件)来做到这一点。
另一种选择是做您尝试做的事情,但不允许来自所有来源的请求(不是.permitAll()
),而是列出特定允许的来源(如localhost:8081
)。
但它不是那么干净,而且您需要为开发环境和生产环境指定不同的来源。
【讨论】:
感谢您的建议。我尝试配置它,但遇到了问题。如果您熟悉 Angular,您也可以看看这个问题吗? ***.com/q/64681061/6834824【参考方案2】:这个错误是拒绝OPTION web方法的结果,所以你应该在configure方法中添加如下语句:
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
像这样:
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers(HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers(HttpMethod.POST, "/rpc/*").permitAll()
.anyRequest().permitAll();
【讨论】:
不幸的是,这没有帮助。 @Katrikken 抱歉,我不小心放了 .antMatchers(HttpMethod.POST, "/api/auth/login").permitAll() 而不是 .antMatchers(HttpMethod.OPTIONS, "/**")。 permitAll(),我不确定你放的是后者。 我编辑了答案以显示正确的答案,也许它会有所帮助 是的,我注意到了,但仍然没有。我尝试按照下面的建议配置代理,但由于某种原因它也不起作用。以上是关于SpringBoot WebMvcConfigurer详解的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot入门到精通-SpringBoot启动流程
SpringBoot入门到精通-SpringBoot自定义starter