2025-02-15

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;

}
 作者“菜園子”

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *