小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 印度阿三17 2019-04-11

來源: https://www.cnblogs.com/daxin/p/3296493.html

自定義Spring MVC3的參數(shù)映射和返回值映射 fastjson首先說一下場景:在一些富客戶端Web應(yīng)用程序中我們會有比較多的Ajax調(diào)用,并且希望與服務(wù)器交互的數(shù)據(jù)需要是復(fù)雜的JSON對象。 fastjon是一個非常高效的JSON序列化和反序列化庫,我希望我們輸入的JSON串能通過fastjson直接反序列化為一個復(fù)雜的JavaBean對象,同時我的返回值能夠能通過fastjson序列化為JSON串。所謂復(fù)雜的JavaBean就是,不僅僅只有一層屬性,而是屬性也是JavaBean的情況, 例如:

public class FooBean {
    private String name;

    private Long id;

    private Date birthday;

    private List<Address> addresses;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public List<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(List<Address> addresses) {
        this.addresses = addresses;
    }

    @Override
    public String toString() {
        return "FooBean{"  
                "name='"   name   '''  
                ", id="   id  
                ", birthday="   birthday  
                ", addresses="   addresses  
                '}';
    }
}
public class Address {
    private String street;
    private int number;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Address{"  
                "street='"   street   '''  
                ", number="   number  
                '}';
    }
}

?

當然,結(jié)構(gòu)還可以再復(fù)雜,Adress對象里還可以又復(fù)雜JavaBean的屬性。

在SpringMVC3中我們可以把輸入簡單的映射為某個Action方法的參數(shù), 例如:

?

@RequestMapping(value="/someAction", method=RequestMethod.POST)
public String processSubmit(FooBean fooBean, Model model) {
// 利用fooBean
    return “views/some_page”;
}

?

用Spring MVC3, 我們可以把Form里的字段輕松的映射到JavaBean的屬性。 Spring MVC3 提供了豐富的參數(shù)映射機制,?詳細信息可以參見這里

同時對于Spring MVC3默認的提供的映射機制不能涵蓋的對象,我們可以通過擴展HandlerMethodArgumentResolver和HttpMessageConverter的機制來實現(xiàn)。

HandlerMethodArgumentResolver對應(yīng)輸入, HttpMessageConverter對應(yīng)輸出

假設(shè)對于上面的FooBean, 我們有這樣一個JSON對象和它對應(yīng):

?

var data = {
    name : "matianyi",
    id : 12345,
    birthday : "1983-07-01 01:12:12",
    addresses : [
        {
            street : "street1",
            number : 1
        },
        {
            street : "street2",
            number : 2
        }
    ]
};

?

Spring MVC3 本身也提供直接把JSON對象映射到JavaBean的功能,例如MappingJackson2HttpMessageConverter和MappingJackson2JsonView。

在這里我們希望通過fastjson來實現(xiàn)序列化和反序列化。所以我們要自定義一個HandlerMethodArgumentResolver用來指定HttpServletRequest的Body映射到一個JavaBean。并且返回的JavaBean通過fastjson序列化。

方法的定義是這樣的:

@RequestMapping(value = "/fastjson", method = RequestMethod.POST)
public @ResponseBody FooBean fastjson2(@FastJson FooBean foo) {
    System.out.println(foo);
    return foo;
}

?

首先這里有個@FastJson的標注,這是我們?yōu)榱俗屪约旱腍andlerMethodArgumentResolver能夠識別這個參數(shù)是需要自己來處理而定義的一個Annotation

?

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FastJson {
}

?

然后就是定義一個FastJsonArgumentResolver,來對HttpServletRequest的body進行解析:

?

public class FastJsonArgumentResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterAnnotation(FastJson.class) != null;
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        // content-type不是json的不處理
        if (!request.getContentType().contains("application/json")) {
            return null;
        }

        // 把reqeust的body讀取到StringBuilder
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();

        char[] buf = new char[1024];
        int rd;
        while((rd = reader.read(buf)) != -1){
            sb.append(buf, 0, rd);
        }

        // 利用fastjson轉(zhuǎn)換為對應(yīng)的類型
        if(JSONObjectWrapper.class.isAssignableFrom(parameter.getParameterType())){
            return new JSONObjectWrapper(JSON.parseObject(sb.toString()));
        } else {
            return JSON.parseObject(sb.toString(), parameter.getParameterType());
        }
    }
}

