zoukankan      html  css  js  c++  java
  • spring mvc给参数起别名

    需求:

    将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

  • 相关阅读:
    deque-size
    deque-size
    deque-resize
    Android4.4——SurfaceFlinger启动
    关于linux signal 6 (SIGABRT)
    (OK) 编译ANDROID
    compile android: depmod: ERROR: Found 2 modules in dependency cycles!
    Fedora 25正式发布:工作站版默认启用Wayland显示服务器
    running ANDROID
    (3/4 OK) 在VirtualBox中运行 cm-13-kiwi (华为 荣耀 5X)
  • 原文地址:https://www.cnblogs.com/davidwang456/p/6781731.html
Copyright © 2011-2022 走看看