GVKun编程网logo

当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数

5

最近很多小伙伴都在问当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展casHtt

最近很多小伙伴都在问当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数这两个问题,那么本篇文章就来给大家详细解答一下,同时本文还将给你拓展cas HttpServletRequestWrapperFilter、Filter 与 HttpServletRequestWrapper 用法、HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向、HttpServletRequest-SetParameter等相关知识,下面开始了哦!

本文目录一览:

当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数

当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数

我有一个过滤器,该过滤器接收传入的请求,然后使用HttpServletRequestWrapper对其进行包装,而HttpServletRequestWrapper上又具有setParameter()方法。但是,这现在在任何过滤的servlet中将不再起作用:

<jsp:include page="testing-include.jsp">
    <jsp:param name="testing" value="testing" />
</jsp:include>

包含页面将不使用request参数。如果我删除了过滤器,并且原始的未修改请求被发送(解包)到了servlet,那么它将再次起作用。这是我的包装纸:

public class HttpServletModifiedRequestWrapper extends HttpServletRequestWrapper {

    Map parameters;

    @SuppressWarnings("unchecked")
    public HttpServletModifiedRequestWrapper(HttpServletRequest httpServletRequest) {
        super(httpServletRequest);
        parameters = new HashMap(httpServletRequest.getParameterMap());
    }

    public String getParameter(String name) {
        String returnValue = null;
        String[] paramArray = getParameterValues(name);
        if (paramArray != null && paramArray.length > 0){
            returnValue = paramArray[0];
        }
        return returnValue;
    }

    @SuppressWarnings("unchecked")
    public Map getParameterMap() {
        return Collections.unmodifiableMap(parameters);
    }

    @SuppressWarnings("unchecked")
    public Enumeration getParameterNames() {
        return Collections.enumeration(parameters.keySet());
    }

    public String[] getParameterValues(String name) {
        String[] result = null;
        String[] temp = (String[]) parameters.get(name);
        if (temp != null){
            result = new String[temp.length];
            System.arraycopy(temp,result,temp.length);
        }
        return result;
    }

    public void setParameter(String name,String value){
        String[] oneParam = {value};
        setParameter(name,oneParam);
    }

    @SuppressWarnings("unchecked")
    public void setParameter(String name,String[] values){
        parameters.put(name,values);
    }
}

如果不查看Tomcat的jsp:include和jsp:param标准操作的实现源,我真的很难确定会发生什么,但是那里肯定有一些冲突。任何帮助,将不胜感激。

cas HttpServletRequestWrapperFilter

cas HttpServletRequestWrapperFilter

