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的数据返回。