春天mvc。不区分大小写的获取参数映射

Posted

技术标签:

【中文标题】春天mvc。不区分大小写的获取参数映射【英文标题】:Spring mvc. case insensitive get parameters mapping 【发布时间】:2015-11-28 14:37:30 【问题描述】:

根据this answer我尝试编写我的代码:

pojo:

class MyBean

    public String getValueName() 
        return valueName;
    

    public void setValueName(String valueName) 
        this.valueName = valueName;
    

    String valueName;

内部控制器:

    @ModelAttribute
    public MyBean createMyBean() 
        return new MyBean();
    
    @RequestMapping(value = "/getMyBean", method = RequestMethod.GET)
    public String getMyBean(@ModelAttribute MyBean myBean) 
        System.out.println(myBean.getValueName());
        return "pathToJsp";
    

web.xml 配置:

<filter>
    <filter-name>caseInsensitiveFilter</filter-name>
    <filter-class>com.terminal.interceptor.CaseInsensitiveRequestFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>caseInsensitiveFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

过滤器:

@Component
public class CaseInsensitiveRequestFilter extends OncePerRequestFilter 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException 
        filterChain.doFilter(new CaseInsensitiveHttpServletRequestWrapper(request), response);
    

    private static class CaseInsensitiveHttpServletRequestWrapper extends HttpServletRequestWrapper 

        private final LinkedCaseInsensitiveMap params = new LinkedCaseInsensitiveMap();

        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request
         * @throws IllegalArgumentException if the request is null
         */
        private CaseInsensitiveHttpServletRequestWrapper(HttpServletRequest request) 
            super(request);
            params.putAll(request.getParameterMap());
        

        @Override
        public String getParameter(String name) 
            String[] values = getParameterValues(name);
            if (values == null || values.length == 0) 
                return null;
            
            return values[0];
        

        @Override
        public Map getParameterMap() 
            return Collections.unmodifiableMap(this.params);
        

        @Override
        public Enumeration getParameterNames() 
            return Collections.enumeration(this.params.keySet());
        

        @Override
        public String[] getParameterValues(String name) 
            return (String[]) params.get(name);
        
    

在调试中我看到过滤器方法调用但我无法实现不区分大小写的获取参数映射。

例如 localhost:8081/getMyBean?valueName=trololo 有效,但 localhost:8081/getMyBean?valuename=trololo - 无效

【问题讨论】:

您为什么认为在您当前的配置中应该调用Filter 根据以下回答:***.com/a/26157610/2674303 所以你使用的是 Spring Boot? @Sotirios Delimanolis 我不确定,但我的 pom 中依赖于 spring-framework-bom @Sotirios Delimanolis 主题已更新 【参考方案1】:

我相信你的问题是@ModelAttribute。您要求 Spring 将参数映射到 MyBean 对象,并且该对象内部的属性是 valueName

为了让 Spring 将参数反映到对象,它需要使用正确的大小写。

你有两个选择:

在您的 MyBean 对象中将属性名称更改为 valuename,并将所有属性名称更改为小写,它应该可以在您的解决方案的帮助下工作。 删除@ModelAttribute 并为每个属性添加@RequestParam。如果你有很多道具,这可能会很痛苦。

【讨论】:

这两个选项都不好。我想将新功能封装在单独的代码中。用 valuename 代替 valueName 太疯狂了 嗯,我明白,但我相信没什么可做的。 为什么?这看起来并不难。我知道 spring mvc 中存在重命名处理器和很多混乱的东西。为什么我不能在适当的地方用 equalsIgnoreCase 替换 equals 问题是,spring 有它的注释处理器。当看到@ModelAttribute 注解时,它会调用反射并尝试设置模型的属性。这与 RequestParam 不同。我查看了注释处理器,但看不到作弊的方法。也许,您应该复制该注释处理器,并以您想要的方式更改它。我真的理解并且我同意应该有一种更简单的方法来做到这一点,但是 unf.我看不见。 感谢您的努力)让我们等待另一个答案。也许有人可以提出更相关的建议【参考方案2】:

这是你可以做的......

使用所有小写变量创建域(POJO)

public class MyBean
    private String valuename;

    public String getValuename() 
        return valuename;
    

    public void setValuename(String valuename) 
        this.valuename = valuename;
    

然后创建一个扩展HttpServletRequestWrapper的类

