WebMvcConfigurer
WebMvcConfigurer 作为配置类是,采用 JavaBean 的形式来代替传统的 xml 配置文件形式进行针对框架个性化定制,就是 Spring MVC XML 配置文件的 JavaConfig(编码)实现方式。自定义 InterceptorViewResolver,
MessageConverter。WebMvcConfigurer 就是 JavaConfig 形式的 Spring MVC 的配置文件WebMvcConfigurer 是一个接口,需要自定义某个对象,实现接口并覆盖某个方法。主要方法功能介绍一下:
publicinterfaceWebMvcConfigurer{//帮助配置 HandlerMappingdefaultvoidconfigurePathMatch(PathMatchConfigurer configurer){}//处理内容协商defaultvoidconfigureContentNegotiation(ContentNegotiationConfigurer configurer){}//异步请求defaultvoidconfigureAsyncSupport(AsyncSupportConfigurer configurer){}//配置默认 servletdefaultvoidconfigureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){}//配置内容转换器defaultvoidaddFormatters(FormatterRegistry registry){}//配置拦截器defaultvoidaddInterceptors(InterceptorRegistry registry){}//处理静态资源defaultvoidaddResourceHandlers(ResourceHandlerRegistry registry){}//配置全局跨域defaultvoidaddCorsMappings(CorsRegistry registry){}//配置视图页面跳转defaultvoidaddViewControllers(ViewControllerRegistry registry){}//配置视图解析器defaultvoidconfigureViewResolvers(ViewResolverRegistry registry){}//自定义参数解析器,处理请求参数defaultvoidaddArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers){}//自定义控制器方法返回值处理器defaultvoidaddReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers){}//配置 HttpMessageConvertersdefaultvoidconfigureMessageConverters(List<HttpMessageConverter<?>> converters){}//配置 HttpMessageConvertersdefaultvoidextendMessageConverters(List<HttpMessageConverter<?>> converters){}//配置异常处理器defaultvoidconfigureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers){}//扩展异常处理器defaultvoidextendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers){}//JSR303 的自定义验证器defaultValidatorgetValidator(){returnnull;}//消息处理对象defaultMessageCodesResolvergetMessageCodesResolver(){returnnull;}}
一、页面跳转控制器
Spring Boot 中使用页面视图,比如 Thymeleaf。要跳转显示某个面,必须通过 Controller 对象。也就是我们需要创建一个 Controller,转发到一个视图才行。 如果我们现在需要显示页面,可以无需这个 Controller。
addViewControllers() 完成从请求到视图跳转。
- 需求:访问/welcome 跳转到项目首页 index.html(Thyemeleaf 创建的对象)
项目代码结构:
step1:创建视图,resources/templates/index.html
<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title></head><body><h3>欢迎各位小伙伴!!!</h3></body></html>
step2:创建SpringMVC配置类
- 重写addViewControllers()方法
- 配置页面控制:addViewController(“请求的uri”).指定他的视图setViewName(目标视图)
packagecom.bjpowernode.mvc.settings;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.ViewControllerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/**
* springmvc配置类
*/@ConfigurationpublicclassMvcSettingsimplementsWebMvcConfigurer{//页面跳转控制器,从请求直达视图@OverridepublicvoidaddViewControllers(ViewControllerRegistry registry){//配置页面控制:addViewController("请求的uri").指定他的视图setViewName(目标视图)
registry.addViewController("/welcome").setViewName("index");}}
step3:测试功能
浏览器访问http://localhost:8080/welcome
二、数据格式化
Formatter<T>是数据转换接口,将一种数据类型转换为另一种数据类型。与 Formatter<T>功能类型的还有Converter<S,T>。本节研究 Formatter<T>接口。Formatter<T>只能将 String 类型转为其他数据数据类型。这点在Web 应用适用更广。因为 Web 请求的所有参数都是 String,我们需要把 String 转为 Integer ,Long,Date 等等。
Spring 中内置了一下 Formatter:
- DateFormatter : String 和 Date 之间的解析与格式化
- InetAddressFormatter :String 和 InetAddress 之间的解析与格式化
- PercentStyleFormatter :String 和 Number 之间的解析与格式化,带货币符合
- NumberFormat :String 和 Number 之间的解析与格式化
- 我在使用@ DateTimeFormat , @NumberFormat 注解时,就是通过 Formatter解析 String 类型到我们期望的Date 或 Number 类型
- Formatter也是 Spring 的扩展点,我们处理特殊格式的请求数据时,能够自定义合适的 Formatter,将请求的 String 数据转为我们的某个对象,使用这个对象更方便我们的后续编码
接口原型
Formatter是一个组合接口,没有自己的方法。内容来自 Printer和 Parser
- Printer:将 T 类型转为 String,格式化输出
- Parser:将 String 类型转为期望的 T 对象。
- 我们项目开发,可能面对多种类型的项目,复杂程度有简单,有难一些。特别是与硬件打交道的项目,数据的格式与一般的 name: lisi, age:20 不同。数据可能是一串“1111; 2222; 333,NF; 4; 561” 。
- 需求:将“1111;2222;333,NF;4;561”接受,代码中用 DeviceInfo 存储参数值
step1:创建 DeviceInfo 数据类
importlombok.Data;@DatapublicclassDeviceInfo{privateString item1;privateString item2;privateString item3;privateString item4;privateString item5;}
step2:自定义 Formatter
packagecom.bjpowernode.mvc.fomatter;importcom.bjpowernode.mvc.model.DeviceInfo;importorg.springframework.format.Formatter;importorg.springframework.util.StringUtils;importjava.text.ParseException;importjava.util.Locale;importjava.util.StringJoiner;/**
* 将请求参数字符串转为 DeviceInfo
*/publicclassDeviceFormatterimplementsFormatter<DeviceInfo>{@OverridepublicDeviceInfoparse(String text,Locale locale)throwsParseException{DeviceInfo info =null;if(StringUtils.hasLength(text)){String[] items = text.split(";");
info =newDeviceInfo();
info.setItem1(items[0]);
info.setItem2(items[1]);
info.setItem3(items[2]);
info.setItem4(items[3]);
info.setItem5(items[4]);}return info;}@OverridepublicStringprint(DeviceInfo object,Locale locale){StringJoiner joiner =newStringJoiner("#");
joiner.add(object.getItem1()).add(object.getItem2()).add(object.getItem3()).add(object.getItem4()).add(object.getItem5());return joiner.toString();}}
step3: 登记自定义的 DeviceFormatter
- addFormatters() 方法登记 Formatter
packagecom.bjpowernode.mvc.settings;importcom.bjpowernode.mvc.fomatter.DeviceFormatter;importorg.springframework.context.annotation.Configuration;importorg.springframework.format.FormatterRegistry;importorg.springframework.web.servlet.config.annotation.ViewControllerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/**
* springmvc配置类
*/@ConfigurationpublicclassMvcSettingsimplementsWebMvcConfigurer{//页面跳转控制器,从请求直达视图@OverridepublicvoidaddViewControllers(ViewControllerRegistry registry){//配置页面控制:addViewController("请求的uri").指定他的视图setViewName(目标视图)
registry.addViewController("/welcome").setViewName("index");}@OverridepublicvoidaddFormatters(FormatterRegistry registry){
registry.addFormatter(newDeviceFormatter());}}
step4: 新建 Controller 接受请求设备数据
importcom.bjpowernode.mvc.model.DeviceInfo;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassDeviceController{@PostMapping("/device/add")publicStringaddDeviceInfo(@RequestParam("device")DeviceInfo info){return"接受设备信息"+info.toString();}}
step5:单元测试
POST http://localhost:8080/device/add
Content-Type: application/x-www-form-urlencoded
device=1111;2222;333,NF;4;561
三、拦截器
HandlerInterceptor 接口和它的实现类称为拦截器,是 SpringMVC 的一种对象。拦截器是 Spring MVC 框架的对象与 Servlet 无关。拦截器能够预先处理发给 Controller 的请求。可以决定请求是否被 Controller 处理。用户请求是先由 DispatcherServlet 接收后,在 Controller 之前执行的拦截器对象。
一个项目中有众多的拦截器:框架中预定义的拦截器, 自定义拦截器。下面我说说自定义拦截器的应用。根据拦截器的特点,类似权限验证,记录日志,过滤字符,登录 token 处理都可以使用拦截器。
拦截器定义步骤:
- 声明类实现 HandlerInterceptor 接口,重写三个方法(需要那个重写那个)
- 登记拦截器
(一)、一个拦截器
需求:zhangsan 操作员用户,只能查看文章,不能修改,删除。
step1:创建文章的 Controller
importorg.springframework.web.bind.annotation.DeleteMapping;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PostMapping;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassArticleController{@PostMapping("/article/add")publicStringaddArticle(){return"发布新的文章";}@PostMapping("/article/edit")publicStringeditArticle(){return"修改文章";}@DeleteMapping("/article/remove")publicStringremoveArticle(){return"删除文章";}@GetMapping("/article/query")publicStringquery(){return"查询文章";}}
step2:创建有关权限拦截器
importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importorg.springframework.web.servlet.HandlerInterceptor;publicclassAuthInterceptorimplementsHandlerInterceptor{privatestaticfinalStringCOMMON_USER="zhangsan";@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{System.out.println("====AuthInterceptor权限拦截器====");String loginUser = request.getParameter("loginUser");String requestURI = request.getRequestURI();if(COMMON_USER.equals(loginUser)&&(
requestURI.startsWith("/article/add")||
requestURI.startsWith("/article/edit")||
requestURI.startsWith("/article/remove"))){returnfalse;}returntrue;}}
step3:登记拦截器
packagecom.bjpowernode.mvc.settings;importcom.bjpowernode.mvc.fomatter.DeviceFormatter;importcom.bjpowernode.mvc.interceptor.AuthInterceptor;importcom.bjpowernode.mvc.interceptor.LoginInterceptor;importorg.springframework.context.annotation.Configuration;importorg.springframework.format.FormatterRegistry;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.ViewControllerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/**
* springmvc配置类
*/@ConfigurationpublicclassMvcSettingsimplementsWebMvcConfigurer{//页面跳转控制器,从请求直达视图@OverridepublicvoidaddViewControllers(ViewControllerRegistry registry){//配置页面控制:addViewController("请求的uri").指定他的视图setViewName(目标视图)
registry.addViewController("/welcome").setViewName("index");}@OverridepublicvoidaddFormatters(FormatterRegistry registry){
registry.addFormatter(newDeviceFormatter());}@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){//权限拦截器AuthInterceptor authInterceptor =newAuthInterceptor();
registry.addInterceptor(authInterceptor).order(2).addPathPatterns("/article/**").excludePathPatterns("/article/query");LoginInterceptor loginInterceptor =newLoginInterceptor();}}
step4:测试拦截器
POST http://localhost:8080/article/add
Content-Type: application/x-www-form-urlencoded
loginUser=lisi&title=Vue3
(二)、多个拦截器
增加一个验证登录用户的拦截器,只有 zhangsan,lisi,admin 能够登录系统。其他用户不可以。
两个拦截器登录的拦截器先执行,权限拦截器后执行,order()方法设置顺序,整数值越小,先执行。 step1:创建登录拦截器
step1:创建登录拦截器
importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importorg.springframework.util.StringUtils;importorg.springframework.web.servlet.HandlerInterceptor;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.List;publicclassLoginInterceptorimplementsHandlerInterceptor{privateList<String> permitUser =newArrayList<>();publicLoginInterceptor(){this.permitUser =Arrays.asList("zhangsan","lisi","admin");}@OverridepublicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{System.out.println("=========LoginInterceptor执行了==========");//获取登录用户名String loginUser = request.getParameter("loginUser");if(StringUtils.hasText(loginUser)&& permitUser.contains(loginUser)){returntrue;}returnfalse;}}
step2:登记拦截器,设置顺序 order
@OverridepublicvoidaddInterceptors(InterceptorRegistry registry){//权限拦截器AuthInterceptor authInterceptor =newAuthInterceptor();
registry.addInterceptor(authInterceptor).order(2).addPathPatterns("/article/**").excludePathPatterns("/article/query");LoginInterceptor loginInterceptor =newLoginInterceptor();
registry.addInterceptor(loginInterceptor).order(1).addPathPatterns("/**")// 拦截所有请求.excludePathPatterns("/article/query")//排除/article/query 请求;}
step3:测试拦截器
POST http://localhost:8080/article/add
Content-Type: application/x-www-form-urlencoded
loginUser=lisi&title=Vue3
版权归原作者 MAGICIAN... 所有, 如有侵权,请联系我们删除。