?

在這里,我們只針對content-type是application/json的對象做處理,最后通過JSON.parseObject方法簡單的把JSON串反序列化為指定的類型。

這里有一個JSONObjectWrapper對象需要解釋一下。 原本我是想如果Action方法的參數(shù)的類型是JSONObject這樣的原始類型的話就直接利用JSON.parseObject(sb.toString())映射過去。 但是由于JSONObject實現(xiàn)了Map結(jié)果,所以Spring MVC3的默認處理器MapMethodProcessor會先起作用,這樣就不能正常的映射成JSONObject對象了。 沒有辦法做了一個簡單的JSONObject包裝類,以使MapMethodProcessor不能對其進行處理。

public class JSONObjectWrapper {
    private JSONObject jsonObject;

    public JSONObjectWrapper(JSONObject jsonObject) {
        this.jsonObject = jsonObject;
    }

    public JSONObject getJSONObject() {
        return jsonObject;
    }
}

?

這里順便提一下,Spring MVC自己的HandlerMethodArgumentResolver有哪些,并且會以什么樣的順序執(zhí)行呢?
其實定義在RequestMappingHandlerAdapter里:

/**
 * Return the list of argument resolvers to use including built-in resolvers
 * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
 */
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();

    // 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()));
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new RequestHeaderMapMethodArgumentResolver());
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));

    // Type-based argument resolution
    resolvers.add(new ServletRequestMethodArgumentResolver());
    resolvers.add(new ServletResponseMethodArgumentResolver());
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
    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;
}

?

在這里我們可以看到:

  • Spring MVC本身提供了非常豐富的HandlerMethodArgumentResolver實現(xiàn)。
  • HandlerMethodArgumentResolver是按順序執(zhí)行,當然為了性能Spring本身是有Cache的,一旦確定了某一個參數(shù)可以應(yīng)用的HandlerMethodArgumentResolver,下次就不會再遍歷這個List了。
  • 自定的HandlerMethodArgumentResolver會晚于Spring自己的被執(zhí)行,這也是上面提到的JSONObject會被MapMethodProcessor先處理的原因。
  • Spring自己的JSON映射機制是通過RequestResponseBodyMethodProcessor AllEncompassingFormHttpMessageConverter來實現(xiàn)的
  • 很不幸這是一個private方法, 你沒有辦法簡單的改變Spring MVC的默認行為,除非你重寫RequestMappingHandlerAdapter

好了,有了FastJsonArgumentResolver, 接下來我們要讓它生效:

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <beans:bean class="org.springframework.samples.mvc.fastjson.FastJsonArgumentResolver"/>
    </mvc:argument-resolvers>
    <mvc:message-converters>
        <beans:bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

?

就是個Spring的配置,這里就不多講了。除了FastJsonArgumentResolver,我們還配置了FastJsonHttpMessageConverter來對返回值進行序列化。

本來我是想自己寫一個FastJsonHttpMessageConverter, 后來發(fā)現(xiàn)fastjson庫里已經(jīng)存在了, 我就不自己造輪子了。我們自己來看看實現(xiàn)吧,截取了一部分:

?

復(fù)制代碼
@Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException,
                                                                         HttpMessageNotWritableException {
    OutputStream out = outputMessage.getBody();
    String text = JSON.toJSONString(obj, features);
    byte[] bytes = text.getBytes(charset);
    out.write(bytes);
}
復(fù)制代碼

?

實現(xiàn)很簡單, 就不詳細說了。

最后來看看如何通過Ajax調(diào)用上面的Action方法:

var data = {
    name : "matianyi",
    id : 12345,
    birthday : "1983-07-01 01:12:12",
    addresses : [
        {
            street : "street1",
            number : 1
        },
        {
            street : "street2",
            number : 2
        }
    ]
};
var link = $(this);
$.ajax({
    url:"/spring-sample/fastjson1",
    dataType:"json",
    type:"POST",
    contentType: "application/json",
    data : JSON.stringify(data),
    success : function(obj){
        console.log(obj);
    }
});

兩點需要注意:

  • contentType: “application/json”
  • data : JSON.stringify(data)

這樣JavaScript的對象會被轉(zhuǎn)換為JSON串,并且最為HttpRequest的BODY傳給服務(wù)器。

來源:http://www./content-4-161401.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多