###HttpServletRequestWrapperFilter 作用其实很简单就是 在HttpServletRequest对象在包装一次,让其支持getUserPrincipal,getRemoteUser方法来获取登录的用户信息。

  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       //从session或者request中取得AttributePrincipal,其实Assertion的一个principal属性
        AttributePrincipal principal = this.retrievePrincipalFromSessionOrRequest(servletRequest);
       //对request进行包装,并处理后面的过滤器,使其后面的过滤器或者servlert能够在reqeust能够在request.getRemoteUser()或者request.getUserPrincipal
        filterChain.doFilter(new HttpServletRequestWrapperFilter.CasHttpServletRequestWrapper((HttpServletRequest)servletRequest, principal), servletResponse);
    }

    protected AttributePrincipal retrievePrincipalFromSessionOrRequest(ServletRequest servletRequest) {
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpSession session = request.getSession(false);
        Assertion assertion = (Assertion)((Assertion)(session == null?request.getAttribute("_const_cas_assertion_"):session.getAttribute("_const_cas_assertion_")));
        return assertion == null?null:assertion.getPrincipal();
    }
    实现起来也比较简单,这个里面使用一个内部类CasHttpServletRequestWrapper,其继承HttpServletRequestWrapper,
    通过给定Assertion对象中取得AttributePrincipal对象来组装CasHttpServletRequestWrapper。
    final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
        private final AttributePrincipal principal;
        CasHttpServletRequestWrapper(HttpServletRequest request, AttributePrincipal principal) {
            super(request);
            this.principal = principal;
        }
        public Principal getUserPrincipal() {
            return this.principal;
        }
        public String getRemoteUser() {
            return this.principal != null?this.principal.getName():null;
        }
        public boolean isUserInRole(String role) {
            if(CommonUtils.isBlank(role)) {
                HttpServletRequestWrapperFilter.this.logger.debug("No valid role provided.  Returning false.");
                return false;
            } else if(this.principal == null) {
                HttpServletRequestWrapperFilter.this.logger.debug("No Principal in Request.  Returning false.");
                return false;
            } else if(CommonUtils.isBlank(HttpServletRequestWrapperFilter.this.roleAttribute)) {
                HttpServletRequestWrapperFilter.this.logger.debug("No Role Attribute Configured. Returning false.");
                return false;
            } else {
                Object value = this.principal.getAttributes().get(HttpServletRequestWrapperFilter.this.roleAttribute);
                if(value instanceof Collection) {
                    Iterator isMember = ((Collection)value).iterator();

                    while(isMember.hasNext()) {
                        Object o = isMember.next();
                        if(this.rolesEqual(role, o)) {
                            HttpServletRequestWrapperFilter.this.logger.debug("User [{}] is in role [{}]: true", this.getRemoteUser(), role);
                            return true;
                        }
                    }
                }
                boolean isMember1 = this.rolesEqual(role, value);
                HttpServletRequestWrapperFilter.this.logger.debug("User [{}] is in role [{}]: {}", new Object[]{this.getRemoteUser(), role, Boolean.valueOf(isMember1)});
                return isMember1;
            }
        }
        private boolean rolesEqual(String given, Object candidate) {
            return HttpServletRequestWrapperFilter.this.ignoreCase?given.equalsIgnoreCase(candidate.toString()):given.equals(candidate);
        }
    }

Filter 与 HttpServletRequestWrapper 用法

Filter 与 HttpServletRequestWrapper 用法

理解Servlet过滤器(javax.servlet.Filter)

过滤器(Filter)的概念

  • 过滤器位于客户端和web应用程序之间,用于检查和修改两者之间流过的请求和响应。
  • 在请求到达Servlet/JSP之前,过滤器截获请求。
  • 在响应送给客户端之前,过滤器截获响应。
  • 多个过滤器形成一个过滤器链,过滤器链中不同过滤器的先后顺序由部署文件web.xml中过滤器映射<filter-mapping>的顺序决定。
  • 最先截获客户端请求的过滤器将最后截获Servlet/JSP的响应信息。

过滤器的链式结构

    可以为一个Web应用组件部署多个过滤器,这些过滤器组成一个过滤器链,每个过滤器只执行某个特定的操作或者检查。这样请求在到达被访问的目标之前,需要经过这个过滤器链。

实现过滤器

在Web应用中使用过滤器需要实现javax.servlet.Filter接口,实现Filter接口中所定义的方法,并在web.xml中部署过滤器。

public class MyFilter implements Filter {
    public void init(FilterConfig fc) {
        //过滤器初始化代码
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        //在这里可以对客户端请求进行检查
        //沿过滤器链将请求传递到下一个过滤器。
        chain.doFilter(request, response);
        //在这里可以对响应进行处理
    }
    public void destroy( ) {
        //过滤器被销毁时执行的代码
    }
}

Filter接口

public void init(FilterConfig config)

web容器调用本方法,说明过滤器正被加载到web容器中去。容器只有在实例化过滤器时才会调用该方法一次。容器为这个方法传递一个FilterConfig对象,其中包含与Filter相关的配置信息

public void doFilter(ServletRequest request, 
            ServletResponse response, FilterChain chain)

每当请求和响应经过过滤器链时,容器都要调用一次该方法。需要注意的是过滤器的一个实例可以同时服务于多个请求,特别需要注意线程同步问题,尽量不用或少用实例变量。 在过滤器的doFilter()方法实现中,任何出现在FilterChain的doFilter方法之前地方,request是可用的;在doFilter()方法之后response是可用的

public void destroy()

容器调用destroy()方法指出将从服务中删除该过滤器。如果过滤器使用了其他资源,需要在这个方法中释放这些资源。

部署过滤器

