Request在ServletAPI的规范连接地址http://blog.csdn.net/zghwaicsdn/article/details/51035146
HTTP简介
URL是浏览器寻找信息时所须要的资源位置。通过URL。人类和应用程序才干找到、使用并共享因特网上大量的数据资源。
URL语法通过格式:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?
<query>#<frag>
差点儿没有那个URL中包括了全部这些组件。
URL最重要的3个部分是方案(scheme)、主机(host)和路径(path).
经常使用介绍
方案 scheme:訪问server以获取资源时要使用那种协议
主机 host:资源宿主server的主机名或点分IP地址
port prot:资源宿主server正在监听的port号。非常多方案都有默认port号(HTTP的默认port号为80)
路径 path:server上资源的本定名,有一个斜杠将其与前面的URL组件分隔开来。
路径组件的语法是与server和方案有关的。
查询 query:某些方案会用这个组件传递參数以激活应用程序(如数据库、公告板、搜索引擎以及其它互联网网关),查询组件的内容没有通用格式。
用字符?将其与URL的器与部分分隔开来。
片段 frag:一小片或一部分资源的名字,引用对象时,不会将frag字段传递给server,这个字段是在client内部使用的。通过字符“#”将其与URL的器与部分分隔开来。
1.方案--使用什么协议
方案实际上是规定怎样訪问制定资源的主要标识符,它会告诉负责解析URL的应用程序应该使用什么协议。
方案组件必须以一个字母符号開始。有第一个“:”符号将其与URL的其余部分分隔开来。方案名是大写和小写无关的。
2.主机与port号
要想在因特网上找到资源。应用程序要知道是那台即其装载了资源。以及在那台机器的什么地方能够找到能对目标资源进行訪问的server。
主机组件表示了因特网上可以訪问资源的宿主机器。可以使用主机名或IP地址来表示主机名。
port组件标识了server正在监听的网络port。对下层使用TCP协议的Http来说。默认port号为80。
3.路径
URL的路径组件说明了资源位于server的什么地方。
路径通常非常像一个分级的文件系统路径。
4.查询字符串
通过提问题或者查询来缩小所请求资源类型的范围。
查询字符串以一系列“名/值”对的形式出现。名值对之间用字符“&”分隔
http报文
http是因特网的信使,那么HTTP报文就是它用来搬东西的包裹。
HTTP报文是在HTTP应用程序之间发送的数据块。这些数据块以一些文本形式元信息开头。这些信息描写叙述了报文的内容及含义,后面跟着可选的数据部分。
这些报文在client、server和代理之间流动。
HTTP使用流入和流出来描写叙述是无处理的方向。
报文向下游流动
HTTP报文会像河水一样流动。无论是请求报文还是响应报文,全部报文都会向下游流动。全部报文的发送者都在接受者的上游。
报文的组成部分
HTTP报文是简单的格式化数据块。
每条报文都包括一条来自client的请求。或者一条来自server的响应。
三部分组成:
1.对报文进行描写叙述的起始行(start line)
2.包括属性的首部块(header)
3.可选的、包括数据的主题部分(body)
由一个回车符和一个换行符分隔
请求报文的格式
<method> <request-URL> <version>
<headers>
<entiry-body>
响应报文的格式
<version> <status> <reason-phrase>
<headers>
<entiry-body>
简要描写叙述:
方法(method)
client希望server对资源运行的动作。
是一个单独的词,比方GET、HEAD或POST。
请求URL(request-URL)
命名了所请求资源。或者URL路径组件的完整URL。假设直接与server进行对化,仅仅要URL的路径组件是资源的绝对路径。
通常就不会有什么问题--server能够假定自己是URL的主机/port
版本号(version)
报文所使用的HTTP版本号,其格式看起来是这种:
HTTP/<major>.<minor>
当中主要版本(major)和次要版本(minor)都是整数。
状态码(status-code)
这三位数字描写叙述了请求过程中所发生的情况。每一个请求状态码的第一位数字都用于描写叙述状态的一般类别。
原因短语(reason-phrase)
数字状态码的可读版本号。包括行终止序列之前的全部文本。
首部(header)
能够有零个或多个首部。每一个首部都包括一个名字,后面跟着一个冒号(:),然后是一个可选的空格。接着是一个值。最后时一个CRLF。
首部是由一个空行(CRLF)结束的,表示了首部列表的结束和实体主题部分的開始。
实体的主题部分(entity-body)
实体的主题部分包括一个由随意数据组成的数据块。并非全部的报文都包括实体的主题部分。有时,报文仅仅是一个CRLF结束。
起始行
全部的HTTP报文都以一个起始行作为開始。
请求报文的起始行说明了要做些什么。响应报文的起始行说明发生了什么。
请求行
请求报文请求server对资源进行一些操作。请求报文的起始行,或称为请求行,包括了一个方法和一个请求URL,这种方法描写叙述了server应该运行的操作,
请求URL描写叙述了要对那个资源运行这种方法。
请求行中还包括HTTP的版本号,用来告知server,client使用的是哪种HTTP。
请求首部
请求首部仅仅在请求报文中有意义的首部。用于说明是谁或什么在发送请求、请求源来自何处,或者client的喜好及能力。
server能够依据请求首部给出的client信息。
试着为client提供更好的响应。
Request请求參数的编码问题
1.POST方法请求编码处理
假设client没有在Content-type标头中设置字符编码信息(比如浏览器能够设置Content-Type:text/html;charset=UTF-8),此时使用HttpServletRequest的
getCharachterEncoding()返回值是null。
在这个情况下,容器若使用的默认编码处理是ISO-8859-1,而client使用UTF-8发送非ASCII字符的请求參数。Servlet直接
使用getParameter()等方法取得该请求參数值,就会是不对的结果也就是得到乱码。
能够使用HttpServletRequest的setCharacterEncoding()方法指定取得POST请求參数时使用的编码。
request.setCharacterEncoding("UTF-8");
//解码
相当于要求容器作这个操作:String text = java.net.URLDecoder.decode("要转码的參数","UTF-8");
//编码
String text = java.net.URLDecoder.decode("原始字符","ISO-8859-1");
一定要在取得不论什么请求參数前运行request.setCharacterEncoding("UTF-8")方法才有作用。
2.GET请求參数编码处理
setCharacterEncoding()方法仅仅对body中字符编码才有作用。也就是基本上这种方法值对POST产生作用,当请求是GET发送时,则未定义这种方法是否会影响容器处理
编码的方式(就其原因,是由于处理URL的是HTTPserver。而非Web容器)。
在Tomcat在GET时,使用setCharacterEncoding()方法设置编码就不会有作用,取得请求參数时仍会产生乱码。
原因是post请求和get请求存放參数位置是不同的:
post方式參数存放在请求数据包的消息体中。get方式參数存放在请求数据包的请求行的URI字段中,以?開始以param=value¶me2=value2的形式附加在URI字段之后。
而request.setCharacterEncoding(charset); 仅仅对消息体中的数据起作用。对于URI字段中的參数不起作用,我们通常通过以下的代码来完毕编码转换
String paramValue = request.getParameter("paramName");
paramValue = new String(paramValue.trim().getBytes("ISO-8859-1"), charset);
对于全局请求无论GET或者POST都须要在filter过滤器中doFilter方法中设置,比方:这里并不严格
request.setCharacterEncoding("UTF-8");
if(request.getMethod().equals("GET")){
//设置GET方法參数编码为UTF-8,通过装饰类MyServletRequestWrapper来改变request对象的请求參数编码
request=new MyServletRequestWrapper(request);
}
servlet中的请求转发
servlet中的请求转发主要有三种方式:
1、 forward:是指转发,将当前request和response对象保存,交给指定的url处理。并没有表示页面的跳转,所以地址栏的地址不会发生改变。
2、 redirect:是指重定向,包括两次浏览器请求,浏览器依据url请求一个新的页面,全部的业务处理都转到下一个页面,地址栏的地址会变发生改变。
3、 include:意为包括,即包括url中的内容。进一步理解为。将url中的内容包括进当前的servlet其中来,并用当前servlet的request和respose来运行
url中的内容处理业务.所以不会发生页面的跳转,地址栏地址不会发生改变。
redirect与include、forward的差别在于是不是同一个Request,redirect会有两次交互。
include与forward的差别在于输出的内容,include包括本身servlet与跳转页面内容的结果,而forward不包括本身servlet的内容。
servlet请求转发与重定向的差别:
request.setAttribute("test","hello");
request.getRequestDispacther("/test.jsp").forword(request,response);
response.sendRedirect("test.jsp");
一、显示结果:
1、当用request.getRequestDispacther("/test.jsp").forword(request,response); 请求转发后,结果页面输出:hello
2、当用response.sendRedirect("test.jsp");重定向后。结果页面输出:null
二、底层分析:
1、请求转发(RequestDispatcher)的过程:
客户首先发送一个请求到server端,server端发现匹配的servlet。并指定它去运行,当这个servlet运行完之后。它要调用getRequestDispacther()方法,
把请求转发给指定的test.jsp,整个流程都是在server端完毕的,并且是在同一个请求里面完毕的,因此servlet和jsp共享的是同一个request,在servlet里面放的全部东西,在jsp中都能取出来,因此,jsp能把结果getAttribute()出来,getAttribute()出来后运行完把结果返回给client。
整个过程是一个请求,一个响应。
2、重定向(sendRedirect)的工作原理:
客户发送一个请求到server。server匹配servlet。这都和请求转发一样,servlet处理完之后调用了sendRedirect()这种方法,这种方法是response的方法,所以。当这个servlet处理完之后,看到response.senRedirect()方法,马上向client返回这个响应。响应行告诉client你必需要再发送一个请求。去訪问test.jsp。
紧接着client受到这个请求后,立马发出一个新的请求,去请求test.jsp,这里两个请求互不干扰,相互独立,在前面request里面setAttribute()的不论什么东西,在后面的request里面都获得不了。
可见,在sendRedirect()里面是两个请求,两个响应。
这种方法会在响应中设置HTTP状态码301以及Location标头,浏览器接受到这个标头,会又一次使用GET方法请求指定的URL,因此地址栏上会反线URL的变更。
三、表面分析:
1、当用RequestDispatcher请求转发后,地址栏为http://localhost:8080/test/TestServlet
这真好应正了上面的分析,我们起初请求的就一个servlet,至于你server端怎么转,流程怎么样的,我client根本就不知道,我发了请求后我就等
着响应,那你server那边愿意怎么转就怎么转。我client不关心也没法知道,所以当server端转发到jsp后,它把结果返回给client,client根本就
不知道你这个结果是我真正訪问的servlet产生的,还是由servlet转发后下一个组件产生的。
2、当用sendRedirect重定向后,地址栏为http://localhost:8080/test/test.jsp
由于这个时候,client已经知道了他第二次请求的是test.jsp,server已经告诉client要去訪问test.jsp了。所以地址栏里会显示想要訪问的结果。
假设在处理请求的过程中发现一些错误。而你想要传送server默认的状态与错误信息。能够使用sendError()方法。
因为利用到HTTP状态码,要求浏览器重定向网页,因此。sendError()方法相同必须在未确认输出前运行,否则会抛出IllegalStateException
response.sendError(404);
package com.zghw.servlet.demo; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Date; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class MyRequestServlet */ @WebServlet("/myRequestServlet/*") public class MyRequestServlet extends HttpServlet { static void f(Object obj) { System.out.println(obj); } private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // http://localhost:8080/servlet-demo/myRequestServlet/test?id=123&abc=222&abc=333 // URL信息 Request_URL(request); // request请求行 RequestLine(request); // request请求header RequestHeader(request); // client和server端信息地址 RequestLocalRemoteAddr(request); // 会话cookie和session RequestCookieSession(request); // request请求參数及属性 RequestParameter(request); // 请求转发 RequestDispatcher(request, response); } /** * 请求转发 */ private void RequestDispatcher(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { f("============ RequestDispatcher =================="); // 转发的类型FORWARD,INCLUDE,REQUEST,ASYNC,ERROR // REQUEST代表来自client的请求 // INCLUDE代表了当前(servlet、jsp、html)是被包括在其它(servlet、jsp、html)里的 // FORWARD代表了由其它Servlet、jsp或html转发过来的 // ASYNC // ERROR DispatcherType dispathcerType = request.getDispatcherType(); f(dispathcerType); // 能够使用?id=111能够使用像get方法一样传送字符串查询參数 RequestDispatcher dispatcher = request .getRequestDispatcher("/ms1?
id=111"); // 在include()或forward()时包括请求參数的作法,仅适用于传递字符串给还有一个Servlet。在调派请求的过程中,假设由必须共享的“对象” // 能够设置给请求对象成为属性,称为请求范围属性。 // 在使用了include或forward后,包括或转发Servlet则能够从request.getAttribute中取出这个值 // 而response.sendRedirect不能取出值。由于它是二次訪问 request.setAttribute("nowDate", new Date()); // include意为包括,即包括url中的内容,进一步理解为。将url中的内容包括进当前的servlet其中来,并用当前servlet的request和 // respose来运行url中的内容处理业务.所以不会发生页面的跳转。地址栏地址不会发生改变。 // 使用include()时。被包括的Servlet中不论什么对请求标头的设置都会被忽略。。被包括的Servlet中能够使用getSession()方法取得HttpSession对象 // dispatcher.include(request, response); // forward是指转发,将当前request和response对象保存,交给指定的url处理。并没有表示页面的跳转,所以地址栏的地址不会发生改变。
dispatcher.forward(request, response); // response.sendRedirect是指重定向,包括两次浏览器请求,浏览器依据url请求一个新的页面。全部的业务处理都转到下一个页面, // 地址栏的地址会变发生改变。 // response.sendRedirect(request.getContextPath()+"/ms"); // 假设在处理请求的过程中发现一些错误,而你想要传送server默认的状态与错误信息,能够使用sendError()方法。 // 由于利用到HTTP状态码,要求浏览器重定向网页,因此,sendError()方法相同必须在未确认输出前运行。否则会抛出IllegalStateException // 能够使用HttpServletResponse来查询状态码 // response.sendError(HttpServletResponse.SC_NOT_FOUND); // 当然能够自己定义原因短语 // response.sendError(HttpServletResponse.SC_NOT_FOUND, "找不到页面"); f("分发后还运行我"); f("============ RequestDispatcher end =================="); } /** * 获取请求參数 * * @param request * @throws UnsupportedEncodingException */ private void RequestParameter(HttpServletRequest request) throws UnsupportedEncodingException { f("============request parameter=================="); // 得到编码方式,这个body内容的编码方式,及POST方式提交的编码方式。 String characterEncoding = request.getCharacterEncoding(); f(characterEncoding); // 得到全部參数值 Enumeration<String> paramterNames = request.getParameterNames(); while (paramterNames.hasMoreElements()) { String name = paramterNames.nextElement(); // 依据參数名称得到參数值 f(name + "=" + request.getParameter(name)); } // 得到全部參数值,以map的形式存储, Map<String, String[]> parameterMap = (Map<String, String[]>) request .getParameterMap(); for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) { System.out.print(entry.getKey() + "="); if (entry.getValue() != null && entry.getValue().length > 0) { for (String value : entry.getValue()) { System.out.print(value + ","); } } } f(""); // 得到參数的多个值,比方多选框 String[] parameterValues = request.getParameterValues("abc"); if (parameterValues != null) { for (String pv : parameterValues) { // 没实用 // String p = URLDecoder.decode(pv, "UTF-8"); // 直接设置编码方式 // String p = new String(pv.getBytes("ISO-8859-1"),"UTF-8"); System.out.print(pv + ","); } } // 依据參数名称得到參数值 String parameter = request.getParameter("id"); f(""); f(parameter); f("============request parameter end=================="); } /** * 会话功能 cookie 和session * * @param request */ private void RequestCookieSession(HttpServletRequest request) { f("============cookies session =================="); // 取得全部Cookie Cookie[] cookies = request.getCookies(); // 取得session HttpSession hs = request.getSession(); // 假设当前session为空则创建一个,true为自己主动创建session HttpSession httpSession = request.getSession(true); // 当前的请求的sessionID。没有指定则返回null String sessionId = request.getRequestedSessionId(); f("改变前的sessionId=" + sessionId); // request.changeSessionId(); // sessionId = request.getRequestedSessionId(); f("改变后的sessionId=" + sessionId); boolean sessionIdFromCookie = request.isRequestedSessionIdFromCookie(); f("sessionID是从Cookie中来的?" + sessionIdFromCookie); boolean sessionIdFromURL = request.isRequestedSessionIdFromURL(); f("sessionId是从URL来的?" + sessionIdFromURL); boolean sessionIdValid = request.isRequestedSessionIdValid(); f("sessionId是有效的?" + sessionIdValid); f("============cookies session end=================="); } /** * client地址信息和server端地址信息 * * @param request */ private void RequestLocalRemoteAddr(HttpServletRequest request) { f("============IP Local port=================="); // server的IP地址 String localAddr = request.getLocalAddr(); f(localAddr); // serverIP地址相应的域名 String localName = request.getLocalName(); f(localName); // 本地使用的端口号 int port = request.getLocalPort(); f(port); // 假设client提供了Accept-Language 值,则使用client提供的语言,否则默认就是用server设置的国际化语言 Locale locale = request.getLocale(); f(locale); // 和上面的不同之处在于这个是多个server语言。默认是使用server设置的本地语言 Enumeration<Locale> enumLocale = request.getLocales(); while (enumLocale.hasMoreElements()) { Locale loc = enumLocale.nextElement(); f(loc); } // clientIP地址 String remoteAddr = request.getRemoteAddr(); f(remoteAddr); // 获得client的主机名,假设没有就获取IP地址 String remoteHost = request.getRemoteHost(); f(remoteHost); // client端口号 int remotePort = request.getRemotePort(); f(remotePort); // client登录用户信息 String user = request.getRemoteUser(); f(remotePort); f("============IP Local port end =================="); } /** * * @param request */ private void RequestHeader(HttpServletRequest request) { // 得到请求中全部header的名称集合 Enumeration<String> en = request.getHeaderNames(); f("============Header=================="); while (en.hasMoreElements()) { // 得到header名称 String name = en.nextElement(); // 取得header相应的值 f(name + "=" + request.getHeader(name)); } // 查询header中的时间戳,比方If-Modified-Since,,假设不存在返回-1 long modified = request.getDateHeader("If-Modified-Since"); f(modified); // 查询head中相应的App值 Enumeration<String> getHeaders = request.getHeaders("App"); while (getHeaders.hasMoreElements()) { // 得到header名称 String name = getHeaders.nextElement(); // 取得header相应的值 f(name + "=" + request.getHeader(name)); } // 查询Header头返回一个数值,假设不存在返回-1 int intValue = request.getIntHeader("abc"); f(intValue); f("============Header end=================="); } /** * reqeust请求行 * 请求报文请求server对资源进行一些操作。请求报文的起始行,或称为请求行,包括了一个方法和一个请求URL。这种方法描写叙述了server应该运行的操作, * 请求URL描写叙述了要对那个资源运行这种方法。请求行中还包括HTTP的版本号,用来告知server。client使用的是哪种HTTP。 */ private void RequestLine(HttpServletRequest request) { f("============request line=================="); // 请求使用的协议及版本号 String protocol = request.getProtocol(); f(protocol); // 请求使用的方法比方GET POST String method = request.getMethod(); f(method); f("============request line end=================="); } /** * 请求取得URL的全部信息 * * @param request * @throws UnsupportedEncodingException */ private void Request_URL(HttpServletRequest request) throws UnsupportedEncodingException { f("============request URL =================="); // 实例http://localhost:8080/servlet-demo/myRequestServlet/test?id=123&abc=222 // 方案实际上是规定怎样訪问制定资源的主要标识符。它会告诉负责解析URL的应用程序应该使用什么协议。
// 方案组件必须以一个字母符号開始,有第一个“:”符号将其与URL的其余部分分隔开来。方案名是大写和小写无关的。 String scheme = request.getScheme(); // 输出:http f(scheme); // 主机组件表示了因特网上能够訪问资源的宿主机器 String serverName = request.getServerName(); // 输出:localhost f(serverName); // 端口组件标识了server正在监听的网络端口。 int serverPort = request.getServerPort(); // 输出:8080 f(serverPort); // 项目在web容器中的根路径,环境路径。
假设应用程序环境路径和Webserver环境根路径相同。则应用程序环境路径为空字符串, // 假设不是。则应用程序环境路径以“/”开头。不包括“/”结尾。 String contextPath = request.getContextPath(); // 输出:/servlet-demo f(contextPath); // 资源位于server的什么地方。路径通常非常像一个分级的文件系统路径。
// Servlet中资源路径 String servletPath = request.getServletPath(); // 输出:/myRequestServlet/test f(servletPath); // 通过提问题或者查询来缩小所请求资源类型的范围。
// 查询字符串以一系列“名/值”对的形式出现,名值对之间用字符“&”分隔 String queryString = request.getQueryString(); // 输出:id=123&abc=222 f(queryString); f(URLDecoder.decode(queryString, "UTF-8")); // 路径信息不包括请求參数,值的是不包括环境路径与Servlet路径部分的额外路径信息。
// 假设没有额外路径信息。则为null(扩展映射、预设Servlet、全然匹配的情况下,getPathInfo()就会取得null) // 假设有额外路径信息。则是一个以“/”开头的字符串。
String pathInfo = request.getPathInfo(); f(pathInfo); // 请求的URI不包括方案主机名端口查询參数。仅包括地址 String requestURI = request.getRequestURI(); // 输出:/servlet-demo/myRequestServlet/test f(requestURI); // 请求的URL不包括查询參数 String requestURL = request.getRequestURL().toString(); // 输出:http://localhost:8080/servlet-demo/myRequestServlet/test f(requestURL); // server端真实绝对路径资源位置 String pathTranslated = request.getPathTranslated(); f(pathTranslated); f("============request URL end=================="); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
package com.zghw.servlet.demo; import java.io.UnsupportedEncodingException; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; /** * 包装request的请求參数编码的转换 * * @author zghw * */ public class MyServletRequestWrapper extends HttpServletRequestWrapper { private static final String CHARSET = "UTF-8"; public MyServletRequestWrapper(HttpServletRequest request) { super(request); } /** * 重写get方法编码參数 */ @Override public String getParameter(String name) { String paramter = super.getParameter(name); paramter = ("").equals(paramter) ?null : convert(paramter); return paramter; } @Override public Map<String, String[]> getParameterMap() { Map<String, String[]> map = super.getParameterMap(); Map<String,String[]> wapper=new HashMap<String,String[]>(); if (map != null) { for (Map.Entry<String, String[]> m : map.entrySet()) { String[] orgin = m.getValue(); String[] values = convertArray(orgin); wapper.put(m.getKey(), values); } } return wapper; } @Override public String[] getParameterValues(String name) { String[] strs = super.getParameterValues(name); if (strs != null) { for (int i = 0; i < strs.length; i++) { strs[i] = convert(strs[i]); } } return strs; } private String[] convertArray(String[] orgin) { String[] value = null; if (orgin != null) { value = new String[orgin.length]; int i = 0; for (String val : orgin) { value[i] = convert(val); i++; } } return value; } private String convert(String paramter) { if (paramter != null) { try { //设置请求參数的默认编码方式ISO-8859-1变为UTF-8 return new String(paramter.getBytes("ISO-8859-1"), CHARSET); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return null; } }
package com.zghw.servlet.demo; import java.io.IOException; import java.util.Date; import java.util.Enumeration; import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyServlet1 extends HttpServlet { private static final long serialVersionUID = 1L; public static void f(Object obj){ System.out.println(obj); } public void init() throws ServletException { System.out.println("运行Servlet1 init()"); } public void destroy() { System.out.println("运行Servlet1 destroy()"); } public void doGet(HttpServletRequest request, HttpServletResponse respose) throws ServletException, IOException { System.out.println("运行Servlet1 service"); DispatcherType dispathcerType = request.getDispatcherType(); System.out.println("dispathcerType:"+dispathcerType); //取出上一个转发的全部request的属性名 Enumeration<String> names = request.getAttributeNames(); while(names.hasMoreElements()){ String name = names.nextElement(); //取出属性值 f(name+":"+request.getAttribute(name)); } String id = request.getParameter("id"); f("paramter:id="+id); Date now=(Date)request.getAttribute("nowDate"); f("得到上一个转发送来的值:nowDate = "+now); //FORWARD上一个servlet或JSP html的信息參数属性,对于FORWARD前一个请求须要做的事情。 if(dispathcerType.equals(DispatcherType.FORWARD)){ String contextPath=(String)request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH); f("FORWARD:"+contextPath); String pathInfo= (String)request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO); f("FORWARD:"+pathInfo); String queryString= (String)request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING); f("FORWARD:"+queryString); String requestURI= (String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); f("FORWARD:"+requestURI); String servletPath= (String)request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH); f("FORWARD:"+servletPath); } //INCLUDE包括类型时。能够从參数中取得的类型 if(dispathcerType.equals(DispatcherType.INCLUDE)){ String contextPath= (String)request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH); f("INCLUDE:"+contextPath); String pathInfo= (String)request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO); f("INCLUDE:"+pathInfo); String queryString= (String)request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING); f("INCLUDE:"+queryString); String requestURI= (String)request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI); f("INCLUDE:"+requestURI); String servletPath= (String)request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH); f("INCLUDE:"+servletPath); } //ERROR类型时,能够从request.getAttribute();中取得须要的參数值 if(dispathcerType.equals(DispatcherType.ERROR)){ String errorException= (String)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); String exceptionType= (String)request.getAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE); String errorMessage= (String)request.getAttribute(RequestDispatcher.ERROR_MESSAGE); String requestURI= (String)request.getAttribute(RequestDispatcher.ERROR_REQUEST_URI); String servletName= (String)request.getAttribute(RequestDispatcher.ERROR_SERVLET_NAME); String statusCode= (String)request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE); } } }
package com.zghw.servlet.demo; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyFilter implements Filter { // 取得过滤器配置參数供doFilter使用 private FilterConfig filterConfig; /** * FilterConfig包括了Filter配置的參数。能够得到ServletContext对象 */ @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("运行MyFilter init"); this.filterConfig = filterConfig; // 获取过滤器的配置參数 Enumeration<String> paramNames = filterConfig.getInitParameterNames(); while (paramNames.hasMoreElements()) { String name = paramNames.nextElement(); System.out.println("过滤器配置的參数 name = " + name + " , value = " + filterConfig.getInitParameter(name)); } // 用来測试ServletContextAttributeListenter实现类作用。 ServletContext servletContext = filterConfig.getServletContext(); // 当加入属性值时,会通知监听器调用attributeAdded servletContext.setAttribute("test1", "test ServletContextAttributeListenter add in MyFilter "); // 当改变属性值时,会通知监听器调用attributeReplaced servletContext.setAttribute("test1", "test ServletContextAttributeListenter replace in MyFilter "); // 当改变属性值时,会通知监听器调用attributeRemoved servletContext.removeAttribute("test1"); } /** * 当请求来到容器,而容器发现调用Servlet的serivce方法前,能够应用某过滤器时。就会调用该过滤器的doFilter()方法, * 能够在doFilter()方法中进行service()方法的前置处理,而后决定是否调用FilterChain的doFilter()方法。* 假设调用了FilterChain的doFilter * ()方法,就会运行下一个过滤器,假设没有下一个过滤器了,就调用请求目标Servlet的service()方法。 * 假设由于某个情况(如用户没有通过验证 * )而没有调用FilterChain的doFilter()方法。则请求就不会继续交给接下来的过滤器或目标Servlet, * 这时候就是所谓的拦截请求(从Servlet的观点来看。根本不知道浏览器有发出请求)。 * 在陆续调用完FIlter实例的doFilter()仍至Servlet的service * ()之后,流程会以堆栈顺序返回,所以在FilterChain的doFilter()运行完成后。 就能够针对service()方法做兴许处理。 * * 仅仅须要知道FilterChain运行后会以堆栈顺序返回就可以。
在实现Filter接口时,不用理会这个Filter前后是否有其它Filter, * 应该将之作为一个独立的元件设计。 Servlet/JSP提供的过滤器机制,事实上是Java EE设计模式中Interceptor * Filter模式的实现。假设希望能够弹性地抽换某功能地前置与后置处理元件 (比如Servlet/JSP * 中Servlet的service()方法的前置与后置处理)。就能够应用Interceptor Filter模式。 */ @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; // POST方法參数编码为UTF-8 request.setCharacterEncoding("UTF-8"); if (request.getMethod().equals("GET")) { // 设置GET方法參数编码为UTF-8,通过装饰类MyServletRequestWrapper来改变request对象的请求參数编码 request = new MyServletRequestWrapper(request); } System.out.println("运行MyFilter doFilter"); System.out.println("运行MyFilter doFilter before"); chain.doFilter(request, response); response.setCharacterEncoding("UTF-8"); System.out.println("运行MyFilter doFilter after"); } @Override public void destroy() { System.out.println("运行MyFilter destroy"); } }