如何修改request参数值并应用到springMvc中

本文介绍了一种方法,通过自定义HttpServletRequestWrapper类,实现在Controller方法中直接从参数获取当前会话的user/userid,避免了重复代码,提高了代码的简洁性和效率。
摘要由CSDN通过智能技术生成

就简洁地说一下吧。大多数crud都是在controller的一个个方法中进行的,一般的思路就是从request里取到当前user,或者userid,然后再通过这个user/userid去数据库里进行下一步操作。仔细想想的话,是不是做了一些重复的操作?能不能有一种方法可以从方法的的参数中直接取到当前user/userid?这样不仅可以直接根据其进行下一步操作,而且代码也减少了冗余。比如原先你可能要这样:

​
    @RequestMapping("test")
    @ResponseBody
    public String test(HttpServletRequest request, HttpSession session) {

            String user_uuid = (String)session.getAttribute(your_id_key);  //假设userid是uuid,并且user_uuid在用户登录的时候就保存在session中

            userService.doService(user_uuid);

            .....

    }

​

现在你只需要这样:   

@RequestMapping("test")
    @ResponseBody
    public String test(HttpServletRequest request, String user_uuid) {

            userService.doService(user_uuid);

            .....

    }

我们更希望像这样直接从参数中拿到当前会话下的user/userid,然后就直接根据其进行其他操作。那么有没有办法实现呢?答案是  有的,请继续看下面的思路

有关request的参数其实都保存在了一个parameterMap中,一般通过request.getParameterMap()得到,只要我们能在controller的方法之前得到user/userid,然后将其添加到request的parameterMap中,那么根据springMvc的参数绑定原则,在上面的test方法中String userid自然可以直接取到对应的值。但是由于tomcat的开发人员不想我们直接修改request的参数值(做了手脚),所以类似request.getParameterMap().put(xxx,xxx)是行不通的,所以需要另辟蹊径。这篇文章讲的挺清楚的https://blog.csdn.net/xieyuooo/article/details/8447301,这里就使用其中的一种方法。

 

继承HttpServletRequestWrapper包装一个自己的request

大致代码都是差不多的,如下

public class HttpRequest extends HttpServletRequestWrapper implements MyHttpRequest {

	private Map<String, String[]> params = new HashMap<String, String[]>();

	@SuppressWarnings("unchecked")
	public HttpRequest(HttpServletRequest request) {
		super(request);
		params.putAll(request.getParameterMap());
	}

	@Override
	public String getParameter(String name) {
		String[] values = params.get(name);
		return values == null || values.length == 0 ? null : values[0];
	}

	@Override
	public String[] getParameterValues(String key) {
		return params.get(key);
	}

	@Override
	public void setParameter(String key, String value) {
		if (value == null)
			return;
		params.put(key, new String[] { value });
	}
    
	@Override
	public void setParameter(String key, String[] value) {
		if (value == null)
			return;
		params.put(key, value);
	}
    
	@Override
	public void setParameter(String key, Object value) {
		if (value == null)
			return;
		params.put(key, new String[] { String.valueOf(value) });
	}

	@Override
	public Map<String, String[]> getParameterMap() {
		return params;
	}

	@Override
	public Enumeration<String> getParameterNames() {
		Enumeration<String> enumeration = new MyEnumeration<String>(params.keySet().iterator());
		return enumeration;
	}

}

对应的MyEnumeration重写下Enumeration的方法(My前缀可能有些人看的不舒服,认为有独占别人东西的感觉,但是并没有这个意思,当初加一个My前缀也没想那么多,仅仅是为了方便区分而已⊙﹏⊙)

public class MyEnumeration<E> implements Enumeration<E> {

	private Iterator<E> iterator;

	public MyEnumeration(Iterator<E> iterator) {
		this.iterator = iterator;
	}

	@Override
	public boolean hasMoreElements() {
		return iterator.hasNext();
	}

