菜园子

BlogJava 首页 新随笔 联系 聚合 管理
  7 Posts :: 1 Stories :: 31 Comments :: 0 Trackbacks


Spring MVC经过三个版本,功能已经改进和完善了很多。尤其是2.5以来采用的Annotation的参数绑定,极大的方便了开发,3.0对其进行更进一步的完善。对于一些特殊的前台框架,传到后台的不是普通的request中的参数,而是request流中的xml格式,这时就不能采用SpringMVC自带的参数绑定方法。这时候考虑是否能扩展一下。

SpringMVC默认使用的是AnnotationMethodHandlerAdapter.java,可以修改这个类来实现扩展。关键位置在如下方法中:

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

     ServletHandlerMethodResolver methodResolver= getMethodResolver(handler);

     Method handlerMethod = methodResolver.resolveHandlerMethod(request);

     ServletHandlerMethodInvoker methodInvoker=new ServletHandlerMethodInvoker(methodResolver);

     ServletWebRequest webRequest = new ServletWebRequest(request, response);

     ExtendedModelMap implicitModel = new BindingAwareModelMap();

     Object result=methodInvoker.invokeHandlerMethod(handlerMethod,handler,webRequest, implicitModel);

     ModelAndView mav=methodInvoker.getModelAndView(handlerMethod,handler.getClass(),result, implicitModel, webRequest);    methodInvoker.updateModelAttributes(handler,(mav!=null?mav.getModel():null),implicitModel,webRequest);

     return mav;

    }

蓝色位置是关键点,ServletHandlerMethodInvoker.java是内部类,继承自HandlerMethodInvoker.java,invokeHandlerMethod方法需要扩展,继续跟踪这个方法,发现是HandlerMethodInvoker.java这个类的方法,这个方法中的关键方法是resolveHandlerArguments(),关键部分如下

if (RequestParam.class.isInstance(paramAnn)) {

RequestParam requestParam = (RequestParam) paramAnn;

paramName = requestParam.value();

required = requestParam.required();

defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());

annotationsFound++;

}

else if (RequestHeader.class.isInstance(paramAnn)) {

RequestHeader requestHeader = (RequestHeader) paramAnn;

headerName = requestHeader.value();

required = requestHeader.required();

defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());

annotationsFound++;

}

到此扩展的话需要添加自己的类型,如RequestParamExt,添加在后面,模仿如下:

else if (RequestParamExt.class.isInstance(paramAnn)) {

RequestParamExtrequestParam = (RequestParamExt) paramAnn;

paramName = requestParam.value();

defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());

miType = requestParam.type();

annotationsFound++;

}

else if (paramName != null) {

args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);

}

这个方法上面添加扩展逻辑:

if(!RequestParamExt.TYPE_NONE.equals(miType)){

if(null == platformRequest){

HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);

platformRequest = new PlatformRequest((HttpServletRequest)request, "utf-8");

platformRequest.receiveData();

}

if(RequestParamExt.TYPE_PLATFORMREQUEST.equals(miType)){

    args[i] = platformRequest;

}

else if(RequestParamExt.TYPE_STR.equals(miType)){

args[i] = resolveRequestStrParamExt(platformRequest, methodParam);

}else{

args[i] = resolveRequestParamExt(miType,platformRequest,paramName, defaultValue, methodParam, webRequest, handler);

}

}

两个resolveRequest*Ext方法如下:

protected Object resolveRequestStrParamExt(PlatformRequest platformRequest, MethodParameter methodParam){

VariableList inVl = platformRequest.getVariableList();

String paraName = methodParam.getParameterName();

return inVl.getValueAsObject(paraName);

}

protected Object resolveRequestParamExt(String miType,PlatformRequest platformRequest, String paramName, 

String defaultValue,MethodParameter methodParam,NativeWebRequest webRequest, Object handler)throws Exception{

if(StringUtils.isBlank(paramName)){

paramName = defaultValue;

}

Class<?> paramType = methodParam.getParameterType();

DatasetList inDl = platformRequest.getDatasetList();

VariableList inVl = platformRequest.getVariableList();

if(RequestParamExt.TYPE_DS.equals(miType)){//绑定的关键过程

Dataset ds = inDl.getDataset(paramName);

Object vo = paramType.newInstance();

MiPDataBinder dataBinder = new MiPDataBinder(vo, false);

    dataBinder.bind(inVl);

    return dataBinder.getTarget();

}

}

同时还需要一个annotation的定义:示例如下:

package com.company.springext.web.bind.annotation;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface RequestParamExt {

    public static final String TYPE_NONE            = "none";

    public static final String TYPE_DS              = "ds";

    public static final String TYPE_VL              = "vl";

    public static final String TYPE_STR             = "string";   

String type() default TYPE_NONE

String value() default "";    

String defaultValue() default "ds";

}

最后是修改Spring配置:

<bean class="com.company.springext.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapterExt">    

</bean>  

到此就实现了自定义格式的数据绑定。

对于特定格式的输出,如果需要自定义的话,同样需要修改AnnotationMethodHandlerAdapterExt.java这个类,关键位置在getModelAndView()方法。在如下位置:

} else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {

            handleResponseBody(returnValue, webRequest);

            return null;

        }

添加自己的扩展方法:

else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBodyExt.class) != null) {

                ResponseBodyExt bodyMi = AnnotationUtils.findAnnotation(handlerMethod, ResponseBodyExt.class);

                handleResponseBodyExt(returnValue, webRequest, bodyMi);

                return null;

            }

定义handleResponseBodyExt方法:

 private void handleResponseBodyExt(Object returnValue, ServletWebRequest webRequest, ResponseBodyMI bodyMi) throws Exception {

            HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse();

            writeWithExtConverters(returnValue, servletResponse, bodyMi);

        }

writeWithExtConverters()方法如下:

 private void writeWithExtConverters(Object returnValue, HttpServletResponse response, ResponseBodyMI bodyMi) throws Exception {            

     convertToXML(...);    

    };

使用方式如下:

    @RequestMapping(value="/getContractList")

    @ResponseBodyExt(isCheck=true, resultType="sql", sqlColumns="ID,TUREID")

     public Page<Contract> getContractList(@RequestParamExt(value = "ds_search", type = "ds") Contract cp) throws Exception {

Page<Contract> page = method1();

return page;

}



QQ:24889356
posted on 2011-09-12 19:12 GhostZhang 阅读(4262) 评论(6)  编辑  收藏

Feedback

# re: Spring MVC 数据绑定的扩展 2011-09-12 20:45 @joe
有什么用?  回复  更多评论
  

# re: Spring MVC 数据绑定的扩展 2011-09-13 09:05 tb
恩 不错 挺有用的   回复  更多评论
  

# re: Spring MVC 数据绑定的扩展[未登录] 2011-09-13 11:13 junxy
不知道楼主的使用场景是什么?能否介绍下,另外对于一般的格式转换,他的转换器就可以满足需求了..呵呵  回复  更多评论
  

# re: Spring MVC 数据绑定的扩展 2011-09-13 12:45 GhostZhang
我们用的是一个特殊的前台框架,参数是xml格式的,所有的参数都在一个xml中,同时xml是存在request.getInputStream()中,所以不用用原来的转换器。
  回复  更多评论
  

# re: Spring MVC 数据绑定的扩展[未登录] 2011-09-13 20:00 junxy
@GhostZhang
为啥参数要用xml格式的呢?我也就是用webservice时遇到过 呵呵   回复  更多评论
  

# re: Spring MVC 数据绑定的扩展 2011-09-13 21:35 GhostZhang
因为前台框架的限制。没办法。  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: