环境:SpringBoot2.7.12
@Configuration@EnableWebMvcpublic class WebConfig {}
如需要自定义数据类型的转换,可以通过如下方式注册
@Configurationpublic class WebConfig implements WebMvcConfigurer { @Override public void addFormatters(FormatterRegistry registry) { registry.addConverterFactory(new ConverterFactory<String, Number>() { @Override public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) { return new Converter<String, T>() { public T convert(String source) { return (T) Integer.valueOf(source) ; } } ; } }); } }
以上添加了从String到Integer的转换(这里只是举例,系统默认已经有了从String到Number的转换器)。每种转换器最终被包装成ConvertersForPair对象,该对象中有个队列保存了所有的转换器。后添加的添加到首位,如下:
private static class ConvertersForPair { private final Deque<GenericConverter> converters = new ConcurrentLinkedDeque<>(); public void add(GenericConverter converter) { this.converters.addFirst(converter); }}
所有如你有自定义的转换器,自定义的优先级比系统自带的要高。
默认情况下,如果类路径上存在 Bean Validation(例如 Hibernate Validator),则 LocalValidatorFactoryBean 会被注册为全局 Validator,与控制器方法参数上的 @Valid 和 Validated 一起使用。
@Configurationpublic class WebConfig implements WebMvcConfigurer { public Validator getValidator() { return new LocalValidatorFactoryBean(); }}
4. 请求拦截器
@Configurationpublic class WebConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new HandlerInterceptor() { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (request.getHeader("token") == null) { return false ; } return true ; } }).addPathPatterns("/**") ; }}
上面配置了一个拦截任意请求的拦截器,在请求到达时会先验证请求header中token是否为null。
拦截器并不适合作为安全层,因为它有可能与控制器Controller路径匹配不匹配,而Controller路径匹配还可以透明地匹配尾部斜线和路径扩展名以及其他路径匹配选项。其中许多选项已被弃用,但仍有可能出现不匹配。一般情况下,我们建议使用 Spring Security,它包含一个专用的 MvcRequestMatcher,可与 Spring MVC 路径匹配保持一致,还具有安全防火墙,可阻止 URL 路径中许多不需要的字符。
自定义Spring MVC 如何从请求中确定所请求的媒体类型(例如,接受头、URL 路径扩展、查询参数等)。
默认情况下,只选中"Accept" header。
@Configurationpublic class WebConfig implements WebMvcConfigurer { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { // 这样配置后,视图技术就能够根据你请求的Accept输出指定的文件内容了 configurer.mediaType("yaml", new MediaType("application", "yaml")) ; }}
上面的配置最终是对ContentNegotiationManager对象进行添加MappingMediaTypeFileExtensionResolver文件扩展解析器。
@Beanpublic ContentNegotiationManager mvcContentNegotiationManager() { if (this.contentNegotiationManager == null) { ContentNegotiationConfigurer configurer = new ContentNegotiationConfigurer(this.servletContext); configurer.mediaTypes(getDefaultMediaTypes()); configureContentNegotiation(configurer); this.contentNegotiationManager = configurer.buildContentNegotiationManager(); } return this.contentNegotiationManager;}protected ContentNegotiationManager buildContentNegotiationManager() { this.factory.addMediaTypes(this.mediaTypes); return this.factory.build();}
部分代码
public class ContentNegotiationManagerFactoryBean { public ContentNegotiationManager build() { if (!CollectionUtils.isEmpty(this.mediaTypes) && !this.favorPathExtension && !this.favorParameter) { this.contentNegotiationManager.addFileExtensionResolvers( new MappingMediaTypeFileExtensionResolver(this.mediaTypes)); } }}
有了MappingMediaTypeFileExtensionResolver解析器后,还需要Controller接口返回ModelAndView对象。如下接口
@GetMapping("/contentType")public ModelAndView contentType() { return new ModelAndView("test") ;}
在classpath下新建test.yaml文件,内容随意。有了这些还不够,我们需要能够解析处理*.yaml的文件。所以还需要视图解析器
@Componentpublic class YamlViewResolver implements ViewResolver { @Override public View resolveViewName(String viewName, Locale locale) throws Exception { if (!viewName.endsWith(".yaml")) { return null ; } return new View() { // 支持的类型 public String getContentType() { return "application/yaml" ; }; @Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { ClassPathResource resource = new ClassPathResource(viewName) ; InputStream is = resource.getInputStream() ; OutputStream outputStream = response.getOutputStream(); byte[] buffer = new byte[4096]; int bytesRead = -1; while ((bytesRead = is.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush() ; is.close(); outputStream.close() ; } } ; }}
有了这些我们配置Spring MVC才能正确的输出我们所需要的文件内容。这个功能是不是太麻烦了,没撒用
本文链接:http://www.28at.com/showinfo-26-70401-0.htmlSpring MVC核心扩展点及使用技巧总结和使用案例
声明:本网页内容旨在传播知识,不代表本站观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。