Springboot下的SpringMVC配置解析 ——WebMvcConfigurerAdapter和WebMvcConfigurationSupport

1、前言

Sprinboot中配置SpringMVC主要是繼承WebMvcConfigurerAdapter(1.x版本)或者WebMvcConfigurationSupport(2.x版本)。此次主要介紹下web應用的一些經常使用配置。前端

2、開始配置

(一)配置參數解析器

參數解析器的做用,通俗來講,參數解析器的做用是將請求中的參數映射到咱們Controller方法參數,好比說經過參數解析器,咱們能夠將前端傳過來的token參數作一下處理,從redis中取出用戶信息,直接映射爲一個userInfo對象,而後Controller方法的參數就直接是UserInfo類型的對象就能夠了。如何使用勒?下面是一個簡單範例,這裏只貼出僞代碼:web

首先咱們建立一個解析器類,而且實現HandlerMethodArgumentResolver接口。redis

public class TokenHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    private RedissonClient redissonClient;
    private UserDao userDao;
    public TokenHandlerMethodArgumentResolver(RedisClient redisClient, UserDao userDao) {
        this.redissonClient = redisClient;
        this.userDao = userDao;
    }
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return User.class.isAssignableFrom(methodParameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception{
        HttpServletRequest nativeRequest = (HttpServletRequest) nativeWebRequest.getNativeRequest();
        String token = nativeRequest.getHeader("token");
        RBucket<String> userIdBucket = redissonClient.getBucket(token);
        if(StringUtils.isNotBlank(userIdBucket.get())){
            User user = userDao.getById(userIdBucket.get());
        }
        return user;
    }
}

而後建立類MyWebConfig,繼承WebMvcConfigurerAdapter並實現ApplicationContextAware接口,爲何實現ApplicationContextAware,是爲了從IOC容器當中取出redissonClient和userDao,用於構造TokenHandlerMethodArgumentResolver。spring

public class MyWebConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
    private UserDao userDao;
    private RedissonClient redissonClient;
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
       argumentResolvers.add(new TokenHandlerMethodArgumentResolver(redissonClient,userDao));
        super.addArgumentResolvers(argumentResolvers);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        userDao = applicationContext.getBean(UserDao.class);
        redissonClient = applicationContext.getBean(RedissonClient.class);
    }
}

如上,HandlerMethodArgumentResolver最重要的兩個方法是boolean supportsParameter(MethodParameter methodParameter)Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory),前者是若是返回ture表示使用該解析器進行解析,後者就是返回處理後的方法參數。另外例子中比較關鍵的方法有經過NativeWebRequest獲取HttpServletRequest的方法 nativeWebRequest.getNativeRequest()。json

這裏的邏輯是,若是參數中有參數的類型是User類型,那麼直接經過token去獲取注入在這裏。對於咱們來講,若是須要用戶信息就只須要在Controller中加個User參數,就自動有了,不須要本身查,就能夠很方便的引用用戶的相關信息。跨域

(二)配置數據序列化

配置數據序列化有兩種方式,一個是經過添加Formatter,一個是添加Converter,二者區別不大,SpingMVC內部處理Formatter時也是包裝了一層Converter。同時這裏值得注意的是,Formatter和Converter是在SpringMVC使用默認參數解析器狀況下使用的,若是你自定義了參數解析器,那麼其接管的參數,轉換規則由自定義參數解析器裏面的邏輯來肯定。app

另外主要被應用於form表單參數或query參數字段,Json傳參不是用這個,Json傳參默認參數解析器是:RequestResponseBodyMethodProcessor,針對請求頭或響應頭爲Content-Type=application/json,調用的消息轉換器會用Jackson的ObjectMapper來序列化或反序列化,因此若是是JSON傳參,配置這個東西沒有用。cors

1.配置Formatter

以配置一個LocalDateTime類與字符串之間的轉換爲例:ide

首先新建一個類LocalDateTimeFormatter以下:post

public class LocalDateTimeFormatter implements Formatter<LocalDateTime> {
    private static final DateTimeFormatter dateTimeFormatter =  DateTimeFormatter.ofPattern("yyyy-MM-dd HH:ss:mm");
    @Override
    public LocalDateTime parse(String s, Locale locale) throws ParseException {
        return LocalDateTime.parse(s, dateTimeFormatter);
    }

    @Override
    public String print(LocalDateTime localDateTime, Locale locale) {
        return dateTimeFormatter.format(localDateTime);
    }
}

其中parse方法主要是將字符串轉換爲對象的邏輯,print方法是將對象轉換爲字符串的邏輯。

而後註冊該Formatter,在MyWebConfig重寫public void addFormatters(FormatterRegistry registry) 方法:

@Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new LocalDateTimeFormatter());
        super.addFormatters(registry);
    }

這樣,當不是json傳參的時候,默認狀況下會使用這個自定義的格式化器進行字符串和對象的轉換。

2.配置Converter

通常狀況下咱們使用Formatter替代Converter,但有時候也會對系統默認的StringHttpMessageConverter進行覆蓋,修改編碼格式爲UTF-8,處理contentType爲text/plain的消息與String對象的轉換。如在MyWebConfig重寫方法void configureMessageConverters(List<HttpMessageConverter<?>> converters):

@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
        super.extendMessageConverters(converters);
    }

##(三)配置靜態資源映射

配置靜態資源重寫的方法爲:void addResourceHandlers(ResourceHandlerRegistry registry),如重寫方法爲:

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/upload/**").addResourceLocations("classpath:/upload/");
        super.addResourceHandlers(registry);
    }

其中addResourceHandler("/upload/**").addResourceLocations("classpath:/upload/")的意思表示將URL:項目訪問url+upload/xxx映射到classpath下的upload目錄裏面名爲XXX的靜態資源,其中addResourceLocations參數爲變長參數,能夠映射多個路徑,也能夠前面加'file:',映射磁盤上任意目錄,如:file:/D://upload/,表示映射到d盤的upload目錄。

(四)配置過濾器

添加過濾器只須要註冊一個FilterRegistrationBean類對象到spring容器便可,如在測試環境註冊一個容許跨域的過濾器:

@Conditional(value = {TestCondition.class})
    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource =
                new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setOrder(10);
        filterRegistrationBean.setFilter(new CorsFilter(urlBasedCorsConfigurationSource));
        filterRegistrationBean.setName("corsFilter");
        filterRegistrationBean.addUrlPatterns("/*");
        return filterRegistrationBean;
    }

@Conditional註解標識在上面表示在測試環境即引用的aplication-test.yml|properties,這裏的value應該傳入一個org.springframework.context.annotation.Condition接口實現類的Class對象。這裏傳入的是TestCondition。代碼以下:

@Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment environment = conditionContext.getEnvironment();
        String[] activeProfiles = environment.getActiveProfiles();
        if (null != activeProfiles) {
            for (String x : activeProfiles) {
                if ("test".equals(x)) {
                    return true;
                }
            }
        }
        return false;
    }

另外對於自定義的過濾器,常規操做以下:

  • 繼承OncePerRequestFilter抽象類,實現doFilterInternal方法。
  • 將這個Filter對象注入到filterRegistrationBean,並配置其餘信息,如order,已通過濾的Url。

如:

@Bean
    public FilterRegistrationBean myFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new MyFilter());
        //order越小,優先級越高
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.setName("myFilter");
        return filterRegistrationBean;
    }

(四)配置攔截器

攔截器與過濾器的區別在於過濾器的優先級比攔截器高,Filter是做用於Servlet前,而Interceptor則相對於Filter更靠後一點。另外Filter不可使用IOC容器資源,Interceptor則能夠。過濾器能完成的功能,經過Interceptor均可以完成,一般狀況下,推薦使用Interceptor。

配置攔截器的步驟是:

1.建立類繼承HandlerInterceptorAdapter。

HandlerInterceptorAdapter有三個方法能夠重寫,未重寫前不作任何處理。三個方法是:

//在業務處理器處理請求以前被執行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
        return true;
}
//在業務處理器處理請求返回響應以前執行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
}
//返回響應以後執行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
}

2.註冊攔截器

在MyWebConfig類重寫方法void addInterceptors(InterceptorRegistry registry),如:

@Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 能夠多個攔截器組成一個攔截器鏈
        // addPathPatterns 用於添加攔截規則
        // excludePathPatterns 用於排除攔截
        registry.addInterceptor(new MyInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/swagger*/**");
        super.addInterceptors(registry);
    }

3、小結

以上就是基於Springboot下的SpringMVC經常使用配置方法,基本上能知足經常使用項目配置需求,其餘就暫時不做了解了。

相關文章
相關標籤/搜索