springmvc 自定义参数处理器

上一篇介绍了springmvc参数绑定的原理
现在让我们尝试自己定义一个参数转换器

先定义一个比较简单的处理器,在写接口的时候,经常需要对分页参数进行处理,比如下面这样

String offset =request.getParameter("offset");
String size = request.getParameter("pageSize");
//拼装成bean或者直接使用

这样会导致很多重复代码,参数处理器可以很好的解决这个问题
首先先定义一个分页参数的bean

public class Pageable implements Serializable {

    private Integer offset; // 起始行号
    private Integer size; // 每页大小

    public Pageable() {
    }

    public Pageable(Integer offset, Integer size) {
        this.offset = offset;
        this.size = size;
    }
//省略get,set
}

定义参数转换器

public class PageableMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private final String DEFAULT_OFFSET = "0";
    private final String DEFAULT_SIZE = "10";

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return Pageable.class.isAssignableFrom(methodParameter.getParameterType());
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
        HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest();
        String offset = request.getParameter("offset");
        String size = request.getParameter("pageSize");
        if (offset.isEmpty()||size.isEmpty()) {
            offset = DEFAULT_OFFSET;
            size = DEFAULT_SIZE;
        }
        return new Pageable(Integer.valueOf(offset), Integer.valueOf(size));
    }
}

最后在配置文件注册该处理器(这是spring4.0以下的注册方式,4.0以上注册方式参考下面的)


        
            
                
            
        
        
    

下面是定义一个比较复杂的转换器


需求:将json格式的请求在参数中获取值,类似于

springmvc 自定义参数处理器_第1张图片
json格式的请求在参数中获取值.png

用到的jar包除了spring的还有jsonpath原来解析json


 com.jayway.jsonpath
 json-path
 2.2.0
 

因为是json格式的报文,所有我们只需要模仿@RequestBody注解的处理,查看源码可知@RequestBody注解对应的处理器为RequestResponseBodyMethodProcessor,
对json处理核心方法将json转换为bean
readWithMessageConverters方法,
该方法是由其父类AbstractMessageConverterMethodArgumentResolver实现,对应uml图

springmvc 自定义参数处理器_第2张图片
uml.png

所以我们只允许继承AbstractMessageConverterMethodArgumentResolver并重写supportsParameter,readWithMessageConverters方法即可实现我们需要的功能

分析结束,现在开始写具体的实现,首先我们需要一个注解用来标注参数,对注解不了解的可以看java注解笔记

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@Documented
public @interface JsonRequest {
    String value() default "";
    boolean required() default true;
}

然后写对应的参数转换器,这边只写核心的方法,具体的查看github,地址在文章末尾

protected  Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter param, Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
        try {
            inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
            InputStream inputStream = inputMessage.getBody();
            String json;
            if (inputStream == null) {
                json = threadLocal.get();
            } else {
                json = StreamUtils.copyToString(inputStream, Charset.defaultCharset());
                threadLocal.set(json);
            }
            JsonRequest jsonRequest = param.getParameterAnnotation(JsonRequest.class);
            return JsonPath.read(json, jsonRequest.value());
        } catch (PathNotFoundException ex) {
            return null;
        }
    }

在配置文件添加配置


        
            
                
                    
  
  
                    
                
            
        
        
            
                
                    
                        application/json;charset=UTF-8
                    
                
            
        
    

添加一个controller

 @RequestMapping("/getUserByJson2")
 @ResponseBody
 public String getUserByJson2(@JsonRequest("$.id") String id, @JsonRequest("$.name") String name) {
        return id + "," + name;
    }

测试发送参数

{
    "id":"1",
    "name":"qqq"
}

返回
"1,qqq"
验证成功
这时将参数id类型改成Long类型发现报错

Request processing failed; nested exception is java.lang.IllegalStateException: argument type mismatch

参数类型不匹配,因为resolveArgument返回的类型和请求的参数类型是相同的,发送的是string类型用Long类型承接自然就报错了,查看AbstractNamedValueMethodArgumentResolver的源码,里面有个binder.convertIfNecessary方法,就是原来处理类型转换的,这个类型转换下一篇再写

源码地址:
https://github.com/lialzmChina/javaeeLearn.git
spring002

你可能感兴趣的:(springmvc 自定义参数处理器)