Springboot自定义参数解析器

环境:Springboot2.3.9.RELEASE


这里的内容基于上一篇文章《Springboot自定义消息转换器 》,可先查看这篇文章了解更多的内容细节。

与上一篇一样,我们还是假设现在要实现这样的一个消息格式:

入参(Post body):

name:张三,age:20

Springboot自定义参数解析器

 

  1. 消息转换器
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自定义消息转换器 》)。

  1. 参数解析器

这个接口参数谁能处理,如何处理的问题。

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 {
}
  1. 配置消息转换器及参数解析器
@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);
	}
	
	
}
  1. Controller接口
@PostMapping("/resolver")
	public Object resolver(@Pack Users user) {
		System.out.println("自定义参数解析器处理结果:" + user) ;
		return user ;
	}
  1. 测试

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

看下系统都有哪些参数解析器


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;
	}

完毕!!!


给个关注+转发呗谢谢啊

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

Springboot自定义参数解析器

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值