环境:Springboot2.3.9.RELEASE
这里的内容基于上一篇文章《Springboot自定义消息转换器 》,可先查看这篇文章了解更多的内容细节。
与上一篇一样,我们还是假设现在要实现这样的一个消息格式:
入参(Post body):
name:张三,age:20
- 消息转换器
public class CustomHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
private static Logger logger = LoggerFactory.getLogger(CustomHttpMessageConverter.class) ;
// 这里指明了只要接收参数是Users类型的都能进行转换
@Override
protected boolean supports(Class<?> clazz) {
return Users.class == clazz ;
}
// 读取内容进行内容的转换
@Override
protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
String content = inToString(inputMessage.getBody()) ;
String[] keys = content.split(",") ;
Users instance = null ;
try {
instance = (Users) clazz.newInstance();
} catch (Exception e1) {
e1.printStackTrace() ;
}
for (String key : keys) {
String[] vk = key.split(":") ;
try {
Field[] fields = clazz.getDeclaredFields() ;
for (Field f:fields) {
if (f.getName().equals(vk[0])) {
f.setAccessible(true) ;
Class<?> type = f.getType() ;
if (String.class == type) {
f.set(instance, vk[1]) ;
} else if (Integer.class == type) {
f.set(instance, Integer.parseInt(vk[1])) ;
}
break ;
}
}
} catch (Exception e) {
logger.error("错误:{}", e) ;
}
}
return instance ;
}
// 如果将返回值以什么形式输出,这里就是调用了对象的toString方法。
@Override
protected void writeInternal(Object t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
outputMessage.getBody().write(t.toString().getBytes()) ;
}
@Override
protected boolean canWrite(MediaType mediaType) {
if (mediaType == null || MediaType.ALL.equalsTypeAndSubtype(mediaType)) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes()) {
if (supportedMediaType.isCompatibleWith(mediaType)) {
return true;
}
}
return false;
}
private String inToString(InputStream is) {
byte[] buf = new byte[10 * 1024] ;
int leng = -1 ;
StringBuilder sb = new StringBuilder() ;
try {
while ((leng = is.read(buf)) != -1) {
sb.append(new String(buf, 0, leng)) ;
}
return sb.toString() ;
} catch (IOException e) {
throw new RuntimeException(e) ;
}
}
}
该消息转换器只支持Users对象(更多一些原理细节,查看上一篇文章《Springboot自定义消息转换器 》)。
- 参数解析器
这个接口参数谁能处理,如何处理的问题。
public class CustomHandlerMethodParameterResolver implements HandlerMethodArgumentResolver {
private CustomHttpMessageConverter messageConverter ;
public CustomHttpMessageConverter getMessageConverter() {
return messageConverter;
}
public void setMessageConverter(CustomHttpMessageConverter messageConverter) {
this.messageConverter = messageConverter;
}
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(Pack.class) ;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
return messageConverter.read((Class<?>)parameter.getNestedGenericParameterType(), inputMessage) ;
}
}
说明:
supportsParameter:方法确定了当前解析器能够处理什么样的参数,这里我自定义了一个Pack注解类,也就是在接口参数上添加@Pack注解。
resolveArgument:方法是对参数的解析的具体实现。这里就是调用我们的消息转换器来实现的。
注意:这里messageConverter.read 这是父类中的方法,如下:
@Override
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return readInternal(clazz, inputMessage);
}
还是调用子类的readInternal方法。
这里的消息转换器我是直接用的,如果你源码调试过你会知道,有些消息转换器内部是有个HttpMessageConverter List的,依次判断当前转换器是否支持。这里为了简单直接使用了。
自定义注解类:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Pack {
}
- 配置消息转换器及参数解析器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public CustomHttpMessageConverter customHttpMessageConverter() {
return new CustomHttpMessageConverter() ;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
CustomHttpMessageConverter messageConvert = customHttpMessageConverter() ;
List<MediaType> supportedMediaTypes = new ArrayList<>() ;
supportedMediaTypes.add(new MediaType("application", "fm")) ;
messageConvert.setSupportedMediaTypes(supportedMediaTypes) ;
converters.add(messageConvert) ;
WebMvcConfigurer.super.configureMessageConverters(converters);
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
CustomHandlerMethodParameterResolver customResolver = new CustomHandlerMethodParameterResolver() ;
customResolver.setMessageConverter(customHttpMessageConverter()) ;
resolvers.add(customResolver) ;
WebMvcConfigurer.super.addArgumentResolvers(resolvers);
}
}
- Controller接口
@PostMapping("/resolver")
public Object resolver(@Pack Users user) {
System.out.println("自定义参数解析器处理结果:" + user) ;
return user ;
}
- 测试
看下系统都有哪些参数解析器
在
RequestMappingHandlerAdapter.java类中
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
完毕!!!
给个关注+转发呗谢谢啊
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80066.html