|
來源: 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)。 假設(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。 方法的定義是這樣的: @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í)行呢? /**
* 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;
}
? 在這里我們可以看到:
好了,有了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)吧,截取了一部分: ?
@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);
}
? 實現(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);
}
});
兩點需要注意:
這樣JavaScript的對象會被轉(zhuǎn)換為JSON串,并且最為HttpRequest的BODY傳給服務(wù)器。 來源:http://www./content-4-161401.html |
|
|