在Web应用的WEB-INF目录下,找到web.xml文件,在其中添加如下代码来声明Filter。

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>
        cn.edu.uibe.webdev.MyFilter
    </filter-class>
    <init-param>
        <param-name>developer</param-name>
        <param-value>TongQiang</param-value>
    </init-param>
</filter>

针对一个Servlet做过滤

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <servlet-name>MyServlet</servlet-name>
</filter-mapping>

针对URL Pattern做过滤

<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/book/*</url-pattern>
</filter-mapping>

<filter-mapping>标记是有先后顺序的,它的声明顺序说明容器是如何形成过滤器链的。过滤器应当设计为在部署时很容易配置的形式。通过认真计划和使用初始化参数,可以得到复用性很高的过滤器。 过滤器逻辑与Servlet逻辑不同,它不依赖于任何用户状态信息,因为一个过滤器实例可能同时处理多个完全不同的请求。

HttpServletRequestWrapper 

Servlet规范中所引入的filter令人心动不已,因为它引入了一个功能强大的拦截模式。Filter是这样一种Java对象,它能在request到达servlet的服务方法之前拦截HttpServletRequest对象,而在服务方法转移控制后又能拦截HttpServletResponse对象。你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但你拟富有成效地使用过滤器的念头却被你不能改变HttpServletRequest对象的参数的现实扫了兴,因为java.util.Map所包装的HttpServletRequest对象的参数是不可改变的。这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给filter的对象。如果在HttpServletRequest对象到达Struts的action  servlet之前,我们可以通过一个filter将用户输入的多余空格去掉,难道不是更美妙吗?这样的话,你就不必等到在Struts的action表单验证方法中才进行这项工作了。 
幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。 
现在,让我们来看看,如何编写自己的HttpServletRequest装饰类

javax.servlet.http.HttpServletRequestWrapper类来装饰HttpServletRequest对象。在本例中,这个filter将删除所传来的参数中多余的空白字符。 

Struts通过调用HttpServletRequest对象的getParameterValues()对象来处理action表单。通过覆盖装饰类中此方法,你可以改变当前HttpServletRequest对象的状态

要创建HttpServletRequest的装饰类,你需要继承HttpServletRequestWrapper并且覆盖你希望改变的方法。列表5中,MyRequestWrapper类将删除getParameterValues()方法返回值的多余空白字符。

列表5:HttpServerletRequest装饰类 
程序代码: 
package trimmer.filter; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 

public final class MyRequestWrapper extends HttpServletRequestWrapper { 
	public MyRequestWrapper(HttpServletRequest servletRequest) { 
		super(servletRequest); 
	} 

    public String[] getParameterValues(String parameter) { 
		String[] results = super.getParameterValues(parameter); 
		if (results == null) 
			return null; 
		int count = results.length; 
		String[] trimResults = new String[count]; 
		for (int i = 0; i < count; i++) { 
			trimResults[i] = results[i].trim(); 
		} 
		return trimResults; 
	} 
} 

列表6演示了如何载获Http请求并装饰HttpServletRequest对象: 

package trimmer.filter; 

import java.io.IOException; 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 

public class MyFilter implements Filter { 

	private FilterConfig filterConfig; 
	
	public void init(FilterConfig filterConfig) throws ServletException { 
		System.out.println("Filter initialized"); 
		this.filterConfig = filterConfig; 
	} 

	public void destroy() { 
		System.out.println("Filter destroyed"); 
		this.filterConfig = null; 
	} 

	public void doFilter(ServletRequest request, ServletResponse response,  FilterChain chain) 
	       throws IOException, ServletException { 
		chain.doFilter(new MyRequestWrapper((HttpServletRequest) request), response); 
	} 
} 

这个程序使用了列表6所示的filter来修整用户输入。要使用这个filter,你需要在web.xml文件中如下设置filter及filter-mapping的元素。 

<filter> 
       <filter-name>TrimmerFilter</filter-name> 
       <filter-class>trimmer.filter.MyFilter</filter-class> 
</filter> 
<filter-mapping> 
       <filter-name>TrimmerFilter</filter-name> 
       <url-pattern>*.do</url-pattern> 
</filter-mapping> 

要测试这个filter,启动这个应用后,在表单中输入一些值,提交表单,看看这个filter是如何修整输入数值的。这是一个实用的装饰模式的应用。 

本文演示了如何通过应用装饰模式来“修改”HttpServletRequest对象,从而使你的servlet  filter更加有用。在上面filter例子中,filter改了request参数中的用户输入,而这一点,如果没有装饰request对象,你是无论如何也不可能做到的。 

第二个例子 转换编码

package wrapper;   
  
import java.io.UnsupportedEncodingException;   
import java.net.URLDecoder;   
  
import javax.servlet.http.HttpServletRequest;   
import javax.servlet.http.HttpServletRequestWrapper;   
  
public class GetHttpServletRequestWrapper extends HttpServletRequestWrapper {   
  
    private String charset = "UTF-8";   
  
    public GetHttpServletRequestWrapper(HttpServletRequest request) {   
        super(request);   
    }   
  
    /**  
     * 获得被装饰对象的引用和采用的字符编码  
     * @param request  
     * @param charset  
     */  
    public GetHttpServletRequestWrapper(HttpServletRequest request,   
            String charset) {   
        super(request);   
        this.charset = charset;   
    }   
  
    /**  
     * 实际上就是调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换  
     */  
    public String getParameter(String name) {   
        String value = super.getParameter(name);   
        value = value == null ? null : convert(value);   
        return value;   
    }   
  
    public String convert(String target) {   
        System.out.println("编码转换之前:" + target);   
        try {   
            return new String(target.trim().getBytes("ISO-8859-1"), charset);   
        } catch (UnsupportedEncodingException e) {   
            return target;   
        }   
    }   
  
} 
------------ 
public void doFilter(ServletRequest request, ServletResponse response,   
            FilterChain chain) throws IOException, ServletException {   
        //设置请求响应字符编码   
        request.setCharacterEncoding(charset);   
        response.setCharacterEncoding(charset);   
        //新增加的代码           
        HttpServletRequest req = (HttpServletRequest)request;   
           
        if(req.getMethod().equalsIgnoreCase("get"))   
        {   
            req = new GetHttpServletRequestWrapper(req,charset);   
        }   
           
        System.out.println("----请求被"+config.getFilterName()+"过滤");   
        //传递给目标servlet或jsp的实际上时包装器对象的引用,而不是原始的HttpServletRequest对象   
        chain.doFilter(req, response);   
           
        System.out.println("----响应被"+config.getFilterName()+"过滤");   
  
    } 

 

 

 

HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向

HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向

上篇文章我们讲了 servlet 的基本原理,这章将讲一下剩余的部分。

HttpServletRequest 接口

  该接口是 ServletRequest 接口的子接口,封装了 HTTP 请求的相关信息,由 Servlet 容器创建其实现类对象并传入 service (ServletRequest req, ServletResponse res) 方法中。我们请求的详细信息都可以通过 HttpServletRequest 接口的实现类对象获取。这个实现类对象一般都是容器创建的,我们不需要管理。

HttpServletRequest 主要功能

获取请求参数

1)什么是请求参数?

请求参数就是浏览器向服务器提交的数据

2)浏览器向服务器如何发送数据

  a)附在 url 后面,如:http://localhost:8989/MyServlet/MyHttpServlet?userId=20

  b)通过表单提交

<form action="MyHttpServlet" method="post">
    你喜欢的足球队<br /><br />
    巴西<input type="checkbox" name="soccerTeam" value="Brazil" /> 
    德国<input type="checkbox" name="soccerTeam" value="German" />
    荷兰<input type="checkbox" name="soccerTeam" value="Holland" />
    <input type="submit" value="提交" />
</form>

3)使用 HttpServletRequest 对象获取请求参数

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  //一个name对应一个值
  String userId = request.getParameter("userId"); 
  System.out.println("userId="+userId); }

 

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //一个name对应一组值
    String[] soccerTeams = request.getParameterValues("soccerTeam");
    for(int i = 0; i < soccerTeams.length; i++){
        System.out.println("team "+i+"="+soccerTeams[i]);
    }
}

在请求域中保存数据

