Spring MVC数据绑定的扩展

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技术群425783133

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值