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

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

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

            userService.doService(userid);

            .....

    }

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

有关request的参数其实都保存在了一个parameterMap中,一般通过request.getParameterMap()得到,只要我们能在springMvc之前得到user/userid,然后将其添加到request的parameterMap中,那么在上面的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();
	}

}

这样request就可以设置参数了,然后在filter中获取到当前user/userid,并将其作为参数设置到自定义的request中

   //setCondition是自定义filter中的一个流程,可以不用太在意
    @Override
	protected boolean setCondition(MyHttpRequest req, HttpServletResponse response)
			throws IOException, ServletException {
		Object id = null;
        //获取到当前用户的id,本质还是从session中取
		if ((id = securityService.checkIdentity_s(req)) == null)
			return true;
        //paramKey可以自己定义,这里我定义的就是"userid"
		req.setParameter(paramKey, id.toString());
		System.err.println("now the request is "+req);
		return false;
	}

最后只需要在chain.doFilter中传入自定义的request即可

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
        //自定义request
		MyHttpRequest req = null;
		if (request instanceof HttpServletRequest) {
			req = new HttpRequest((HttpServletRequest) request);
			for (int i = 0; i < filters.size(); i++) {
                //HttpFilter是自定义的一个抽象类
				HttpFilter filter = filters.get(i);
                //调用所有的filter,前面的setCondition函数就是里面的一个小流程
				filter.doFilter(req, response, chain);
			}
            //一定要注意传进去的是自定义的request
			chain.doFilter(req, response);
		} else {
			for (int i = 0; i < otherFilters.size(); i++) {
				OtherFilter filter = otherFilters.get(i);
				filter.doOtherRequest(request, response, chain);
			}
			chain.doFilter(request, response);
		}
	}

登录后(用户登录后其数据库里的userid会被保存到session中)再进行测试,直接在浏览器输入路径

后台打印,两种方式都可以取出

这样,就实现了直接从参数中拿到当前的user/userid,然后就可以直接根据其进行其他操作了,代码也不再那么冗余

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

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号我回复了一个问题了的(确信的眼神),但是今天发现我的回复莫名奇妙不见了,所以也不知道真实情况是什么,不过既然已经过了这么久,相信问题也已经自己解决了吧,就不再重复回复了( ̄▽ ̄)

猜你喜欢

转载自blog.csdn.net/qq_37960007/article/details/84102187