環境: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.www897cc.com/showinfo-26-70401-0.htmlSpring MVC核心擴展點及使用技巧總結和使用案例
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com