springmvc 自定義參數(shù)處理器

上一篇介紹了springmvc參數(shù)綁定的原理
現(xiàn)在讓我們嘗試自己定義一個(gè)參數(shù)轉(zhuǎn)換器

先定義一個(gè)比較簡(jiǎn)單的處理器,在寫(xiě)接口的時(shí)候,經(jīng)常需要對(duì)分頁(yè)參數(shù)進(jìn)行處理,比如下面這樣

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

這樣會(huì)導(dǎo)致很多重復(fù)代碼,參數(shù)處理器可以很好的解決這個(gè)問(wèn)題
首先先定義一個(gè)分頁(yè)參數(shù)的bean

public class Pageable implements Serializable {

    private Integer offset; // 起始行號(hào)
    private Integer size; // 每頁(yè)大小

    public Pageable() {
    }

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

定義參數(shù)轉(zhuǎn)換器

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

最后在配置文件注冊(cè)該處理器(這是spring4.0以下的注冊(cè)方式,4.0以上注冊(cè)方式參考下面的)

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="customArgumentResolvers">
            <list>
                <bean class="com.catfish.PageableMethodArgumentResolver"/>
            </list>
        </property>
        <property name="order" value="-1"/>
    </bean>

下面是定義一個(gè)比較復(fù)雜的轉(zhuǎn)換器


需求:將json格式的請(qǐng)求在參數(shù)中獲取值,類(lèi)似于

json格式的請(qǐng)求在參數(shù)中獲取值.png

用到的jar包除了spring的還有jsonpath原來(lái)解析json

<dependency>
 <groupId>com.jayway.jsonpath</groupId>
 <artifactId>json-path</artifactId>
 <version>2.2.0</version>
 </dependency>

因?yàn)槭莏son格式的報(bào)文,所有我們只需要模仿@RequestBody注解的處理,查看源碼可知@RequestBody注解對(duì)應(yīng)的處理器為RequestResponseBodyMethodProcessor,
對(duì)json處理核心方法將json轉(zhuǎn)換為bean
readWithMessageConverters方法,
該方法是由其父類(lèi)AbstractMessageConverterMethodArgumentResolver實(shí)現(xiàn),對(duì)應(yīng)uml圖

uml.png

所以我們只允許繼承AbstractMessageConverterMethodArgumentResolver并重寫(xiě)supportsParameter,readWithMessageConverters方法即可實(shí)現(xiàn)我們需要的功能

分析結(jié)束,現(xiàn)在開(kāi)始寫(xiě)具體的實(shí)現(xiàn),首先我們需要一個(gè)注解用來(lái)標(biāo)注參數(shù),對(duì)注解不了解的可以看java注解筆記

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

然后寫(xiě)對(duì)應(yīng)的參數(shù)轉(zhuǎn)換器,這邊只寫(xiě)核心的方法,具體的查看github,地址在文章末尾

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

在配置文件添加配置

<mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="com.lialzm.spring.support.JsonRequestMethodArgumentResolver">
                <constructor-arg>
                    <list>
  <!--只是用來(lái)防止報(bào)錯(cuò),目前并沒(méi)有使用到消息轉(zhuǎn)換器-->
  <ref bean="byteArrayHttpMessageConverter"/>
                    </list>
                </constructor-arg>
            </bean>
        </mvc:argument-resolvers>
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json;charset=UTF-8</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

添加一個(gè)controller

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

測(cè)試發(fā)送參數(shù)

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

返回
"1,qqq"
驗(yàn)證成功
這時(shí)將參數(shù)id類(lèi)型改成Long類(lèi)型發(fā)現(xiàn)報(bào)錯(cuò)

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

參數(shù)類(lèi)型不匹配,因?yàn)閞esolveArgument返回的類(lèi)型和請(qǐng)求的參數(shù)類(lèi)型是相同的,發(fā)送的是string類(lèi)型用Long類(lèi)型承接自然就報(bào)錯(cuò)了,查看AbstractNamedValueMethodArgumentResolver的源碼,里面有個(gè)binder.convertIfNecessary方法,就是原來(lái)處理類(lèi)型轉(zhuǎn)換的,這個(gè)類(lèi)型轉(zhuǎn)換下一篇再寫(xiě)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評(píng)論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,273評(píng)論 6 342
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,057評(píng)論 25 709
  • 最近一直在反思,可能好多年了,最終的結(jié)論是,很多事情我們可以讓彼此更舒服。 這個(gè)的唯一渠道是,善解人意,換位思考。...
    笑莉說(shuō)閱讀 332評(píng)論 5 8
  • 一家民辦學(xué)校已經(jīng)運(yùn)作了10多年,基礎(chǔ)不錯(cuò),最近幫她運(yùn)作項(xiàng)目,爭(zhēng)取政策和資金支持,計(jì)劃將來(lái)上市,深入了解情況后,感覺(jué)...
    甲坤閱讀 562評(píng)論 0 0

友情鏈接更多精彩內(nèi)容