需求:

将http报文请求(保护body和url)中的参数传递给Controller时支持使用别名。

举例:

下面两条请求报文的结果是一致的。

http://example.com/foo?jobType=permanent&location=Stockholm

http://example.com/foo?jt=permanent&loc=Stockholm

返回响应

解决方法

 Spring MVC3 提供了丰富的参数映射机制, 详细信息可以参见这里

同时对于Spring MVC默认的提供的映射机制不能涵盖的对象,我们可以通过扩展HandlerMethodArgumentResolver和HttpMessageConverter的机制来实现。

HandlerMethodArgumentResolver对应输入, HttpMessageConverter对应输出

1.预备代码

package com.davidwang456.web.model;

import com.davidwang456.web.annotation.ParamName;

public class Job {
    @ParamName("jt")
    private String jobType;
    @ParamName("loc")
    private String location;
    public String getJobType() {
        return jobType;
    }
    public void setJobType(String jobType) {
        this.jobType = jobType;
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
    
    @Override
    public String toString(){
        return "jobType="+jobType+",location="+location;
    }
    
}

2.注解

package com.davidwang456.web.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
/**
 * Overrides parameter name
 */

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ParamName {

    /**
     * The name of the request parameter to bind to.
     */
    String value();

}

3.注解处理器

package com.davidwang456.web.processor;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;

import com.davidwang456.web.annotation.ParamName;

/**
 * Method processor supports {@link ParamName} parameters renaming
 *
 */

public class RenamingProcessor extends ServletModelAttributeMethodProcessor {

    @Autowired
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    //Rename cache
    private final Map<Class<?>, Map<String, String>> replaceMap = new ConcurrentHashMap<Class<?>, Map<String, String>>();

    public RenamingProcessor(boolean annotationNotRequired) {
        super(annotationNotRequired);
    }

    @Override
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest nativeWebRequest) {
        Object target = binder.getTarget();
        Class<?> targetClass = target.getClass();
        if (!replaceMap.containsKey(targetClass)) {
            Map<String, String> mapping = analyzeClass(targetClass);
            replaceMap.put(targetClass, mapping);
        }
        Map<String, String> mapping = replaceMap.get(targetClass);
        ParamNameDataBinder paramNameDataBinder = new ParamNameDataBinder(target, binder.getObjectName(), mapping);
        requestMappingHandlerAdapter.getWebBindingInitializer().initBinder(paramNameDataBinder, nativeWebRequest);
        super.bindRequestParameters(paramNameDataBinder, nativeWebRequest);
    }

    private static Map<String, String> analyzeClass(Class<?> targetClass) {
        Field[] fields = targetClass.getDeclaredFields();
        Map<String, String> renameMap = new HashMap<String, String>();
        for (Field field : fields) {
            ParamName paramNameAnnotation = field.getAnnotation(ParamName.class);
            if (paramNameAnnotation != null && !paramNameAnnotation.value().isEmpty()) {
                renameMap.put(paramNameAnnotation.value(), field.getName());
            }
        }
        if (renameMap.isEmpty()) return Collections.emptyMap();
        return renameMap;
    }
}

4.数据绑定

package com.davidwang456.web.processor;

import java.util.Map;

import javax.servlet.ServletRequest;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;

/**
* ServletRequestDataBinder which supports fields renaming using {@link ParamName}
*
*/
public class ParamNameDataBinder extends ExtendedServletRequestDataBinder {

   private final Map<String, String> renameMapping;

   public ParamNameDataBinder(Object target, String objectName, Map<String, String> renameMapping) {
       super(target, objectName);
       this.renameMapping = renameMapping;
   }

   @Override
   protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
       super.addBindValues(mpvs, request);
       for (Map.Entry<String, String> entry : renameMapping.entrySet()) {
           String from = entry.getKey();
           String to = entry.getValue();
           if (mpvs.contains(from)) {
               mpvs.add(to, mpvs.getPropertyValue(from).getValue());
           }
       }
   }
}

5.注册处理器

    <mvc:annotation-driven>
        <mvc:argument-resolvers>
            <bean class="com.davidwang456.web.processor.RenamingProcessor">
                <constructor-arg name="annotationNotRequired" value="true"/>
            </bean>
        </mvc:argument-resolvers>
    </mvc:annotation-driven>

或者java config模式

package com.davidwang456.web.configurer;

import java.util.List;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.davidwang456.web.processor.RenamingProcessor;

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{
      @Override
      public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
          RenamingProcessor renameResolver = new RenamingProcessor(true);
          argumentResolvers.add(renameResolver);
      }
}

 

参考文献:

【1】http://stackoverflow.com/questions/8986593/how-to-customize-parameter-names-when-binding-spring-mvc-command-objects

【2】http://geekabyte.blogspot.tw/2014/08/how-to-inject-objects-into-spring-mvc.html

【3】http://www.cnblogs.com/daxin/p/3296493.html

posted on 2017-04-28 15:15  一天不进步,就是退步  阅读(6126)  评论(0编辑  收藏  举报