springMVC 扩展点

SpringMVC扩展

流程图

一般需要扩展的地方包括:

  • HandlerMethodArgumentResolver
    可以定制自己的参数接收方式 和@PathVariable同级
  • HandlerMethodReturnValueHandler
    定制返回方式,和@ResponseBody同级
  • MessageConverter
    如果采用@ResponseBody,可以根据不同的Class和MediaType定制不同的Converter

核心代码

自定义HandlerMethodArgumentResolver


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lexiaoyao.springmvc_config.pojo.Result;
import com.lexiaoyao.springmvc_config.pojo.annotations.ResultBody;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

/**
 * 自定义HandlerMethodArgumentResolver
 * 用于处理被@ResultBody标记的变量
 */
public class ResultBodyArgumentHandler implements HandlerMethodArgumentResolver {

    /**
     * 处理@ResultBody注解
     *
     * @param methodParameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(ResultBody.class);
    }

    /**
     * 这个方法的返回值作为反射处理的参数
     *
     * @param methodParameter
     * @param modelAndViewContainer
     * @param nativeWebRequest
     * @param webDataBinderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        //获取HttpServletRequest类
        HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest();
        int length = request.getContentLength();
        if (length == 0) return null;

        //从inputStream中获取字节流
        ServletInputStream inputStream = request.getInputStream();
        byte[] bytes = new byte[length];
        //通过工具类读取
        IOUtils.readFully(inputStream, bytes);

        //将byte[]转为javabean
        Result o = JSON.parseObject(bytes, Result.class);
        JSONObject jsonObject = (JSONObject) o.getData();
        //将jsonObject转换为实际的javaBean
        //methodParameter.getParameterType() 获取参数class
        return jsonObject.toJavaObject(methodParameter.getParameterType());
    }
}
      @Configuration
      public class SpringMVCConfig implements WebMvcConfigurer
    /**
     * 注册新的参数处理器
     *
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new ResultBodyArgumentHandler());
    }

定义Converter

注入FastJsonHttpMessageConverter


import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.lexiaoyao.springmvc_config.handler.ResultBodyArgumentHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.nio.charset.Charset;
import java.util.List;

@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {

    //跨域设置
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        //针对的映射
        registry.addMapping("/**")
                //针对的origin域名
                .allowedOrigins("*")
                //针对的方法
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
                //是否允许发送Cookie
                .allowCredentials(true)
                //从预检请求得到相应的最大时间,默认30分钟
                .maxAge(3600)
                //针对的请求头
                .allowedHeaders("*");
    }

    /**
     * 注册新的参数处理器
     *
     * @param resolvers
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new ResultBodyArgumentHandler());
    }

//    /**
//     * 如果是json的MediaType,不能使用这种方式,应该使用直接注入的方式
//     *
//     * @param converters
//     */
//    @Override
//    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//        converters.add(getFastJsonHttpMessageConverter());
//    }

    /**
     * 采用fastJson来处理json转换
     *
     * @return
     */
    @Bean
    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        return getFastJsonHttpMessageConverter();
    }

    /**
     * 定制化FastJsonHttpMessageConverter
     *
     * @return
     */
    private FastJsonHttpMessageConverter getFastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        fastJsonHttpMessageConverter.setFastJsonConfig(getFastJsonConfig());
        fastJsonHttpMessageConverter.setDefaultCharset(Charset.forName("UTF-8"));
        return fastJsonHttpMessageConverter;
    }

    private FastJsonConfig getFastJsonConfig() {
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteNullStringAsEmpty);
        return fastJsonConfig;
    }
}

note

建议采用直接将converter注入的方式来新增converter。
因为在springMVC中,实际上维护着一个converter的list,默认是按照从上往下,如果有满足条件的converter就采用这个当前的converter来处理当前值。
我们自己定义的converter,如果是FastJsonHttpMessageConverter,通过实现WebMvcConfig接口,实现extendMessageConverters的方式扩展,那么MappingJackson2HttpMessageConverter在这个队列的靠前的位置,所有会优先于FastJsonHttpMessageConverter处理json的数据返回。

git

https://github.com/lexiaoyao1995/springmvcdemo

posted @ 2020-10-20 21:29  刃牙  阅读(865)  评论(0编辑  收藏  举报