数据保存在请求域中,可以转发到其他 Servlet 或者 jsp 页面,这些 Servlet 或者 jsp 页面就会 从请求中再取出数据

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //将数据保存到request对象的属性域中request.setAttribute("attrName", "attrValueInRequest");
    //两个Servlet要想共享request对象中的数据,必须是转发的关系
    request.getRequestDispatcher("/ReceiveServlet").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //从request属性域中获取数据
    Object attribute = request.getAttribute("attrName"); 
    System.out.println("attrValue="+attribute);
}

HttpServletResponse 接口

HttpServletResponse ServletResponse 接口的子接口,封装了 HTTP 响应的相关信息,由

Servlet 容器创建其实现类对象并传入 service (ServletRequest req, ServletResponse res) 方法中。主要功能:

1)使用 PrintWriter 对象向浏览器输出数据

//通过PrintWriter对象向浏览器端发送响应信息
PrintWriter writer = res.getWriter();
writer.write("Servlet response"); writer.close();

2)实现请求重定向

请求转发与重定向

请求转发和重定向是 web 应用页面跳转的主要手段,应用十分广泛,所以我们一定要搞清楚他们的区别。

请求转发:

  1)第一个 Servlet 接收到了浏览器端的请求,进行了一定的处理,然后没有立即对请求进行响应,而是将请求 “交给下一个 Servlet” 继续处理,下一个 Servlet 处理完成之后对浏览器进行了响应。在服务器内部将请求 “交给” 其它组件继续处理就是请求的转发。对浏览器来说,一共只发了一次请求,服务器内部进行的 “转发” 浏览器感觉不到,同时浏览器地址栏中的地址不会变成 “下一个 Servlet” 的虚拟路径。

  2)在转发的情况下,两个 Servlet 可以共享 Request 对象中保存的数据

  3)转发的情况下,可以访问 WEB-INF 下的资源

  4)当需要将后台获取的数据传送到 JSP 上显示的时候,就可以先将数据存放到 Request 对象中,再转发到 JSP 从属性域中获取。此时由于是 “转发”,所以它们二者共享 Request 对象中的数据。

public class ForwardServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("forwardServlet  doGet");

        //请求的转发
        //1.调用HTTPServletRequest 的getRequestDispatcher()方法获取RequestDispatcher对象
        //调用getRequestDispatcher()方法时需要传入转发的地址
        String path = "testServlet";

        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/"+path);
        //2.调用调用HTTPServletRequest 的forward(request,response)进行请求的转发
        requestDispatcher.forward(request,response);
    }
}

请求重定向:

  1)第一个 Servlet 接收到了浏览器端的请求,进行了一定的处理,然后给浏览器一个特殊的响应消息,这个特殊的响应消息会通知浏览器去访问另外一个资源,这个动作是服务器和浏览器自动完成的,但是在浏览器地址栏里面能够看到地址的改变,会变成下一个资源的地址。

  2)对浏览器来说,一共发送两个请求,所以用户是能够感知到变化的。

  3)在重定向的情况下,不能共享 Request 对象中保存的数据。

public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("RedirectServlet doGet");

        //执行请求的重定向,直接调用reponse.sendRedirect(path)方法
        //path为重定向的地址
        String path = "testServlet";
        response.sendRedirect(path);
    }
}

转发与重定向的区别:

 

转发

重定向

浏览器地址栏

不会变化

会变化

Request

同一个请求

两次请求

API

Request 对象

Response 对象

位置

服务器内部完成

浏览器完成

WEB-INF

可以访问

不能访问

共享请求域数据

可以共享

不可以共享

目标资源

必须是当前 Web 应用中的资源

不局限于当前 Web 应用

 


图解转发和重定向

 

原文出处:https://www.cnblogs.com/java-chen-hao/p/10729903.html

HttpServletRequest-SetParameter

HttpServletRequest-SetParameter

我知道我可以HttpServletRequest.getParameter()用来获取URL参数值。

是否可以使用等效方法设置/替换值?

今天关于当原始请求用HttpServletRequestWrapper包装时,jsp:param不再设置参数的介绍到此结束,谢谢您的阅读,有关cas HttpServletRequestWrapperFilter、Filter 与 HttpServletRequestWrapper 用法、HttpServletRequest 接口、HttpServletResponse 接口、请求转发与重定向、HttpServletRequest-SetParameter等更多相关知识的信息可以在本站进行查询。

本文标签: