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的數據返回。