网上很多代码都是千篇一律的cvs,相信我只要你认真看完我写的这篇,你就可以完全掌握这个知识点,这篇文章不适合直接cvs,一定要先理解。
最近重写个项目遇到个比较棘手的问题,老项目是PHP接口,这个接口同时兼容POSTjson和form表单,更骚的是连form-data也兼容。。。因为写PHP请求的对接方代码不严谨。详见这里。
而在Java中,一个接口只支持一种content-type,json就用@RequestBody,form表单就用@RequestParam或不写,form-data就用MultipartFile。
兼容版本
如果要把在一个接口中同时兼容三种,比较笨的办法就是获取HttpServletRequest,然后自己再写方法解析。类似如下:
private Map getParams(HttpServletRequest request) {
String contentType = request.getContentType();
if (contentType.contains('application/json')) {
// json 解析...
return null;
} else if (contentType.contains('application/x-www-form-urlencoded')) {
// form 表单解析 ...
return null;
} else if (contentType.contains('multipart')) {
// 文件流解析
return null;
} else {
throw new BizException('不支持的content-type');
}
}
复制代码
但是这样写有弊端
代码很丑,具体到解析代码又臭又长只能返回固定map或者自己重新组装参数类无法使用@Valid校验参数,像我这种几十个参数都要检验的简直是灾难
优雅版本
网上有form表单和json同时兼容的版本,但是没有兼容form-data,我在这做一下补充。
自定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GamePHP {
}
复制代码
自定义注解解析
public class GamePHPMethodProcessor implements HandlerMethodArgumentResolver {
private GameFormMethodArgumentResolver formResolver;
private GameJsonMethodArgumentResolver jsonResolver;
public GamePHPMethodProcessor() {
List> messageConverters = new ArrayList<>();
PHPMessageConverter PHPMessageConverter = new PHPMessageConverter();
messageConverters.add(PHPMessageConverter);
jsonResolver = new GameJsonMethodArgumentResolver(messageConverters);
formResolver = new GameFormMethodArgumentResolver();
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
GamePHP ann = parameter.getParameterAnnotation(GamePHP.class);
return (ann != null);
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
ServletRequest servletRequest = nativeWebRequest.getNativeRequest(ServletRequest.class);
String contentType = servletRequest.getContentType();
if (contentType == null) {
throw new IllegalArgumentException('不支持contentType');
}
if (contentType.contains('application/json')) {
return jsonResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
}
if (contentType.contains('application/x-www-form-urlencoded')) {
return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
}
if (contentType.contains('multipart')) {
return formResolver.resolveArgument(methodParameter, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
}
throw new IllegalArgumentException('不支持contentType');
}
}
复制代码
@Bean
public MyMvcConfigurer mvcConfigurer() {
return new MyMvcConfigurer();
}
public static class MyMvcConfigurer implements WebMvcConfigurer {
public void addArgumentResolvers(List resolvers) {
resolvers.add(new GamePHPMethodProcessor());
}
}
复制代码
form-data的特殊处理
引入jar包
commons-fileupload
commons-fileupload
1.3.1
commons-io
commons-io
2.4
复制代码
新增解析bean
@Bean(name = 'multipartResolver')
public MultipartResolver multipartResolver(){
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding('UTF-8');
resolver.setResolveLazily(true);//resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
resolver.setMaxInMemorySize(40960);
resolver.setMaxUploadSize(50*1024*1024);//上传文件大小 50M 50*1024*1024
return resolver;
}
复制代码
特殊说明,GameJsonMethodArgumentResolver和GameFormMethodArgumentResolver是我们自定义的json和form解析,如果你没有自定义的,使用spring默认的ServletModelAttributeMethodProcessor和RequestResponseBodyMethodProcessor也可以。
只需将@RequestParam注解改为@GamePHP,接口即可同时兼容三种content-type。
其流程为,spring启动的时候,MyMvcConfigurer调用addArgumentResolvers方法将GamePHPMethodProcessor注入,接到请求时,supportsParameter方法判断是否使用此resolver,如果为true,则进入resolveArgument方法执行。
至此我们可以得出一个结论,PHP是世界上最垃圾的语言。写代码一时爽,维护火葬场。
文章为作者独立观点,不代表股票交易接口观点