public class CustomWrappedRequest extends HttpServletRequestWrapper

    private final Map<String, String[]> modifiableParameters;
    private Map<String, String[]> allParameters = null;

    public CustomWrappedRequest(final HttpServletRequest request, 
                                                    final Map<String, String[]> additionalParams)
    
        super(request);
        modifiableParameters = new TreeMap<String, String[]>();
        modifiableParameters.putAll(additionalParams);
    

    @Override
    public String getParameter(final String name)
    
        String[] strings = getParameterMap().get(name);
        if (strings != null)
        
            return strings[0];
        
        return super.getParameter(name);
    

    @Override
    public Map<String, String[]> getParameterMap()
    
        if (allParameters == null)
        
            allParameters = new TreeMap<String, String[]>();
            allParameters.putAll(super.getParameterMap());
            allParameters.putAll(modifiableParameters);
        
        return Collections.unmodifiableMap(allParameters);
    

    @Override
    public Enumeration<String> getParameterNames()
    
        return Collections.enumeration(getParameterMap().keySet());
    

    @Override
    public String[] getParameterValues(final String name)
    
        return getParameterMap().get(name);
    

最后添加一个带有适当 web.xml 配置的过滤器,doFilter() 将如下所示

public void doFilter(ServletRequest request, ServletResponse reponse, FilterChain chain)
            throws IOException, ServletException 
        Map<String, String[]> params = request.getParameterMap();
        Map<String, String[]> extraParams = new TreeMap<String, String[]>();
        Iterator<String> i = params.keySet().iterator();

        while ( i.hasNext() )
          
            String key = (String) i.next();
            String value = ((String[]) params.get( key ))[ 0 ];
            extraParams.put(key.toLowerCase(), new String[] value);

          
        HttpServletRequest wrappedRequest = new CustomWrappedRequest((HttpServletRequest)request, extraParams);

        chain.doFilter(wrappedRequest, reponse);

    

在这里,过滤器会将参数转换为小写并将其附加到您的自定义请求中。 然后使用可以在控制器代码中使用@ModelAttribute来获取所需的对象。

希望对你有帮助:)

【讨论】:

valuename 太糟糕了 我知道...但是如果您想要不区分大小写的请求参数映射,spring 不提供任何钩子...我相信您将不得不为您的域坚持使用小写或大写. Spring 是开源项目。我相信很多春季提交者都会访问 SO。也许票会被创建。【参考方案3】:

实际上,您必须根据您的 bean 变量名称更改 CaseInsensitiveRequestFilter 类中的内容。在您的情况下,变量是valueName,因此对于每个请求,它将根据您的变量设置方法骆驼案例注入将其转换,然后根据您的请求进行匹配。只需尝试满足您的自定义要求:

package biz.deinum.web.filter;

import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.filter.OncePerRequestFilter;

public class CaseInsensitiveRequestFilter extends OncePerRequestFilter 
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException 
        filterChain.doFilter(new CaseInsensitiveHttpServletRequestWrapper(request), response);
    

    private static class CaseInsensitiveHttpServletRequestWrapper extends HttpServletRequestWrapper 

        private final LinkedCaseInsensitiveMap<String[]> params = new LinkedCaseInsensitiveMap<>();

        private CaseInsensitiveHttpServletRequestWrapper(HttpServletRequest request) 
            super(request);
            Map<String, String[]> map = request.getParameterMap();
            Set set = map.entrySet();
            Iterator it = set.iterator();
            Map<String, String[]> tempMap = new HashMap<String, String[]>(); 
            while (it.hasNext()) 
                Map.Entry<String, String[]> entry = (Entry<String, String[]>) it.next();
                String key = entry.getKey();
                // Keep your parameter bean name here in your case it is "valueName"
                String beanParamaterName = "valueName";
                if(key.equalsIgnoreCase(beanParamaterName))
                    tempMap.put(key.toLowerCase(), entry.getValue());
                
            
            params.putAll(tempMap);
        

        @Override
        public String getParameter(String name) 
            String[] values = getParameterValues(name);
            System.out.println(values.toString()+"-");
            if (values == null || values.length == 0) 
                return null;
            
            return values[0];
        

        @Override
        public Map<String, String[]> getParameterMap() 
            return Collections.unmodifiableMap(this.params);
        

        @Override
        public Enumeration<String> getParameterNames() 
            return Collections.enumeration(this.params.keySet());
        

        @Override
        public String[] getParameterValues(String name) 
            System.out.println(name);
            return (String[])params.get(name);
        
    

【讨论】:

以上是关于春天mvc。不区分大小写的获取参数映射的主要内容,如果未能解决你的问题,请参考以下文章

映射不区分大小写 - 代码优先 - 实体框架

不改变 POJO 的不区分大小写的 JSON 到 POJO 的映射

带有null键的Java不区分大小写的映射[duplicate]

如何注释DTO以启用不区分大小写的映射?

由于不区分大小写的 URL 和默认值,如何避免 ASP.NET MVC 中的重复内容?

在 ASP.NET MVC 中强制区分大小写路由