	@Override
	public E nextElement() {
		return iterator.next();
	}

}

好了,到这里你就拥有了一个可以自己设置参数的MyRequest对象了,然后思路就很清晰了,因为用户已经登录过,所以其user_uuid保存在session中,只要我们在filter中将user_uuid从session中取出来,并set到MyRequest对参数集合中,然后springMvc在接收你的MyRequest对象时就会调用getParameter方法,自然而然也就将user_uuid的值绑定到了controller方法的参数中。

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {

       //取出登录时的user_uuid(凭证)
       String user_uuid = (String)request.getSession().getAttribute(your_id_key);

       //接口                       自定义Request 
       MyHttpRequest mRequest = new HttpRequest(request);

       //将取出的user_uuid set到自定义请求的参数集合中
       mRequest.setParameter(your_id_key, user_uuid);

       //注意这里传的是自定义的request
       filter.doFilter(mRequest, response);

    ...

}

 

登录后再进行测试,直接在浏览器输入路径

后台打印,可以看到,成功地从方法的参数中拿到了session中保存的值

这样,就实现了直接从参数中拿到当前的user/userid,然后就可以直接根据其进行其他操作了,代码也不再那么冗余。有人看到最开始的两个例子可能会疑惑,这对比下来也就简化了一行代码呀,对,没错,但只简化了一行代码是因为这个业务逻辑本身就很简单,如果是一些特殊而复杂的业务逻辑,你可能需要写很多行代码才能得到一个结果,如果能将这个结果能提前在filter中保存到自定义请求的参数集合中,那么后台在编程时只需要在方法中声明一下就能拿到结果,显然要方便很多很多,尤其是对代码简洁强迫症患者来讲 (比如我自己),就是一个福音了。

 

说一些额外的(上面没问题了下面就可以忽略)

1> 为什么要使用filter,使用拦截器不更方便吗?

其实最开始我也是使用的Interceptor,但是后面发现不行,看了下dispatcher的源码,找到了原因所在

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
       ......

        try {
            ModelAndView mv = null;

         ......

                // interceptor前置拦截
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                try {
                    // 真正执行handler的方法,返回ModelAndView
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
           ......
    }

可以看到,真正传进去的参数都是processedRequest,所以说,即使你在interceptor的前置拦截中将processedRequest的引用指向了自定义的request,在真正处理handler的时候,传进去的仍然是processedRequest,而不是你自己的request。所以只能在调用doDispatch之前将HttpServletRequest的引用指向自定义的request,而filter恰好可以做到
 

 

2> 有关filter的配置,当然是使用spring的代理filter:DelegatingFilterProxy,web.xml如下

     <filter>
		<filter-name>DelegatingFilterProxy</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
		    <param-name>targetBeanName</param-name>
		    <param-value>filterManager</param-value>
		</init-param>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>DelegatingFilterProxy</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

然后在spring的配置中声明filter,如下

	<bean id="convinientFilter" name="convinientFilter"
		class="com.mine.support.web.filter.ConvinientFilter">
		<property name="excludeMappingPath" value="/,/*.log,/*log,*.css,*.js,*.png,*.jpg,*.jpeg"></property>
	</bean>
              
	<bean id="filterManager" class="com.mine.support.web.filter.FilterManager">
		<property name="filters">
			<list>
				<ref bean="convinientFilter"/>
			</list>
		</property>
	</bean>

---------------------------------------------------------------------------------------------------------------------------------------------------------------

然后说一下自己的一些事,由于十月打了一整月比赛,所以十月没时间写博客,然后我的话基本上有问题我都会回复的,只是有些奇怪我记得11月1号我回复了一个问题了的(确信的眼神),但是今天发现我的回复莫名奇妙不见了,所以也不知道真实情况是什么,不过既然已经过了这么久,相信问题也已经自己解决了吧,就不再重复回复了( ̄▽ ̄)

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值