Servlet

本文深入探讨了Servlet的工作原理,包括JDK与Tomcat的兼容性问题、生命周期管理、请求响应处理及乱码解决方案。通过实例展示了Servlet的初始化、运行、销毁过程,以及如何利用web.xml配置和注解实现自动加载、请求转发与重定向。同时,讲解了请求参数的获取方法与Servlet文件配置,强调了Servlet多重映射的实践。
摘要由CSDN通过智能技术生成

5# Servlet

问题

1.JDK和Tomcat兼容性问题
java.lang.UnsupportedClassVersionError: servletDemo/HelloWorldServlet has been compiled by a more recent version of the Java Runtime (class file version 59.0), this version of the Java Runtime only recognizes class file versions up to 52.0 (无法载入的.类 [servletDemo.HelloWorldServlet])
2.JDK和环境配置
3.Tomcat启动后一闪而过
4.Tomcat乱码问题

1.Servlet概述

  • Servlet是使用Java语言编写的运行在服务器端的程序
  • 狭义的Servlet: 指Java语言实现的一个接口;广义的Servlet: 指任何实现了这个Servlet接口的类
  • Servlet的主要作用: 处理客户端传来的HTTP请求,并返回一个响应(它能处理的请求有doGet()和doPost()等方法)
  • Servlet由Servlet容器提供,Servlet容器将Servlet动态的加载到服务器上
  • Servlet容器指提供了Servlet功能的服务器(Tomcat)
  • Servlet容器支持所有HTTP协议的请求和响应,与HTTP协议相关的Servlet使用HTTP请求和TTP响应与客户端进行交互
    在这里插入图片描述
  • 1.Servlet的请求首先会被HTTP服务器(Apache) 接收
  • 2.HTTP服务器只负责静态HTML页面的解析,对于Servlet的请求转发给Servlet容器(Tomcat)
  • 3.Servelt容器根据web.xml文件中的映射关系,调用相应的Servlet
  • 4.Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端
  • 5.针对Servlet的每次请求,Web服务器在调用service()方法之前都会创建两个对象,分别是HttpServletRequest和HttpServletResponse
  • 6.HttpServletRequest用于封装HTTP请求信息,简称request对象;HttpServletResponse用于封装HTTP响应信息,简称response对象
  • 7.在Web服务器运行阶段,每个Servlet都只会创建一个实例对象;而每次HTTP请求,Web服务器都会调用所请求Servlet实例的service()方法,重新创建一个request对象和response对象
    在这里插入图片描述

2.Servlet生命周期

在这里插入图片描述

  • 一个Servlet的生命周期由部署Servlet的容器来控制
  • Servlet生命周期划分为3个阶段
    • 1.初始化阶段
    • 2.运行阶段
    • 3.销毁阶段

1.初始化阶段

  • 1.客户端向Servlet容器(Tomcat)发出HTTP请求要求访问Servlet
  • 2.Servlet容器解析请求,检查内存中是否存在相应的Servlet对象
  • 3.如果有直接使用该Servlet对象,如果没有则创建Servlet实例对象(class),然后调用init()方法实现Servlet的初始化工作
  • 4.在Servlet的整个生命周期中,它的init()方法只被调用一次

2.运行阶段

  • 1.Servelt容器为请求创建代表HTTP请求的ServletRequest对象和代表HTTP响应的ServletResponse对象
  • 2.将它们作为参数传递给Servlet的service()方法
  • 3.service()方法从ServletRequest对象中获得客户端请求信息并处理该请求,通过ServletResponse对象生成响应结果
  • 4.在Servlet的整个生命周期内,对于Servlet的每一次请求,Servlet都会调用一次Servlet的service()方法,并且创建新的ServletRequest和ServletResponse对象;即service()方法在Servlet的整个生命周期中会被调用多次

3.销毁阶段

  • 1.当服务器关闭或Web应用被移除出容器时,Servlet随着Web应用的销毁而销毁
  • 2.在销毁Servlet之前,Servlet容器会调用Servlet的destroy()方法,以便让Servlet对象释放它所占用的资源
  • 3.在Servlet的整个生命周期中,destroy()方法也只调用一次
  • 4.Servlet对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭或Web应用被移除容器时,Servlet对象才销毁

4.自动加载Servlet程序

  • 1.使Servlet在Tomcat启动时就自动加载并且初始化,需要使用web.xml中的< load-on-startup>元素
  • 2.< load-on-startup>元素是< servlet>元素的一个子元素,它用于指定Servlet被加载的时机和顺序
  • 3.< load-on-startup>元素的值必须是一个整数;如果这个值是一个负数,或者没有设定这个元素,Servlet容器将在客户端首次请求这个Servlet时加载它;如果这个值是正整数或0,Servlet容器将在Web应用启动时加载并初始化Servlet
  • 4.< load-on-startup>元素的值越小,它对应的Servlet就越先被加载
    package test;
    
    import java.io.IOException;
    
    import javax.servlet.GenericServlet;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class ServletTest6 extends GenericServlet{
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	
    	public void init(ServletConfig config) throws ServletException {
    		System.out.println("auto load");
    	}
    
    	@Override
    	public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stube
    		System.out.println("HelloWorld");			
    	}
    	
    	public void destroy() {
    		System.out.println("destroy");
    	}	
    }
    
      <servlet>
      	<servlet-name>ServletTest6</servlet-name>
      	<servlet-class>test.ServletTest6</servlet-class>
      	<load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
      	<servlet-name>ServletTest6</servlet-name>
      	<url-pattern>/ServletTest6</url-pattern>
      </servlet-mapping>
    
    在这里插入图片描述
    在这里插入图片描述

3.Servlet接口及其实现类

1.Servlet类的层次结构:
在这里插入图片描述

  • 说明:
    • Java API提供了javax.servlet和javax.servlet.http包,为编写Servlet提供了相应的接口和实现类。
    • 编写所有的Servlet时必须直接或间接地实现javax.servlet.Servlet接口,该接口定义了Servlet的生命周期方法
    • 一般采用间接实现,即通过javax.servlet.GenericServlet或javax.servlet.http.HttpServlet类派生
    • 编写Servlet时要用到javax.servlet.HttpServlet类为javax.servlet.GenericServlet的子类
    • GenericServlet是一个抽象类,该类为Servlet接口提供了部分实现,但它并没有实现HTTP请求处理
    • HttpServlet是GenericServlet的子类,它继承了GenericServlet的所有方法,并对HTTP请求中的POST,GET等类型提供了具体的操作方法
    • javax.servlet.GenericServlet类为java.lang.Object类的子类,并且实现了javax.servlet.Servlet接口,javax.servlet.ServletConfig接口,javax.io.Serializable接口
    • 一般情况下要用到的javax.servlet.http.HttpServieRequest接口继承于javax.servlet.ServletRequest接口;javax.servlet.http.HttpServletResponse接口继承于javax.servlet.ServletResponse接口

2.Servlet接口与实现类

类/接口名说明
Servlet接口定义了Servlet必须实现的方法
HttpServlet类提供Servlet接口的HTTP特定实现
HttpServletRequest接口获得客户端的请求信息
HttpServletResponse接口获得服务器端的响应信息
ServletContext接口与相应的Servlet容器通信
ServletConfig接口用于在Servlet初始化时向其传递信息

3.Servlet接口常用方法

方法名功能
void init(ServletConfig config)容器创建好Servlet对象后会调用该方法,在Servlet的生命周期中仅执行一次;该方法接收一个ServletConfig类型的参数,Servlet容器通过这个参数向Servlet传递初始信息
void service(ServletRequest request,ServletResponse response)负责响应用户的请求,当容器接收到客户端访问Servlet对象的请求后,就会调用此方法;容器会构造一个表示客户端请求信息的ServletRequest对象和一个用于响应客户端请求信息的ServletResponse对象作为参数传递给service()方法;在该方法中,通过ServletRequest对象可以得到客户端的相关信息和请求信息,通过ServletResponse对象可以设置响应信息
void destroy当服务器关闭或Servlet对象被移除时,容器会执行该方法,释放Servlet对象占用的资源
ServletConfig getServletConfig()返回一个ServletConfig对象,该对象用来返回初始化参数和ServletContext接口提供有关Servlet的配置信息
String getServletInfo()返回一个字符串,提供有关Servlet的信息;如:作者,版本,版权信息

4.HttpServlet类常用方法

方法名功能
void doGet()由Servlet引擎调用处理一个HTTP GET请求
void doPost()由Servlet引擎调用处理一个HTTP POST请求
void doPut()处理一个HTTP PUT请求,请求URI指出被载入的文件位置
void doDelete()处理一个HTTP DELETE请求,请求URI指出资源被删除
void service()将请求导向doGet(),doPost()等,一般不应该覆盖此方法

5.HttpServletRequest接口常用方法

方法名功能
String getContextPath()返回指定Servlet上下文(Web应用)的URI的前缀
Cookie[] getCookies()返回与请求相关Cookie的一个数组
String getHeader(String name)返回指定的HTTP头标
String getMethod返回HTTP请求方法(如:GET,POST)
String getQueryString()返回查询字符串,即URI中"?"后面的部分
String getRequestedSessionId(返回客户端的会话ID)
String getRequestURI()返回统一资源标识符(URI)中的一部分,从"/"开始,包括上下文但不包括任意查询子串
String getServeltPath()返回请求URI上下文后的子串
HttpSession getSession(boolean create)返回当前HTTP会话,如果不存在,则创建一个新的会话,create参数为true
boolean isRequestedSessionIdValid()如果客户端返回的会话ID仍然有效,则返回true
Object getAttribute(String name)返回具有指定名字的请求属性
Enumeration getAttributeName()返回请求中所以属性名的枚举值
String getCharacterEncoding()返回请求所用的字符编码
Int getContentLength()指定输入流的长度,如果未知则返回-1
String getParameter(String name)返回指定参数,如果不存在,则返回null
Enumeration getParameterName()返回请求中所以参数名的一个枚举(可能为空)
String[] getParameterValues(String name)返回指定输入参数名的取值数组,如果不存在则返回null
String getProtocol()返回请求使用协议的名称和版本
String getServerName()返回处理请求的服务器的主机名
String getServerPort()返回接收主机正在监听的端口号
String getRemoteAddr()返回客户端主机的数字型IP地址
String getRemoteHost()返回客户端主机名
void setAttribute(String name,Object obj)以指定名称保存请求中指定对象的引用
void removeAttribute(String name)从请求中删除指定属性

6.HttpServletResponse接口常用方法

方法名功能
void addCookie(Cookie cookie)将一个Set-Cookie头标加入到响应
void addDateHeader(String name,long date)使用指定日期加入带有指定名字的响应头标
void setHeader(String name,String value)设置具有指定名字和取值的一个响应头标
boolean containHeader(String name)判断响应是否包含指定名字的头标
void setStatus(int status)设置响应状态码为指定值
String getCharacterEncoding()返回响应使用字符编码的名称
OutputStream getOutputStream()返回一个记录二进制的响应数据的输出流,此方法和getWriter()方法两者只能调用其一
Writer getWriter()返回一个记录文本的响应数据的PrintWriter
void reset清除输出缓存及所有响应头标
void setContentLength(int Length)设置响应的内容体的长度
void setContentType(String type)设置响应的内容类型

4.分析Servlet接口及其实现类

1.HttpServlet类

  • 1.Web应用大多都是通过HTTP协议和客户端进行交互,因此在Servlet接口中提供了一个抽象类javax.servlet.http.HttpServlet,它是GenericServlet的子类,专门创建基于HTTP协议的Servlet
  • 2.HttpServlet源码分析
    • 1.配置源码包:Eclipse–Window–Preferences–Java–Installed JRE
    • 2.查看源码:Ctrl+鼠标左键点击要查看的类即可查看源码
    • 3.手动配置源码包:如果通过步骤2无法查看源码,可通过网络下载相应的xxx_src.zip文件(无需解压),然后点击步骤2中的Attach Resouce手动配置
    • 4.分析HttpServlet源码
      public abstract class HttpServlet extends GenericServlet {
      ...
      ...
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{
              String protocol = req.getProtocol();
              String msg = lStrings.getString("http.method_get_not_supported");
              if (protocol.endsWith("1.1")) {
      	        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
              } else {
                  resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
              }
      }
      ...
      ...
      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              String protocol = req.getProtocol();
              String msg = lStrings.getString("http.method_post_not_supported");
              if (protocol.endsWith("1.1")) {
                  resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
              } else {
                  resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
              }
      }
      ...
      ...
      protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              String method = req.getMethod();
              if (method.equals(METHOD_GET)) {
                  long lastModified = getLastModified(req);
                  if (lastModified == -1) {
                      // servlet doesn't support if-modified-since, no reason
                      // to go through further expensive logic
                      doGet(req, resp);
                  } else {
                      long ifModifiedSince;
                      try {
                          ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                      } catch (IllegalArgumentException iae) {
                          // Invalid date header - proceed as if none was set
                          ifModifiedSince = -1;
                      }
                      if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                          // If the servlet mod time is later, call doGet()
                          // Round down to the nearest second for a proper compare
                          // A ifModifiedSince of -1 will always be less
                          maybeSetLastModified(resp, lastModified);
                          doGet(req, resp);
                      } else {
                          resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                      }
                  }
      
              } else if (method.equals(METHOD_HEAD)) {
                  long lastModified = getLastModified(req);
                  maybeSetLastModified(resp, lastModified);
                  doHead(req, resp);
      
              } else if (method.equals(METHOD_POST)) {
                  doPost(req, resp);
      
              } else if (method.equals(METHOD_PUT)) {
                  doPut(req, resp);
      
              } else if (method.equals(METHOD_DELETE)) {
                  doDelete(req, resp);
      
              } else if (method.equals(METHOD_OPTIONS)) {
                  doOptions(req,resp);
      
              } else if (method.equals(METHOD_TRACE)) {
                  doTrace(req,resp);
      
              } else {
                  //
                  // Note that this means NO servlet supports whatever
                  // method was requested, anywhere on this server.
                  //
      
                  String errMsg = lStrings.getString("http.method_not_implemented");
                  Object[] errArgs = new Object[1];
                  errArgs[0] = method;
                  errMsg = MessageFormat.format(errMsg, errArgs);
      
                  resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
              }
          }
      ...
      ...
      public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
              HttpServletRequest  request;
              HttpServletResponse response;
              try {
                  request = (HttpServletRequest) req;
                  response = (HttpServletResponse) res;
              } catch (ClassCastException e) {
                  throw new ServletException("non-HTTP request or response");
              }
              service(request, response);
          }
      }
      ...
      ...
      
      • 1.HttpServlet主要有两大功能:第一是根据用于请求方式的不同,定义相应的doXxx()方法处理用户请求;第二是通过service()方法将HTTP请求和相应分别强转为HttpServletRequest和HttpServletResponse类型的对象
      • 2.HttpServlet在重写的service()方法中,为每一种Http请求方式都定义了对应的doXxx()方法;因此当定义的类继承HttpServlet后只需根据请求方式重写相应的doXxx()方法即可而不需要重写service()方法
      • 3.编译的步骤
        在这里插入图片描述

2.ServletConfig接口

  • 1.Servlet运行期间需要一些辅助信息(例:文件使用的编码等),这些信息可以在web.xml文件中使用一个或多个< init-param>元素进行配置
  • 2.当Tomcat初始化一个Servlet时,会将该Servlet的配置信息封装到一个ServletConfig对象
  • 3.通过调用init(ServletConfig config)方法将ServletConfig对象传递给Servlet
  • 4.ServletConfig定义了一系列获取配置信息的方法(即通过ServletConfig对象可以获得web.xml文件中的参数信息)
    方法说明功能描述
    String getInitParameter(String name)根据初始化参数名返回对应的初始化参数值
    Enumeration getInitParameterNames()返回一个Enumeration对象,其中包含了所有的初始化参数名
    ServletContext getServletContext()返回一个代表当前Web应用的ServletContext对象
    String getServletName()返回一个Servlet的名字,即web.xml中< servlet-name>元素的值
     <servlet>
      	<servlet-name>test1</servlet-name>
      	<servlet-class>test.ServletTest1</servlet-class>
      	<init-param>
      		<param-name>encoding</param-name>
     		<param-value>UTF-8</param-value>
    	</init-param>
      </servlet>
      <servlet-mapping>
      	<servlet-name>test1</servlet-name>
      	<url-pattern>/test/*</url-pattern>
      </servlet-mapping>
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	// TODO Auto-generated method stub
    	response.setContentType("text/html;charset=utf-8");
    	PrintWriter out = response.getWriter();
    	ServletConfig config = this.getServletConfig();
    	String paramValue = config.getInitParameter("encoding");
    	String ServletName = config.getServletName();
    	out.println("ServletTest1<br/>");
    	out.println("<h3>" + paramValue + "</h3>");
    	out.println(ServletName);
    }
    
    在这里插入图片描述
    在这里插入图片描述
  • 语法说明:
    • 1.< init-param>元素:表示要设置的参数
    • 2.< param-name>元素:表示参数的名称
    • 3.< param-value>元素:表示参数的值
    • 4.注意doGet()的方法中需要设置响应的格式为html文档,否则不会显示格式

3.ServletContext接口

  • 1.当Servlet容器启动时会为每个Web应用创建一个唯一的ServletContext对象代表当前的Web应用
  • 2.ServletContext接口可以获取Web应用程序的初始化参数
    • 1.在web.xml文件中,不仅可以配置某个Servlet的初始化信息,还可以配置整个Web应用的初始化信息,Web应用初始化参数配置方法如下
      <context-param>
      	<param-name>xxx</param-name>
      	<param-value>yyy</param-name>
      </context-param>
      
    • 2.< context-param>元素位于根元素< web-app>中,它的子元素< param-name>< param-value>分别用来指定参数的名字和参数值
    • 3.想要使用这些参数信息可以使用ServletContext接口,通过该接口给出的方法获得
       <context-param>
        	<param-name>SchoolName</param-name>
        	<param-value>huazhong</param-value>
       </context-param>
      
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	// TODO Auto-generated method stub
      	response.setContentType("text/html;charset=utf-8");
      	PrintWriter out = response.getWriter();
      	
      	ServletConfig config = this.getServletConfig();
      	ServletContext context1 = this.getServletContext();
      	ServletContext context2 = config.getServletContext();
      	
      	String paramValue = config.getInitParameter("encoding");
      	String ServletName = config.getServletName();
      	Enumeration<String> paramValue1 = context1.getInitParameterNames();
      	while(paramValue1.hasMoreElements()) {
      		String name = paramValue1.nextElement();
      		String value = context1.getInitParameter(name);
      		out.println("<h3>" + name + ":" + value + "</h3>");
      	}
      	Enumeration<String> paramValue2 = context2.getInitParameterNames();
      	while(paramValue2.hasMoreElements()) {
      		String name = paramValue2.nextElement();
      		String value = context2.getInitParameter(name);
      		out.println("<h3>" + name + ":" + value + "</h3>");
      	}
      	
      	out.println("ServletTest1<br/>");
      	out.println("<h3>" + paramValue + "</h3>");
      	out.println(ServletName);
      }
      
      在这里插入图片描述
      在这里插入图片描述
    • 语法说明:
      • 1.结果1和结果2的区别:web.xml中ServletTest1配置了信息,而ServletTest2没有配置信息,所以ServletTest2中paramValue为null,ServletName为包名.类名
      • 2.context参数信息是整个Web应用的初始信息,所有两个Servlet都可以获取
  • 3.实现多个Servlet对象共享数据
    • 1.由于一个Web应用中的所有Servlet共享同一个ServletContext对象,因此,ServletContext对象的域属性可以被该Web应用中的所有Servlet访问
    • 2.ServletContext接口的方法
      方法说明功能描述
      Enumeration getAttributeNames()返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的所有域属性名
      Object getAttribute(String name)根据参数指定的属性名返回一个与之匹配的域属性值
      void removeAttribute(String name)根据参数指定的域属性名,从ServletContext中删除匹配的域属性
      void setAttribute(String name,Object obj)设置ServletContext的域属性,其中name是域属性名,obj是域属性值
    • ServletTest1
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		ServletContext context = this.getServletContext();
      		context.setAttribute("data", "this is ServletTest1's data");			
      }
      
    • ServletTest2
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		PrintWriter out = response.getWriter();
      		ServletContext context = this.getServletContext();
      		String value = (String) context.getAttribute("data");
      		out.println(value);		
      }
      
      在这里插入图片描述
    • 语法说明:
      • 1.context.getAttribute(String name)方法返回的是Object对象,需要强转为String类型
      • 2.需要先运行ServletTest1再运行ServletTest2才会成功显示,否则显示为null
      • 3.ServletContext对象所存储的数据可以被多个Servlet所共享
  • 4.读取Web应用下的资源文件
    • 1.实际开发中可能会读取Web应用中的一些资源文件(例:配置文件,图片等),为此在ServletContext接口中定义了一些读取Web资源的方法,这些方法是依靠Servlet容器来实现的
    • 2.Servlet容器根据资源文件相对于Web应用的路径,返回关联资源文件的IO流,资源文件在文件系统的绝对路径等
    • 3.ServetContext接口的常用方法
      方法说明功能描述
      Set getResourcePaths(String path)返回一个Set集合,集合中包含资源目录中子目录的和文件的路径名称;参数path必须以正斜线/开始,指定匹配资源的部分路径
      String getRealPath(String path)返回资源文件在服务器文件系统上的真实路径(文件的绝对路径);参数path代表资源文件的虚拟路径,它以正斜线/开始,/表示当前Web应用的根目录,如果Servlet容器不能将虚拟路径转换为文件系统的真实路径,则返回null
      URL getResource(String path)返回映射到某个资源文件的URL对象;参数path必须以正斜线/开始
      InputStream getResourceAsStream(Path path)返回映射到某个资源文件的InputStream输入流对象;参数path传递规则和getResource()方法一致
    • 1.创建一个资源文件(注意文件是在src/main/java中创建)
      在这里插入图片描述
    • 2.编写资源文件内容
      School = qhUniversity
      Address = Beijing
      
    • 3.创建读取资源文件的Servlet(两种方式)
      //方法一
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	response.setContentType("text/html;charset=utf-8");
      	ServletContext context = this.getServletContext();
      	PrintWriter out = response.getWriter();
      	InputStream in = context.getResourceAsStream("/WEB-INF/classes/nyst.properties");
      	Properties pros = new Properties();
      	pros.load(in);
      	out.println("School:" + pros.getProperty("School") + "<br/>");
      	out.println("Address:" + pros.getProperty("Address") + "<br/>");
      }
      
      在这里插入图片描述
      //方法二
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	response.setContentType("text/html;charset=utf-8");
      	ServletContext context = this.getServletContext();
      	PrintWriter out = response.getWriter();
      	String path = context.getRealPath("/WEB-INF/classes/test.properties");
      	FileInputStream in = new FileInputStream(path);
      	Properties pros = new Properties();
      	pros.load(in);
      	out.println(path+"<br/>");
      	out.println("School:" + pros.getProperty("School") + "<br/>");
      	out.println("Address:" + pros.getProperty("Address") + "<br/>");
      }
      
      在这里插入图片描述
    • 语法说明:
      • 1.资源文件后缀名一般是.properties
      • 2.注意文件是在src/main/java中创建,创建后会自动复制到Tomcat相应项目的WEB-INF/classes目录下(资源文件在Tomcat服务器相应项目的WEB-INF/classes目录下才能正常运行)
      • 3.getResourceAsStream(String path)方法获得关联nyst.properties资源文件的输入流对象;其中的path必须以正斜线/开始,表示nyst.properties文件相对于Web应用的相对路径
      • 4.可以通过使用getRealPath(String path)方法获取资源文件的绝对路径
      • 5.注意两者的区别:
        • 一个是InputStream in = context.getResourceAsStream("/WEB-INF/classes/nyst.properties");
        • 一个是String path = context.getRealPath("/WEB-INF/classes/test.properties");FileInputStream in = new FileInputStream(path);

4.HttpServletRequest接口

  • HttpServletRequest接口继承自ServletRequest接口,专门用来封装HTTP请求信息
  • HTTP请求信息分为请求行,请求头,请求消息体3部分

1.获取请求行信息的相关方法

  • 访问Servlet时会在请求信息的请求行中包含:请求方法,请求资源名,请求路径等信息
  • HttpServletRequest接口中定义了一系列用于获取请求行信息的方法
    方法声明功能描述
    String getMethod该方法用于获取HTTP请求信息中的请求方式(例:GET,POST等)
    String getRequestURI()该方法用于获取请求行中的资源名称(即位于URL的主机和端口之后,参数之前的部分)
    String getQueryString()该方法用于获取请求行中的参数(即资源路径?后面的所有内容)
    String getProtocol()该方法用于获取请求行中的协议名和版本(例:HTTP/1.0)
    String getContextPath()该方法用于获取请求URL中属于Web应用的路径,该路径以/开头,表示相对于整个Web站点的根目录,且路径结尾不含/,如果请求URL属于Web站点的根目录,那么返回结果为空字符串("")
    String getServletPath()该方法用于获取Servlet的名称(未配置xml)或Servlet所映射的路径(已配置xml)
    String getRemoteAddr()该方法用于获取请求客户端的IP地址,其格式类似于"192.168.0.1"
    String getRemoteHost()该方法用于获取请求客户端的完整主机名,其格式类似于"pc1.nyst.cn"(如果无法解析出客户端的完整主机名,该方法将会返回客户端的IP地址)
    int getRemotePort()该方法用于获取请求客户端网络连接的端口号
    String getLocalAddr()该方法用于获取Web服务器上接收当前请求网络连接的IP地址
    String getLocalName()该方法用于获取Web服务器上接收当前网络连接IP所对应的主机名
    int getLocalPort()该方法用于获取Web服务器上接收当前网络连接的端口号
    String getServletName()该方法用于获取当前请求所指向的主机名(即HTTP请求消息中Host头字段所对应的主机名部分)
    int getServletPort()该方法用于获取当前请求所连接的服务器端口号(即HTTP请求消息中Host头字段所对应的端口号部分)
    String getScheme)该方法用于获取请求的协议名(例:http,https,ftp)
    StringBuffer getRequestURL()该方法用于获取客户端发出请求时的完整URL(包括协议,服务器名,端口号,资源路径等信息),但不包括后面的参数部分(该方法返回的结果是StringBuffer类型而不是String类型,便于对结果进行修改)
  • RequestLine.jsp
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    	<html>
    	<head>
    	<meta charset="UTF-8">
    	<title>登录请求页面</title>
    	</head>
    	<body>
    		<form action="RequestLineServlet">
    			用户名:<input type="text" name="username"><br/>&nbsp;:<input type="password" name="pwd"><br/>
    			<input type="submit" name="submit" value="提交">
    		</form>
    	</body>
    	</html>
    
  • RequestLineServlet.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		out.println("getMethod: " + "<b>" + request.getMethod() + "</b>" + "<br>");
    		out.println("getRequestRUI: " + "<b>" + request.getRequestURI() + "</b>" + "<br>");
    		out.println("getQueryString: " + "<b>" + request.getQueryString() + "</b>" + "<br>");
    		out.println("getMethod: " + "<b>" + request.getMethod() + "</b>" + "<br>");
    		out.println("getProtocol: " + "<b>" + request.getProtocol() + "</b>" + "<br>");
    		out.println("getContextPath: " + "<b>" + request.getContextPath() + "</b>" + "<br>");
    		out.println("getPathInfo: " + "<b>" + request.getPathInfo() + "</b>" + "<br>");
    		out.println("getPathTranslated: " + "<b>" + request.getPathTranslated() + "</b>" + "<br>");
    		out.println("getServletPath: " + "<b>" + request.getServletPath() + "</b>" + "<br>");
    		out.println("getRemoteAddr: " + "<b>" + request.getRemoteAddr() + "</b>" + "<br>");
    		out.println("getRemoteHost: " + "<b>" + request.getRemoteHost() + "</b>" + "<br>");
    		out.println("getRemotePort: " + "<b>" + request.getRemotePort() + "</b>" + "<br>");
    		out.println("getLocalAddr: " + "<b>" + request.getLocalAddr() + "</b>" + "<br>");
    		out.println("getLocalName: " + "<b>" + request.getLocalName() + "</b>" + "<br>");
    		out.println("getLocalPort: " + "<b>" + request.getLocalPort() + "</b>" + "<br>");
    		out.println("getServerName: " + "<b>" + request.getServerName() + "</b>" + "<br>");
    		out.println("getServerPort: " + "<b>" + request.getServerPort() + "</b>" + "<br>");
    		out.println("getScheme: " + "<b>" + request.getScheme() + "</b>" + "<br>");
    		out.println("getRequestURL: " + "<b>" + request.getRequestURL() + "</b>" + "<br>");
    	}
    
  • RequestLineServlet的xml配置文件
    <servlet>
      	<servlet-name>RequestLineServlet</servlet-name>
      	<servlet-class>servletDemo.RequestLineServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      	<servlet-name>RequestLineServlet</servlet-name>
      	<url-pattern>/RequestLine</url-pattern>
    </servlet-mapping>
    
    在这里插入图片描述
    在这里插入图片描述
  • 语法说明:
    • 1.编写jsp文件,注意jsp文件的action为xml中<url-pattern>元素对应的内容;如果没有配置xml文件,则action为servlet的名称
    • 2.编写servlet文件,注意设置字符编码格式
    • 3.编写web.xml文件,注意<url-pattern>元素是servlet对外访问路径

2.获取请求消息头的相关方法

  • 当请求Servlet时,需要通过请求头向服务器传递附加信息,例:客户端可以接收的数据类型,压缩方式,语言等
  • 为此在HttpServletRequest接口中定义了一系列用于获取HTTP请求头字段的方法
    方法声明功能描述
    String getHeader(String name)该方法用于获取一个指定头字段的值;如果请求消息中没有包含指定的头字段,getHeader()方法返回null;如果请求消息中包含多个指定名称的头字段,getHeader()方法返回其中第一个头字段的值
    Enumeration getHeaders(String name)该方法返回一个Enumeration集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成,在多数情况下一个头字段名在请求消息中只出现一次,但有时候可能会出现多次
    Enumeration getHeaderNames()该方法用于获取一个包含所有请求头字段的Enumeration对象
    int getIntHeader(String name)该方法用于获取指定名称的头字段,并将其值转为int类型。注意如果指定名称的头字段不存在,返回值为-1;如果获取到的头字段的值不能转为int类型,将发生NumberFormatException异常
    long getDateHeader(String name)该方法用于获取指定头字段的值,并将其按GMT时间格式转换为一个代表日期/时间的长整数,这个长整数是自1970年1月1日0点0分0秒算起的以毫秒为单位的时间值
    String getContentType()该方法用于获取Content-Type头字段的值,结果为String类型
    int getContentLength()该方法用于获取Content-Length头字段的值,结果为int类型
    String getCharacterEncoding()该方法用于返回请求消息的实体部分的字符编码,通常是从Content-Type头字段中进行提取
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		request.setCharacterEncoding("utf-8");
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		Enumeration headerNames = request.getHeaderNames();
    		while(headerNames.hasMoreElements()) {
    			String headerName = (String) headerNames.nextElement();
    			out.println(headerName + ": " + "<b>" + request.getHeader(headerName) + "</b><br>");
    		}
    //异常		out.println("getIntHeader: " + request.getIntHeader("host") + "<br/>");
    //异常		out.println("DateHeader: " + request.getDateHeader("host") + "<br/>");
    		out.println("ContentType: " + request.getContentType() + "<br/>");
    		out.println("ContentLength: " + request.getContentLength() + "<br/>");
    		out.println("CharacterEncoding: " + request.getCharacterEncoding() + "<br/>");
    	}
    
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

3.利用Referer请求防止盗链

  • referer: 浏览器向服务器发出的请求,可能是直接在浏览器中输入URL地址,也可能是单击一个网页上的超链接;第一种直接在浏览器地址栏中输入URL,浏览器不会发送referer请求头;第二种单击一个网页上的超链接,浏览器会使用Referer头字段标识发出请求的超链接所在网页的URL
  • 原理: 获取referer头字段的值,检查请求来源,判断其是否是本站链接发送的请求;如果是则允许访问,否则不允许访问
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	// TODO Auto-generated method stub
    	request.setCharacterEncoding("utf-8");
    	response.setContentType("text/html;charset=utf-8");
    	PrintWriter out = response.getWriter();
    	String referer = request.getHeader("referer");
    	String sitePart = "http://" + request.getServerName();
    	if(referer != null && referer.startsWith(sitePart)) {
    		out.println(referer + "<br/>");
    		out.println(sitePart + "<br/>");
    		out.println("正在准备下载");
    	} else {
    		RequestDispatcher rd = request.getRequestDispatcher("download.html");
    		rd.forward(request, response);
    	}
    }
    
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset=utf-8>
    <title>下载页面</title>
    </head>
    <body>
    	<h4>请前往官方页面进行下载</h4>
    	<a href="/MyselfWeb/Down">Download</a>
    </body>
    </html>
    
    在这里插入图片描述
    在这里插入图片描述
  • 语法说明:
    • 第一次请求Servlet时,请求消息中不含Referer请求头,所以Servlet将下载请求转发给了download页面
    • 第二次请求Servlet时,请求消息中包含Referer请求头,并且其值与Servlet位于同一个站点,因此Servlet接受下载请求
    • 注意最好使用jsp,使用html时会出现乱码

4.获取参数

  • 实际开发中经常需要获取用户提交的表单数据(例:用户名,密码等),为了方便获取表单中的请求参数,在HttpServletRequest接口的父类ServletRequest中,定义了一系列获取请求参数的方法
    方法声明功能描述
    String getParameter(String name)该方法用于获取某个指定名称的参数值;如果请求消息中没有包含指定名称的参数,则返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,则返回第一个出现的参数值
    String[] getParameterValues(String name)HTTP请求中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的Form表单生成);如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,需要使用该方法
    Enumeration getParameterNames()该方法用于返回一个包含请求消息中所有参数名的Enumeration对象,在此基础上可以对请求消息中的所有参数进行遍历
    Map getParameterMap()该方法用于将请求消息中的所有参数名和值装入一个Map对象中返回
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    		username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
    		password = new String(password.getBytes("ISO-8859-1"),"UTF-8");
    		out.println("用户名: " + username + "<br/>");
    		out.println("密码: " + password + "<br/>");
    		
    		String[] hobby = request.getParameterValues("hobby");
    		out.println("爱好:" + "<br/>");
    		for(int i=0; i<hobby.length; i++) {
    			out.println(hobby[i] + "&nbsp;");
    		}
    		out.println("<hr/>");
    		
    		Enumeration Parameters = request.getParameterNames();
    		while(Parameters.hasMoreElements()) {
    			String param = (String) Parameters.nextElement();
    			out.println(param + "<br/>");
    		}
    		String csd = Charset.defaultCharset().name();
    		out.println("get方法使用的码表是:" + csd);
    	}
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		request.setCharacterEncoding("utf-8");
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    		
    		out.println("用户名: " + username + "<br/>");
    		out.println("密码: " + password + "<br/>");
    		
    		String[] hobby = request.getParameterValues("hobby");
    		out.println("爱好:" + "<br/>");
    		for(int i=0; i<hobby.length; i++) {
    			out.println(hobby[i] + "&nbsp;");
    		}
    		out.println("<hr/>");
    		
    		Enumeration Parameters = request.getParameterNames();
    		while(Parameters.hasMoreElements()) {
    			String param = (String) Parameters.nextElement();
    			out.println(param + "<br/>");
    		}
    	}
    
    <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    </head>
    <body>
    	<form action="FormTest" method="get">
    		<table>
    			<tr>
    				<td>用户名:</td><td><input type="text" name="username"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;码:</td><td><input type="password" name="password"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;好:</td>
    				<td>
    					<input type="checkbox" name="hobby" value="football">足球
    					<input type="checkbox" name="hobby" value="basketball">篮球
    					<input type="checkbox" name="hobby" value="table tennis">乒乓球
    				</td>
    			</tr>
    			<tr>
    				<td>&nbsp;别:</td>
    				<td>
    					<input type="radio" name="sex" value="boy"><input type="radio" name="sex" value="girl"></td>
    			</tr>
    			<tr>
    				<td></td>
    				<td>
    					<input type="submit" name="submit" value="提交">
    					<input type="reset" name="reset" value="重置">
    				</td>
    			</tr>
    		</table>
    	</form>
    </body>
    </html>
    
    在这里插入图片描述
  • 语法说明:
    • 1.jsp页面中的action可以是< url-pattern>元素的值,也可以是Servlet的名称

5.传递参数

  • Request对象不仅可以获取一系列数据,还可以通过属性传递数据
  • 只有属于同一个请求中的数据才可以通过ServletReques对象传递数据
    方法声明功能描述
    String setAttribute(String name,Object obj)该方法用于将一个属性对象与一个名称关联后存储进ServletRequest对象中;如果ServletRequest对象中已经存在指定名称的属性,该方法将先删除原来的属性再添加新的属性;如果传递给该方法的属性值对象为null,则会删除指定名称的属性(等同于removeAttribute()方法)
    String getAttribute(String name)该方法用于从ServletRequest对象中返回指定名称的属性对象
    String removeAttribute(String name)该方法用于从ServletRequest对象中删除指定名称的属性
    Enumeration getAttributeNames()该方法用于返回一个包含ServletRequest对象中所有属性名的Enumeration对象,在此基础上可以对ServletRequest对象中的所有属性进行遍历处理

6.解决请求参数中文乱码问题

  • 1.乱码产生的原因:
    • 由于HTML设置了浏览器在传递参数时,采用的编码方式是UTF-8,但在解码时采用的是默认的ISO-8859-1,因此会导致乱码的出现
  • 1.POST方式解决乱码:
    • 1.HttpServletRequest接口中,提供了一个setCharacterEncoding()方法,该方法用于设置request对象的解码方式
    • 2.这种解决乱码的方式只对Post方式有效,对Get方式无效
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    </head>
    <body>
    	<form action="FormTest" method="post">
    		<table>
    			<tr>
    				<td>用户名:</td><td><input type="text" name="username"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;码:</td><td><input type="password" name="password"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;好:</td>
    				<td>
    					<input type="checkbox" name="hobby" value="football">足球
    					<input type="checkbox" name="hobby" value="basketball">篮球
    					<input type="checkbox" name="hobby" value="table tennis">乒乓球
    				</td>
    			</tr>
    			<tr>
    				<td>&nbsp;别:</td>
    				<td>
    					<input type="radio" name="sex" value="boy"><input type="radio" name="sex" value="girl"></td>
    			</tr>
    			<tr>
    				<td></td>
    				<td>
    					<input type="submit" name="submit" value="提交">
    					<input type="reset" name="reset" value="重置">
    				</td>
    			</tr>
    		</table>
    	</form>
    </body>
    </html>
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		request.setCharacterEncoding("utf-8");
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    
    		out.println("用户名: " + username + "<br/>");
    		out.println("密码: " + password + "<br/>");
    		
    		String[] hobby = request.getParameterValues("hobby");
    		out.println("爱好:" + "<br/>");
    		for(int i=0; i<hobby.length; i++) {
    			out.println(hobby[i] + "&nbsp;");
    		}
    		out.println("<hr/>");
    		
    		Enumeration Parameters = request.getParameterNames();
    		while(Parameters.hasMoreElements()) {
    			String param = (String) Parameters.nextElement();
    			out.println(param + "<br/>");
    		}
    	}
    
    	/**
    	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
    	 */
    	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		doGet(request,response);
    	}
    
    在这里插入图片描述
    在这里插入图片描述
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    </head>
    <body>
    	<form action="FormTest" method="get">
    		<table>
    			<tr>
    				<td>用户名:</td><td><input type="text" name="username"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;码:</td><td><input type="password" name="password"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;好:</td>
    				<td>
    					<input type="checkbox" name="hobby" value="football">足球
    					<input type="checkbox" name="hobby" value="basketball">篮球
    					<input type="checkbox" name="hobby" value="table tennis">乒乓球
    				</td>
    			</tr>
    			<tr>
    				<td>&nbsp;别:</td>
    				<td>
    					<input type="radio" name="sex" value="boy"><input type="radio" name="sex" value="girl"></td>
    			</tr>
    			<tr>
    				<td></td>
    				<td>
    					<input type="submit" name="submit" value="提交">
    					<input type="reset" name="reset" value="重置">
    				</td>
    			</tr>
    		</table>
    	</form>
    </body>
    </html>
    
    在这里插入图片描述
    在这里插入图片描述
  • 2.GET方式解决乱码
    • 1.先使用错误码表ISO-8859-1将数据重新编码,然后再使用码表UTF-8进行解码(即:UTF-8编码–>ISO-8859-1解码–>ISO-8859-1编码–>UTF-8解码)
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    </head>
    <body>
    	<form action="FormTest" method="get">
    		<table>
    			<tr>
    				<td>用户名:</td><td><input type="text" name="username"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;码:</td><td><input type="password" name="password"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;好:</td>
    				<td>
    					<input type="checkbox" name="hobby" value="football">足球
    					<input type="checkbox" name="hobby" value="basketball">篮球
    					<input type="checkbox" name="hobby" value="table tennis">乒乓球
    				</td>
    			</tr>
    			<tr>
    				<td>&nbsp;别:</td>
    				<td>
    					<input type="radio" name="sex" value="boy"><input type="radio" name="sex" value="girl"></td>
    			</tr>
    			<tr>
    				<td></td>
    				<td>
    					<input type="submit" name="submit" value="提交">
    					<input type="reset" name="reset" value="重置">
    				</td>
    			</tr>
    		</table>
    	</form>
    </body>
    </html>
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		
    		String username = request.getParameter("username");
    		String password = request.getParameter("password");
    		
    		username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
    		password = new String(password.getBytes("ISO-8859-1"),"UTF-8");
    		out.println("用户名: " + username + "<br/>");
    		out.println("密码: " + password + "<br/>");
    		
    		String[] hobby = request.getParameterValues("hobby");
    		out.println("爱好:" + "<br/>");
    		for(int i=0; i<hobby.length; i++) {
    			out.println(hobby[i] + "&nbsp;");
    		}
    		out.println("<hr/>");
    		
    		Enumeration Parameters = request.getParameterNames();
    		while(Parameters.hasMoreElements()) {
    			String param = (String) Parameters.nextElement();
    			out.println(param + "<br/>");
    		}
    	}
    
    在这里插入图片描述

5.HttpServletResponse接口

  • 该接口继承自ServletResponse接口,专门用来封装HTTP响应信息
  • 由于HTTP响应消息分为状态行,响应消息头,消息体三部分,因此在HttpServletResponse接口中定义了向客户端发送响应状态码,响应消息头,响应消息体的方法

1.发送状态码相关的方法

  • 1.setStatus(int status)方法
    • 1.该方法用于设置HTTP响应消息的状态码并生成响应状态行
    • 2.响应状态行中的状态描述信息直接与状态码有关,而HTTP版本由服务器确定,只要通过该方法设置了状态码即可实现状态行的发送
    • 3.正常情况Web服务器会默认产生一个状态码为200的状态行
  • 2.sendError(int sc)方法
    • 1.该方法用于发送表示错误信息的状态码(例:404状态码表示找不到客户端请求的资源)
    • 2.在response对象中,提供了两个重载的sendError(int sc)方法
      public void sendError(int code) throws java.io.IOException
      public void sendError(int code,String ,message) throws java.io.IOException
      

2.发送响应消息头相关的方法

  • 1.当Servlet向客户端发送响应消息时,HTTP协议的响应头字段有很多种
  • 2.HttpServletResponse接口中定义了一系列设置HTTP响应头字段的方法
    方法声明功能描述
    void addHeader(String name,String value)该方法用来设置HTTP协议的响应头字段,其中参数name用于指定响应头字段的名称;参数value用于指定响应头字段的值;该方法可以增加同名的响应头字段
    void setHeader(String name,String value)该方法用来设置HTTP协议的响应头字段,其中参数name用于指定响应头字段的名称;参数value用于指定响应头字段的值;该方法会覆盖同名的响应头字段
    void addIntHeader(String name,String value)该方法用来设置包含整数值响应头字段,避免了使用上面两种方法时,需要将int类型的设置值转换为String类型的麻烦
    void setIntHeader(String name,String value)该方法用来设置包含整数值响应头字段,避免了使用上面两种方法时,需要将int类型的设置值转换为String类型的麻烦
    void setContentLength(int len)该方法用来设置响应消息的实体内容的大小,单位为字节,对于HTTP协议来说,这个方法就是设置Content-Length响应头字段的值
    void setContentType(String type)该方法用来设置Servlet输出内容的MIME类型,对于HTTP协议来说就是设置Content-Type响应头字段的值,(例:如果发送到客户端的内容是jpeg格式的图像数据,就需要将响应头字段的类型设置为image/jpeg;如果响应的内容为文本,该方法还可以设置字符编码(如:text/html;charset=utf-8))
    void setLocale(Locale loc)该方法用来设置响应消息的本地化信息,对于HTTP来说,就是设置Content-Language响应头字段和Content-Type头字段中的字符编码部分; 如果HTTP消息没有设置Content-Type头字段,该方法设置的字符集编码不会出现在HTTP消息的响应头中,如果调用了setCharacterEncoding()或setContentType()方法指定了相应内容的字符集编码,该方法将不再具有指定字符集编码的功能
    void setCharacterEncoding(String charset)该方法用来设置输出内容使用的字符编码,对于HTTP协议来说就是设置Content-Type头字段的字符集编码部分,如果没有设置Content-Type头字段,setCharacterEncoding方法设置的字符集编码不会出现在HTTP消息的响应头中;该方法比setContentType()和setLocale()方法的优先权高,它的设置结果将覆盖其他两种方法所设置的字符码表

3.发送响应消息体相关的方法

  • HTTP响应消息中大量的数据都是通过响应消息体传递,ServletResponse遵循以IO流传递大量数据的设计理念
  • 在发送响应消息体时,定义了两个与输出流相关的方法
  • 1.getOutputStream()方法
    • 该方法所获取的字节输出流对象为ServletOutputStream类型
    • ServletOutputStream是OutputStream的子类,它可以直接输出字节数组中的二进制数据
  • 2.getWriter()方法
    • 该方法获取的字符输出流对象为PrintWriter类型
    • PrintWriter类型的对象可以直接输出字符文本内容,想要输出内容为字符文本的网页文档可以使用该方法
  • 虽然response对象的getOutputStream和getWriter()方法都可以发送响应消息体,但是它们互相排斥,不可同时使用,否则会发生错误
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		String data = "nyst";
    		OutputStream out = response.getOutputStream();
    		out.write(data.getBytes());
    	}
    
    在这里插入图片描述
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		String data = "test";
    		PrintWriter out = response.getWriter();
    		out.println(data);
    	}
    
    在这里插入图片描述
    在这里插入图片描述

4.解决中文输出乱码问题

  • 1.由于计算机中的数据都是以二进制形式存储的,因此当传输文本时就会发生字符和字节之间的转换

  • 2.字符和字节之间的转换是通过查码表完成的,将字符转换为字节的过程称为编码,将字节转换成字符的过程称为解码。 //如果编码和解码使用的码表不一致就会导致乱码问题

    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		String data = "中国";
    		PrintWriter out = response.getWriter();
    		out.println(data);
    	}
    

    在这里插入图片描述

  • 语法说明:

    • 1.如图所示浏览器显示的内容是??,说明发生了乱码问题;此处产生乱码的原因是response对象的字符输出流在编码时,采用的是ISO-8859-1的字符码表;该码表不兼容中文,会将中国编码为63 63(在ISO-8859-1的码表中查不到的字符就会显示63)
    • 2.当浏览器对接收到的数据进行解码时,会采用默认的码表GB2312,将63解码为,因此浏览器将中国两个字符显示为??
      在这里插入图片描述
  • 3.HttpServletResponse接口中,提供了一个setCharacterEncoding()方法,该方法用于设置字符的编码方式

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		//设置字符编码使用的码表为UTF-8
    		response.setCharacterEncoding("utf-8");
    		String data = "中国";
    		PrintWriter out = response.getWriter();
    		out.println(data);
    	}
    

    在这里插入图片描述

  • 语法说明:

    • 1.如图所示浏览器显示的还是乱码,这是由于浏览器解码错误,因为response对象的字符输出流设置的编码方式为UTF-8,而浏览器使用的解码方式是GB2312
      在这里插入图片描述
  • 4.在HttpServletResponse对象中,提供了两种解决乱码的方案

    • 第一种方式
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	// TODO Auto-generated method stub
      	//使用utf-8编码
      	response.setCharacterEncoding("utf-8");
      	//通知浏览器使用utf-8编码
      	response.setHeader("Content-Type", "text/html;charset=utf-8");
      	String data = "中国";
      	PrintWriter out = response.getWriter();
      	out.println(data);
      }
      
      在这里插入图片描述
    • 第二种方式
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	// TODO Auto-generated method stub
      	response.setContentType("text/html;charset=utf-8");
      	String data = "中国";
      	PrintWriter out = response.getWriter();
      	out.println(data);
      }
      
      在这里插入图片描述

5.实现网页定时刷新并跳转

  • 1.HTTP协议中定义了一个Refresh头字段,它可以通知浏览器再指定的时间内自动刷新,并可以添加跳转功能
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setHeader("Refresh", "3");
    		response.getWriter().println(new java.util.Date());		
    	}
    
    在这里插入图片描述
  • 2.网页自动刷新并跳转
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		String data = "中国";
    		PrintWriter out = response.getWriter();
    		out.println(data);
    		response.setHeader("Refresh", "2;URL=http://www.baidu.com");
    	}
    

6.实现请求重定向

  • 某些情况下针对客户端的请求,一个Servlet类可能无法完成全部工作,这时可以使用请求重定向来完成
  • 注意通过请求重定向处理客户端请求会改变浏览器的URL地址
    在这里插入图片描述
  • 请求重定向:指Web服务器接收到客户端的请求后,可能由于某些条件限制,不能访问当前请求URL所指向的Web资源而是指定了一个新的资源路径,让客户端重新发送请求
  • 为了实现请求重定向,在HttpServletResponse接口中,定义了一个sendRedirect()方法,该方法用于生成302响应码和Location响应头,从而通知客户端重新访问Location响应头中指定的URL
  • 语法格式:
    public void sendRedirect(java.lang.String location) throws java.io.IOException
    
  • 语法说明:
    • 参数location可以使用相对URL,Web服务器会自动将相对URL翻译成绝对URL,再生成Location头字段
  • Login.jsp
    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    </head>
    <body>
    	<form action="LoginServlet" method="get">
    		<table>
    			<tr>
    				<td>用户名:</td><td><input type="text" name="username"></td>
    			</tr>
    			<tr>
    				<td>&nbsp;码:</td><td><input type="password" name="password"></td>
    			</tr>
    			<tr>
    				<td></td>
    				<td>
    					<input type="submit" name="submit" value="登录">
    					<input type="reset" name="reset" value="取消">
    				</td>
    			</tr>
    		</table>
    	</form>
    </body>
    </html>
    
  • LoginServlet.java
    public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException {
    	request.setCharacterEncoding("utf-8");
    	response.setContentType("text/html;charset=utf-8");
    	PrintWriter out = response.getWriter();
    	String username = request.getParameter("username");
    	String password = request.getParameter("password");
    	if(username==null) {
    		username="";
    	}
    	if(password==null) {
    		password="";
    	}
    	if(username.equals("wu") && password.equals("123456")) {
    		response.sendRedirect("success.html");
    	}else {
    		response.sendRedirect("Login.jsp");
    	}
    	
    }
    
  • success.html
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录成功</title>
    </head>
    <body>
    	<h3>欢迎</h3>
    </body>
    </html>
    
    在这里插入图片描述
    在这里插入图片描述

6.RequestDispatcher接口

  • 1.当一个Web资源收到客户端的请求后,如果希望服务器通知另一个资源去处理请求,除了使用sendRedirect方法实现请求重定向外,还可以通过RequestDispatcher接口的实例对象实现
  • 2.ServletRequest接口中定义了一个获取RequestDispatcher对象的方法
  • 3.获取到RequestDispatcher对象后,可以使用该对象中的两个方法通知其他Web资源处理当前的Servlet请求
    方法声明功能描述
    RequestDispatcher getRequestDispatcher(String path)该方法返回封装了某个路径所指定资源的RequestDispatcher对象,其中参数path必须以/开头,用于表示当前Web应用的根目录
    forward(ServletRequest request,ServletResponse response)该方法用于将请求从一个Servlet传递给另一个Web资源。在Servlet中,可以对请求做一个初步处理,然后通过调用这个方法,将请求传递给其他资源进行响应;注意:该方法必须在响应提交给客户端之前被调用,否则将抛出IIIegalStateException异常
    include(ServletRequest request,ServletResponse response)该方法用于将其他的资源作为当前响应内容包含进来
  • 4.forword方法可以实现请求转发,include方法可以实现请求包含

1.请求转发

  • 1.Servlet中如果当前Web资源不想处理请求时,可以通过forward()方法将当前请求传递给其他的Web资源进行处理,这种方式称为请求转发
  • 2.原理:当浏览器客户端访问Servlet1时,可以通过forward()方法将请求转发给其他Web资源,其他Web资源处理完请求后,直接将响应结果返回到客户端
  • 3.注意:forward转发后的Servlet2页面的地址栏仍然是浏览器对Servlet1的请求路径,但是浏览器中内容是Servlet2页面,这是因为请求转发是发生在服务器内部的行为,从Servlet1到到Servlet2属于一次请求,在一次请求中可以使用request属性进行数据共享
    在这里插入图片描述
  • RequestForwardServlet.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		request.setAttribute("school", "河南大学");
    		PrintWriter out = response.getWriter();
    		out.println("测试");
    		RequestDispatcher rd = request.getRequestDispatcher("/RequestForward");
    		rd.forward(request, response);
    	}
    
  • RequestForward.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		String school = (String) request.getAttribute("school");
    		out.println(school + "欢迎登录<br/>Forward响应成功");
    	}
    
    在这里插入图片描述
  • 语法说明:
    • 如图所示显示的内容是RequestForward页面,URL路径仍为RequestForwardServlet

2.请求包含

  • 1.请求包含:指使用include()方法将Servlet请求转发给其他Web资源进行处理
  • 2.与请求转发不同的是:在请求包含返回的响应消息中,既包含了当前Servlet的响应消息也包含了其他Web资源所作出的响应信息
  • 3.原理:当客户端访问Servlet1时,Servlet1通过调用include()方法将其他Web资源包含进来,当请求处理完毕后回送给客户端的响应结果既包含当前Servlet的响应结果也包含其他Web资源的响应结果
    在这里插入图片描述
  • IncludeServlet.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		request.setAttribute("school", "东南大学");
    		PrintWriter out = response.getWriter();
    		out.println("清华大学");
    		RequestDispatcher rd = request.getRequestDispatcher("/Include");
    		rd.include(request, response);
    	}
    
  • Include.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		PrintWriter out = response.getWriter();
    		String school  = (String) request.getAttribute("school");
    		out.println(school + "欢迎登录");
    	}
    
    在这里插入图片描述
  • IncludeServlet.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		response.setContentType("text/html;charset=utf-8");
    		request.setAttribute("school", "东南大学");
    		PrintWriter out = response.getWriter();
    		out.println("清华大学");
    		RequestDispatcher rd = request.getRequestDispatcher("/Include");
    		rd.include(request, response);
    	}
    
  • Include.java
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		PrintWriter out = response.getWriter();
    		String school  = (String) request.getAttribute("school");
    		out.println(school + "欢迎登录");
    	}
    
    在这里插入图片描述
  • 语法说明:
    • 1.如图所示第一种情况会出现乱码,说明在Include中设置响应字符编码没有起作用
    • 2.这次因为浏览器请求IncludeServlet时,用于封装响应消息的HttpServletResponse对象已经建立,该对象在编码时采用的是默认的ISO-8859-1,所以当客户端接收到数据时,Web服务器会继续保持调用HttpServletResponse对象中的信息,并采用GB2312解码从而导致乱码
    • 3.使用include()方法实现请求包含后,浏览器显示的URL地址是不会发生变化的

5.Servlet的文件配置

  • web.xml文件中< servlet-mapping>元素用于映射一个Servlet的对外访问路径,该路径也称虚拟路径
  • 创建好的Servlet只有映射成虚拟路径,客户端才能对其进行访问
  • 1.Servlet多重映射
    • 指的是同一个Servlet可以被映射成多个虚拟路径(即:客户端可以通过多个虚拟路径实现对同一个Servlet的访问)
  • 2.Servlet多重映射的实现方式
    • ServletDemo1.java
      package servletDemo;
      
      import java.io.IOException;
      import java.io.PrintWriter;
      
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      /**
       * Servlet implementation class ServletDemo1
       */
      @WebServlet("/ServletDemo1")
      public class ServletDemo1 extends HttpServlet {
      	private static final long serialVersionUID = 1L;
             
          /**
           * @see HttpServlet#HttpServlet()
           */
          public ServletDemo1() {
              super();
              // TODO Auto-generated constructor stub
          }
      
      	/**
      	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
      	 */
      	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		// TODO Auto-generated method stub
      		PrintWriter out = response.getWriter();
      		out.println("<html><body><h3>Welcome To The First Servlet!</h3></body></html>");
      		out.flush();
      	}
      }
      
    • 1.配置多个< servlet-mapping>元素
       <servlet>
        	<servlet-name>Demo1</servlet-name>
       	<servlet-class>servletDemo.ServletDemo1</servlet-class>
        </servlet>
       <servlet-mapping>
        	<servlet-name>Demo1</servlet-name>
       	<url-pattern>/test1</url-pattern>
       </servlet-mapping>
        <servlet-mapping>
       	<servlet-name>Demo1</servlet-name>
        	<url-pattern>/test2</url-pattern>
       </servlet-mapping>
      
    • 2.< servlet-mapping>元素下配置多个< url-pattern>子元素
       <servlet>
        	<servlet-name>Demo1</servlet-name>
        	<servlet-class>servletDemo.ServletDemo1</servlet-class>
        </servlet>
        <servlet-mapping>
        	<servlet-name>Demo1</servlet-name>
        	<url-pattern>/test1</url-pattern>
        	<url-pattern>/test2</url-pattern>
       </servlet-mapping>
      
      在这里插入图片描述
      在这里插入图片描述
  • 3.Servlet映射路径中的通配符
    • 1.格式为 *.扩展名(例: * .do表示以.do结尾的URL请求路径可以访问该Serlvet;*表示任何URL路径都可以访问该Servlet)
    • 2.格式为/* (例:/abc/ * 表示以abc开始的URL请求路径都可以访问该Servlet)
  • 4.注意
    • 1.两种通配符的格式不能混合使用(例:/abc/*do是不合法的映射路径)
    • 2.客户端访问Servlet时,如果请求的URL地址能够匹配多个虚拟路径,Tomcat将采取最具体匹配原则查找与请求URL最接近的虚拟映射路径
  • 5.最具体匹配原则
      <servlet>
      	<servlet-name>test1</servlet-name>
      	<servlet-class>test.ServletTest1</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>test1</servlet-name>
      	<url-pattern>/test/*</url-pattern>
      </servlet-mapping>
      <servlet>
      	<servlet-name>test2</servlet-name>
      	<servlet-class>test.ServletTest2</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>test2</servlet-name>
      	<url-pattern>/*</url-pattern>
      </servlet-mapping>
       <servlet>
      	<servlet-name>test3</servlet-name>
      	<servlet-class>test.ServletTest3</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>test3</servlet-name>
      	<url-pattern>/test</url-pattern>
      </servlet-mapping>
        <servlet>
      	<servlet-name>test4</servlet-name>
      	<servlet-class>test.ServletTest4</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>test4</servlet-name>
      	<url-pattern>*.do</url-pattern>
     </servlet-mapping>
    
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 说明:
    • 1./test/*:表示以/test/开头的请求URL可以匹配到该Servlet
    • 2./*:表示所有请求URL都可以匹配到该路径
    • 3./test:表示请求URL为/test匹配到该Servlet
    • 4.*.do:表示以.do结尾的请求URL可以匹配到该Servlet
    • 注意优先级:1和3的优先级比2高,2的优先级比4高;即:当有以/开始的具体URL时会优先选择该Servlet,如果都没有则会匹配/*对应的Servlet;如果想使用*.do则需要将/*删除
    • 匹配优先级与配置在xml的顺序无关,只与上述说明有关
  • 6.缺省Servlet
    • 如果某个Servlet的映射路径仅仅是一个正斜线/,那么这个Servlet就是当前Web应用的缺省Servlet
    • Servlet’服务器在接收到访问请求时,如果在web.xml文件中找不到匹配的< servlet-mapping>元素的URL,就会将访问请求交给缺省Servlet处理(即:缺省Servlet用户处理其他Servlet都不处理的访问请求)
        <servlet>
        	<servlet-name>ServletTest5</servlet-name>
        	<servlet-class>test.ServletTest5</servlet-class>
        </servlet>
        <servlet-mapping>
        	<servlet-name>ServletTest5</servlet-name>
        	<url-pattern>/</url-pattern>
        </servlet-mapping>
      
      在这里插入图片描述
    • Tomca安装目录下的web.xml文件也配置了一个缺省Servlet
    • org.apache.catalina.servlets.DefaultServlet被设置为缺省的Servlet
    • 它对Tomcat服务器上所有Web应用都起作用
    • 当Tomcat服务器中的某个Web应用没有缺省Servlet时,都会将DefaultServlet作为默认缺省的Servlet
    • 当客户端访问Tomcat服务器中的某个静态HTML时,DefaultServlet会判断HTML是否存在,如果存在,就会将数据以流的形式回送给客户端,否则会报告404错误
      在这里插入图片描述

1.Servlet别名形式的URL调用

  • 在Tomcat服务器下,Servlet应该放到应用程序的WEB-INF\classes目录下,而调用Servlet的URL是http://主机名/应用程序文件夹名/Servlet名。同时大多数Web服务器还允许定义Servlet的别名,因此Servlet也可能以使用别名形式的URL调用
  • 1.部署Servlet
    • 将ServletDemo1.java编译成ServletDemo1.class文件,然后将应用程序文件夹下的WEB-INF文件夹直接复制到webapps中的新建文件夹chap01中
    • 修改前目录
      在这里插入图片描述
    • 修改后目录在这里插入图片描述
  • 2.修改web.xml文件
    • 修改前
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>MyselfWeb</display-name>
      <welcome-file-list>
         <welcome-file>index.html</welcome-file>
         <welcome-file>index.htm</welcome-file>
         <welcome-file>index.jsp</welcome-file>
         <welcome-file>default.html</welcome-file>
         <welcome-file>default.htm</welcome-file>
         <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
      </web-app>
      
    • 修改后
      <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>MyselfWeb</display-name>
      <welcome-file-list>
      	<welcome-file>index.html</welcome-file>
          <welcome-file>index.htm</welcome-file>
          <welcome-file>index.jsp</welcome-file>
          <welcome-file>default.html</welcome-file>
          <welcome-file>default.htm</welcome-file>
          <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
      <!-- JSPC servlet mapping start -->
      <!-- 完成对Servlet的名称(name)和Servlet类(class)之间的匹配 -->
      <!-- 本例将名称为Demo1的Servlet匹配到servletDemo包中的ServletDemo1类-->
      <servlet>
          <servlet-name>Demo1</servlet-name>
          <display-name>Demo1</display-name>
          <description>The First Servlet</description>
          <servlet-class>servletDemo.ServletDemo1</servlet-class>
      </servlet>
      <!-- 完成了Servlet的映射,即如果在浏览器地址栏中出现了/Demo1的内容,则映射成名称为Demo1的Servlet -->
      <servlet-mapping>
          <servlet-name>Demo1</servlet-name>
          <url-pattern>/Demo1</url-pattern>
      </servlet-mapping> 
      <!-- JSPC servlet mapping end -->
      </web-app>
      
    • 修改前路径
      在这里插入图片描述
    • 修改后路径在这里插入图片描述

6.会话及其会话技术

  • 1.Web开发中,服务器跟踪用户信息的技术称为会话技术
  • 2.Web会话过程:它指一个客户端与Web服务器之间连续发生的一系列请求和响应过程
  • 3.HttpServletRequestServletContext都可以对数据进行保存,两者的区别:
    • 1.HtttpServletRequest: 客户端请求Web服务器时,针对每次HTTP请求,Web服务器都会创建一个HttpServletRequest对象,该对象只能保存本次请求所传递的数据
    • 2.ServletContext: 同一个Web应用共享同一个Servlet对象,所以同一个Web应用下的所有Servlet都能读取ServletContext保存的数据

1.Cookie对象

  • 1.Cookie是一种会话技术,它用于将会话过程中的数据保存到用户的浏览器中,从而使浏览器和服务器可以更好的进行数据交互
  • 2.Web应用中,当通过浏览器访问Web服务器时,服务器会给客户端发送一些信息,这些信息都保存在Cookie中
  • 3.当浏览器再次访问服务器时,都会在请求头中将Cookie发送给服务器,方便服务器对浏览器作出正确的响应
  • 4.服务器向客户端发送Cookie时,会在HTTP响应头字段增加Set-Cookie响应头字段
    在这里插入图片描述
  • 5.流程说明:
    • 1.当用户第一次访问服务器时,服务器会在响应消息中增加Set-Cookie头字段,将用户信息以Cookie的形式发送给浏览器
    • 2.一旦用户浏览器接受了服务器发送的Cookie信息,就会将他保存在浏览器的缓存区
    • 3.当浏览器后续访问该服务器时,都会在请求消息中将用户信息以Cookie的形式发送给Web服务器,从而使服务器分辨出当前请求是哪个用户发出
  • 6.Set-Cookie头字段中设置Cookie遵循一定的语法格式
    Set-Cookie:user=nyst; path=/;
    
  • 语法说明:
    • 1.user:表示Cookie的名称;nyst:表示Cookie的值;path表示Cookie的路径属性
    • 2.Cookie必须以键值对的形式存在,其属性可以有多个,但这些属性必须用分号和空格分隔
  • 7.Cookie API
    • Servlet API中提供了javax.servlet.http.Cookie类,该类包含生成Cookie信息和提取Cookie’信息各个属性的方法
      方法声明功能描述
      public Cookie(String name,String value)该方法为构造方法,参数name用于指定Cookie名称,Value用于指定Cookie的值;注意:Cookie一旦创建,名称name就不能修改,Cookie的值可以为任何值并且创建后可以被修改
      String getName()该方法用于返回Cookie的名称
      void setValue(String newValue)该方法用于为Cookie设置一个新的值
      String getValue()该方法用于返回Cookie的值
      void setMaxAge(int expiry)该方法用于设置Cookie在浏览器客户端上保持有效的秒数;如果设置的值为正整数,浏览器会将Cookie信息保存在本地硬盘中,从当前时间开始,在没有超过指定的秒数之前,这个Cookie都保持有效,并且同一台计算机上运行的浏览器都可以使用这个Cookie信息;如果设置的值为负整数,浏览器会将Cookie信息保存在缓存中,当浏览器关闭时,Cookie信息会被删除;如果设置值为0,则表示通知浏览器立即删除这个Cookie信息;默认情况该属性的值是-1
      int getMaxAge()该方法用于返回Cookie在浏览器客户端上保持有效的秒数
      void setPath(String url)该方法用于设置该Cookie项的有效目录路径;如果创建的某个Cookie对象没有设置Path属性,那么该Cookie只对当前访问路径所属的目录及其子目录有效;如果想让某个Cookie项对站点的所有目录下的访问路径都有效,应调用Cookie对象的setPath()方法将其Path属性设置为/
      String getPath()该方法用于返回该Cookie项的有效目录路径
      void setDomain(String pattern)该方法用于设置该Cookie项的有效域;domain属性用来指定浏览器访问的域(例:百度的域为baidu.com);当设置domain属性时,必须以.开头(例:domain=.baidu.com);默认情况domain属性的值为当前主机名,浏览器再访问当前主机下的资源时都会将Cookie信息回送给服务器;domain属性的值不区分大小写
      String getDomain()该方法用于返回该Cookie项的有效域
      void setVersion(int v)该方法用于设置该Cooki项采用的协议版本
      int getVersion()该方法用于返回该Cooki项采用的协议版本
      void setComment(String purpose)该方法用于设置该Cookie项的注解部分
      String getComment()该方法用于返回该Cookie项的注解部分
      void setSecure(boolean flag)该方法用于设置该Cookie项是否值能使用安全的协议传送
      String getSecure(()该方法用于返回该Cookie项是否只能使用安全的协议传送
  • 8.显示用户上次访问时间
    • LastAccessServlet.java
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      	// TODO Auto-generated method stub
      	response.setContentType("text/html;charset=utf-8");
      	PrintWriter out =response.getWriter();
      	String lastAccessServlet = null;	
      	Cookie[] cookies = request.getCookies();
      	for(int i=0; cookies!=null&&i<cookies.length; i++) {
      		if("lastAccess".equals(cookies[i].getName())) {
      			lastAccessServlet = cookies[i].getValue();
      			break;
      		}
      	}
      
      	if(lastAccessServlet == null) {
      		out.println("您是首次访问本站!");
      	} else {
      		out.println("您上次访问的时间是: " + lastAccessServlet);
      	}
      	
      	String currentTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date());
      	Cookie cookie = new Cookie("lastAccess",currentTime);
      	response.addCookie(cookie);
      }
      
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    • 语法说明:
      • 1.如图所示:开始显示的是图一,刷新后会显示上次访问的时间,每次刷新,时间都会改变
      • 2.关闭浏览器后再打开浏览器,再次访问该Servlet显示的是图三而没有显示上次访问时间,这是因为在默认情况下,Cookie对象的Max-Age属性的值是-1,即:浏览器关闭时,删除该Cookie对象
      • 3.可以通过setMaxAge()方法设置有效时间,只要Cookie设置的有效时间没有结束,用户就可以一直访问该Cookie保存的信息

2.Session对象

  • 1.Cookie技术可以将用户的信息保存在各自的浏览器中,并且可以在多次请求下实现数据的共享
  • 2.Session是一种将会话数据保存到服务器端的技术
  • 3.原理: 当浏览器访问Web服务器时,Servlet容器就会为客户端创建一个Session对象和ID属性;当客户端后续访问服务器时,只要将ID标识号传递给服务器,服务器就能判断出该请求是哪个客户端发送的,从而选择与之对应的Session对象为其服务
    在这里插入图片描述
    • 1.如图所示:用户甲和用户乙都调用buyServlet将商品添加到购物车中,调用payServlet进行商品结算
    • 2.当用户甲访问购物网站时,服务器为甲创建了一个Session信息(相当于购物车),当甲将Nokia手机添加到购物车网站时,Nokia手机的信息便存放到了Session对象中
    • 3.同时服务器将Session对象的ID属性以Cookie(Set-Cookie:JSESSIONID=111)的形式返回给浏览器
    • 4.当甲完成购物进行结账时,需要向服务器发送结账请求,这时浏览器自动在请求头中将Cookie信息回送给服务器,服务器根据ID属性找到为用户甲所创建的Session对象,并将Session对象中所存放的Nokia手机信息取出来进行结算,用户乙同理
  • 4.HttpSession API
    • 1.HttpServletRequest定义了用于获取Session对象的getSession方法
    • 2.该方法有两种重载方式
      //根据传递的参数判断是否创建新的HttpSession对象,如果参数为true,则在相关的HttpSession对象不存在时创建并返回新的HttpSession对象,否则不创建新的HttpSession对象,返回null
      public HttpSession getSession()
      //在相关的HttpSession对象不存在时总是创建新的HttpSession对象
      public HttpSession getSession()
      //注意:getSession()方法可能会产生发送会话标识号的Cookie头字段,因此必须在发送任何响应内容之前调用getSession()方法
      
    • 3.HttpSession接口中定义了操作会话数据的常用方法
      方法声明功能描述
      String getId()该方法用于返回与当前HttpSession对象关联的会话标识号
      long getCreationTime()该方法用于返回Session创建的时间,这个时间是创建Session的时间与1970年1月1日00:00:00之间时间差的毫秒表示形式
      long getLastAccessedTime()该方法用于返回客户端最后一次发送与Session相关请求的时间,这个时间是发送请求的时间与1970年1月1日00:00:00之间时间差的毫秒表示形式
      void setMaxInactiveInterval(int interval)该方法用于设置当前HttpSession对象可空闲的以秒为单位的最长时间(即:修改当前会话的默认超时间隔)
      boolean isNew()该方法用于判断当前HttpSeesion对象是否是新创建的
      void invalidate()该方法用于强制使Session对象无效
      ServletContext getServletContext()该方法用于返回当前HttpSession对象所属于的Web应用程序对象(即:代表当前Web应用程序的ServletContext对象)
      void setAttribute()该方法用于将一个对象与一个名称关联后存储到当前的HttpSession对象中
      String getAttribute()该方法用于从当前HttpSession对象中返回指定名称的属性对象
      void removeAttribute(String name)该方法用于从当前HttpSession对象中删除指定名称的属性
  • 5.Session超时管理
    • 1.客户端第一次访问某个能开启会话功能的资源时,Web服务器就会创建一个与该客户端对应的HttpSession对象
    • 2.HTTP协议中,Web服务器无法判断当前的客户端浏览器是否还会继续访问,也无法检测客户端浏览器是否关闭(即:即使客户端离开或关闭了浏览器,Web服务器还要保留与之对应的HttpSession)
    • 3.随着时间的推移,这些不再使用的HttpSession对象会在Web服务器中积累的越来越多,从而使Web服务器内存耗尽;为了解决这种问题,Web服务器采用了超时限制的办法来判断客户端是否还在继续访问
    • 4.超时限制:指在一定的时间内,如果某个客户端一直没有请求访问,则Web服务器就会认为该客户端的请求已经结束,并且将该客户端会话所对应的HttpSession对象变成垃圾对象,等待垃圾收集器将其从内存中彻底清除;反之如果浏览器超时后,再次向服务器发出请求访问,那么Web服务器则会创建一个新的HttpSession对象,并为其分配一个新的ID属性
    • 5.会话的有效时间可以在web.xml文件中设置,其默认值由Servlet容器定义,在Tomcat安装目录/conf/web.xml文件中可以找到该配置信息
      在这里插入图片描述
    • 语法说明:
      • 1.设置的时间值是以分钟为单位(即:Tomcat服务器的默认会话超时间隔为30分钟)
      • 2.如果将< session-timeout>元素中的时间值设置成0或一个负数,则表示会话永不超时
      • 3.Tomcat安装目录/conf/web.xml文件对站点内的所有Web应用程序都起作用
      • 4.如果想单独设置某个Web应用程序的会话超时间隔,则需在自己应用的web.xml文件中进行设置,内容同上
      • 5.如果想使Session失效,除了可以等待会话时间超时外,还可以通过invalidate()方法强制使会话失效

3.实现购物车

4.实现用户登录

7.Servlet应用

1.Servlet读取HTML表单数据

  • 2.Servlet中调用HttpServletRequest的getParameter方法,在调用参数中提供表单元素的名字即可读取数据
  • 3.getParameter(String name)方法的返回值是一个字符串,是参数中指定的变量名字第一次出现所对应的值
    • 1.如果指定的表单变量存在,但是没有值,getParameter就会返回空字符串
    • 2.如果指定的表单变量不存在,则返回null
  • 4.如果表单变量可能对应多个值,可以用getParameterValues方法,它能够返回一个字符串数组
  • 5.HttpServletNames方法可以获得完整的表单变量名字列表,getParameterNames返回的是一个Enumeration,其中的每一项都可以转换为调用getParameter的字符串

1.Servlet读取指定HTML表单数据

  • register.html
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    </head>
    <body>
    <table border=1 align=center>
    <form action="Register" name="register" method="post" onsubmit="return check()">
    	<tr>
    		<th colspan="2">用户注册</th>
    	</tr>
    	<tr>
    		<td>用户名:</td>
    		<td><input type="text" name="username" size=11></td>
    	</tr>
    	<tr>
    		<td>密码:</td>
    		<td><input type="password" name="pwd1" size=18 ></td>
    	</tr>
    	<tr>
    		<td>确认密码:</td>
    		<td><input type="password" name="pwd2" size=18 ></td>
    	</tr>
    	<tr>
    		<td>电子邮箱:</td>
    		<td><input type="email" name="email" size=18 ></td>
    	</tr>
    	<tr>
    		<td>性别:</td>
    		<td>
    			<input type="radio" name="sex" value="boy"><input type="radio" name="sex" value="girl"></td>
    	</tr>
    	<tr>
    		<td>教育程度:</td>
    		<td>
    			<select name="edu">
    				<option value="c">本科</option>
    				<option value="h">高中</option>
    				<option value="s">初中</option>
    			</select>
    		</td>
    	</tr>
    	<tr>
    		<td><input type="submit" name="submit" value="提交"></td>
    		<td><input type="reset" name="reset" value="重置" ></td>
    	</tr>
    </form>
    </body>
    </html>
    
    • RegisterServlet.java
    package servletDemo;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.util.Enumeration;
    
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class RegisterServlet extends HttpServlet{
    	
    
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 775147027821523486L;
    
    	public RegisterServlet() {
    		
    	}
    	
    	public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException {
    		request.setCharacterEncoding("UTF-8");
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    		String pwd1 = (String)request.getParameter("pwd1");
    		String pwd2 = (String)request.getParameter("pwd2");
    		if(pwd1.equals(pwd2)) {
    			out.println("<html>");
    			out.println("<head><title>Read All Parameter</title></head>");
    			out.println("<body>");
    			out.println("<h3 align=center>All Patameter From Request</h3>");
    			out.println("<table border=1 align=center>");
    			out.println("<tr><th>Parameter Name</th><th>Patameter Value</th></tr>");
    			Enumeration enumNames = request.getParameterNames();
    			while(enumNames.hasMoreElements()) {
    				int i = 0;
    				String strParam = (String) enumNames.nextElement();
    				String[] strValue = request.getParameterValues(strParam);
    				out.println("<tr>");
    				out.println("<td>"+strParam+"</td>");
    				out.println("<td>"+strValue[i++]+"</td>");
    				out.println("<tr>");
    			}
    			out.println("</table>");
    			out.println("</body>");
    			out.println("</html>");
    		}else {
    			out.println("<h3>两次输入的密码不一致,请重新输入</h3>");
    			out.println("<h3>5秒后跳转到注册页面,如果失败请点击以下链接手动进入</h3>");
    			out.println("<a href=register.html>注册页面</a>");
    			response.setHeader("refresh", "5,register.html");
    		}
    	}
    }
    
    • web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
      <display-name>MyselfWeb</display-name>
      <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
      </welcome-file-list>
      <servlet>
      	<servlet-name>Register</servlet-name>
      	<servlet-class>servletDemo.RegisterServlet</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>Register</servlet-name>
      	<url-pattern>/Register</url-pattern>
      </servlet-mapping>
    </web-app>
    
  • 结果
    在这里插入图片描述
    在这里插入图片描述
    正确结果
    在这里插入图片描述
    错误结果
    在这里插入图片描述

8.Filter过滤器

1.Filter定义

  • 1.Filter过滤器其实就是一个实现了javax.servlet.Filter接口的类,用于对request,response对象进行修改
  • 2.Filter过滤器功能是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前后实现一些特殊功能
    在这里插入图片描述
  • 说明:
    • 1.浏览器访问服务器中的目标资源时会被Filter拦截,在Filter中进行预处理操作然后再将请求转发给目标资源

    • 2.服务器接收到这个请求后会对其进行响应,在服务器处理响应过程中,也需要先将响应结果发送给过滤器,在过滤器中对响应结果进行处理后,才会发送给客户端

      方法声明功能描述
      init(FilterConfig filterConfig)该方法用来初始化过滤器,可以完成与构造方法类似的初始化功能; 如果初始化代码中要使用FilterConfig对象,那么这些初始化代码只能在Filter的init()方法中编写,而不能在构造方法中编写
      doFilter(ServletRequest request,ServletResponse response,FilterChain chain)该方法有多个参数;request和response参数为Web服务器或Filter链中的上一个Filter传递过来的请求和响应对象;chain参数代表当前Filter链对象,在当前Filter对象中的doFilter()方法内部需调用FilterChain对象的doFilter()方法,才能把请求交付给Filter链中的下一个Filter或者目标程序去处理
      destroy()该方法在Web服务器卸载Filter对象之前被调用,用于释放被Filter对象打开的资源
  • 3.以上3个方法是Filter的生命周期方法:
    • 1.init()方法在Web应用程序加载的时候调用
    • 2.destroy()方法在Web应用程序卸载的时候调用,这两个方法都只会被调用一次
    • 3.doFilter()方法只要客户端请求就会被调用,并且Filter所有的工作集中在doFilter()方法中

2.Filter映射

  • 1.filter拦截的资源需要在web.xml文件中进行配置,这些配置信息就是Filter映射
  • 2.Filter映射方式分为两种
    • 1.使用通配符*拦截用户的所有请求
      <filter>
        	<filter-name>FirstFilter</filter-name>
       	<filter-class>filter.FirstFilter</filter-class>
      </filter>
      <filter-mapping>
        	<filter-name>FirstFilter</filter-name>
        	<url-pattern>/*</url-pattern>
      </filter-mapping>
      
    • 语法说明:
      • 1.<filter>根元素用于注册一个Filter
      • 2.<filter-name>子元素用于设置Filter名称
      • 3.<filter-class>子元素用于设置Filter类的完整名称
      • 4.<filter-mapping>根元素用于设置一个过滤器所拦截的资源
      • 5.<filter-name>子元素必须与<filter><filter-name>子元素相同
      • 6.<url-pattern>子元素用于匹配用户请求的URL
        • 1.匹配原则类似servlet映射
        • 2.区别是Filter过滤器的<url-pattern>相当于servlet的<url-pattern>设置
          <servlet>
          	<servlet-name>FilterServlet</servlet-name>
          	<servlet-class>servletDemo.FilterServlet</servlet-class>
          </servlet>
          <servlet-mapping>
          	<servlet-name>FilterServlet</servlet-name>
          	<url-pattern>/FilterTest/adv</url-pattern>
          </servlet-mapping>
          <filter>
          	<filter-name>FirstFilter</filter-name>
          	<filter-class>filter.FirstFilter</filter-class>
          </filter>
          	<filter-mapping>
          	<filter-name>FirstFilter</filter-name>
          	<url-pattern>/FilterTest/*</url-pattern>
          </filter-mapping>
          
        • FilterServlet
          protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          // TODO Auto-generated method stub
          PrintWriter out =  response.getWriter();
          out.println("Hello FilterServlet");
          }
          
        • FirstFilter
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          // TODO Auto-generated method stub
          // place your code here
          PrintWriter out = response.getWriter();
          out.println("Filter Success");
          // pass the request along the filter chain
          //chain.doFilter(request, response);
          }
          
          在这里插入图片描述
    • 2.拦截不同方式的访问请求
      • 1.web.xml文件中,一个< filter-mapping>元素用于配置一个Filter所负责拦截的资源
      • 2.< filter-mapping>元素中有一个特殊的子元素< dispatcher>,该元素用于指定过滤器所拦截的资源被Servlet容器调用的方式,< dispatcher>元素的值共有4个:
        • 1.REQUEST:
          • 当用户直接请求访问页面时,Web容器会调用该过滤器
          • 如果目标资源是通过RequestDipatcher的include()或forward()方法访问的,该过滤器将不会调用
        • 2.INCLUDE:
          • 如果目标资源是通过RequestDispathcer的include()方法访问的,那么该过滤器将被调用;除此之外,该过滤器不会调用
        • 3.FORWARD:
          • 如果目标资源是通过RequestDispathcer的forward()方法访问的,那么该过滤器将被调用;除此之外,该过滤器不会调用
        • 4.ERROR:
          • 如果目标资源是通过声明式异常处理机制调用的,那么该过滤器将被调用;除此之外,该过滤器不会调用
        <servlet>
          	<servlet-name>FilterServlet</servlet-name>
         	<servlet-class>servletDemo.FilterServlet</servlet-class>
        </servlet>
        <servlet-mapping>
          	<servlet-name>FilterServlet</servlet-name>
        	<url-pattern>/FilterTest/adv</url-pattern>
        </servlet-mapping>
        <filter>
          	<filter-name>FirstFilter</filter-name>
        	<filter-class>filter.FirstFilter</filter-class>
        </filter>
        <filter-mapping>
          	<filter-name>FirstFilter</filter-name>
          	<url-pattern>/FilterTest/*</url-pattern>
        <!--<dispatcher>REQUEST</dispatcher>-->
          	<dispatcher>INCLUDE</dispatcher>
        </filter-mapping>
        
        在这里插入图片描述
        在这里插入图片描述
      • ForwardServlet
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        		// TODO Auto-generated method stub
        		RequestDispatcher dispatcher = request.getRequestDispatcher("/first.jsp");
        		dispatcher.forward(request, response);
        	}
        
      • first.jsp
        <body>
        	<p>Forward Test</p>
        	<p>this is first</p>
        </body>
        
         <servlet>
          	<servlet-name>Forward</servlet-name>
          	<servlet-class>servletDemo.ForwardServlet</servlet-class>
        </servlet>
        <servlet-mapping>
          	<servlet-name>Forward</servlet-name>
          	<url-pattern>/Forward</url-pattern>
        </servlet-mapping>
        <filter>
          	<filter-name>FirstFilter</filter-name>
          	<filter-class>filter.FirstFilter</filter-class>
        </filter>
        <filter-mapping>
          	<filter-name>FirstFilter</filter-name>
          	<url-pattern>/first.jsp</url-pattern>
         <!-- 	<dispatcher>FORWARD</dispatcher>-->
        </filter-mapping>
        
        在这里插入图片描述
        在这里插入图片描述

3.Filter链

  • 1.一个Web应用程序中可以注册多个Filter程序,每个Filter程序都可以针对一个URL进行拦截
  • 2.如果多个Filter程序都对同一个URL进行拦截,那么这些FIlter就会组成一个Filter链(也叫过滤器链)
  • 3.Filter链用FilterChain对象来表示,FilterChain对象中有一个doFilter()方法,该方法就是让Filter链上的当前过滤器放行,使请求进入下一个FIlter或Web应用,否则只会显示该过滤器的内容而无法使请求跳转到下一个页面
    在这里插入图片描述
  • 语法说明:
    • 1.浏览器访问Web服务器中的资源时,需要经过两个过滤器Filter1和Filter2
    • 2.首先Filter1会对请求进行拦截,在Filter1过滤器的doFilter()方法中处理好请求后,通过调用FIlter1的doFilter()方法中的chain.doFilter()方法将请求传递给FIlter2,Filter2将用户请求处理后同样调用chain.doFilter()方法,最终将请求发送给目标资源
    • 3.Web服务器对该请求做出响应时也会被过滤器拦截,这个拦截顺序与请求相反,最终将响应结果发送给客户端
    • 4.Filter链中的各个Filter的对Servletd的拦截顺序与它们在web.xml文件中< filter-mapping>元素的映射顺序一样(即:顺序位于上面的Filter先拦截,优先级依次降低)
    • 5.chain.doFilter()方法上面的语句是对request对象的拦截,下面是对response对象的拦截,两个拦截时的顺序相反(即:对request对象的拦截顺序和该Filter在xml文件配置顺序一样,而response对象刚好相反)
    • 6.请求拦截时读取的是chain.doFilter()方法上面的信息,响应拦截时读取的是chain.doFilter()方法下面的信息
    • 7.chain.doFilter()方法将处理将给下一个页面,如果没有该方法,则不会跳转到下一个页面,只会显示拦截信息
    • 8.Filter链中的各个Filter的对文件修改的优先级与它们在web.xml文件中< filter-mapping>元素的映射顺序一样(即:顺序位于上面的Filter修改的内容可以对面的所有内容生效,而下面的Filter修改的内容无法对上面的Filter内容生效)
    • 9.Servlet与Filter不存在顺序关系,即:不管Servlet在web.xml文件中位于Filter上面还是下面,Servlet只要映射匹配都可以被Filter拦截过滤
  • 4.测试
    • 1.MyFilter1.java
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      	// TODO Auto-generated method stub
      	// place your code here
      	PrintWriter out = response.getWriter();
      	out.println("Hello MyFilter1 Before");
      	// pass the request along the filter chain
      	chain.doFilter(request, response);
      	out.println("Hello MyFilter1 After");
      }
      
    • 2.MyFilter2.java
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      	// TODO Auto-generated method stub
      	// place your code here
      	PrintWriter out = response.getWriter();
      	out.println("Hello MyFilter2 Before");
      	// pass the request along the filter chain
      	chain.doFilter(request, response);
      	out.println("Hello MyFilter2 After");
      }
      
    • 3.web.xml
      <servlet>
      	<servlet-name>MyServlet</servlet-name>
       	<servlet-class>servletDemo.MyServlet</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>MyServlet</servlet-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </servlet-mapping>
      <filter>
      	<filter-name>Myfilter2</filter-name>
      	<filter-class>filter.MyFilter2</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>Myfilter2</filter-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </filter-mapping>
      <filter>
      	<filter-name>Myfilter1</filter-name>
      	<filter-class>filter.MyFilter1</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>Myfilter1</filter-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </filter-mapping>
      
    • MyFilter1配置顺序在前 在这里插入图片描述
    • MyFilter2配置顺序在前 在这里插入图片描述
    • MyServlet配置顺序在前 在这里插入图片描述

4.FilterConfig接口

  • 1.Servlet API提供FilterConfig接口获取Filter程序在web.xml文件中的配置信息
  • 2.该接口封装了Filter程序在web.xml中的所有注册信息,并且提供了一系列获取这些配置信息的方法
    方法声明功能描述
    String getFilterName()该方法用于返回web.xml文件中为Filter所设置的名称,也就是返回< filter-name>元素的设置值
    String getInitParameter(String name)该方法用于返回web.xml文件中为Filter所设置的某个名称的初始化参数值,如果指定名称的初始化参数不存在,则返回null
    Enumeration getInitParameterNames()该方法用于返回一个Enumeration集合对象,该集合对象中包含在web.xml文件中为当前Filter设置的所有初始化参数的名称
    ServletContext getServletContext()该方法用于返回FilterConfig对象中所包装的ServletContext对象的引用
  • 1.web.xml
      <servlet>
      	<servlet-name>MyServlet</servlet-name>
      	<servlet-class>servletDemo.MyServlet</servlet-class>
      </servlet>
      <servlet-mapping>
      	<servlet-name>MyServlet</servlet-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </servlet-mapping>
      <filter>
      	<filter-name>Myfilter3</filter-name>
      	<filter-class>filter.MyFilter3</filter-class>
    	<init-param>
      		<param-name>encoding</param-name>
      		<param-value>UTF-8</param-value>
      	</init-param>
      	 <init-param>
      		<param-name>context-type</param-name>
      		<param-value>text/html</param-value>
      	</init-param>
      </filter>
      <filter-mapping>
      	<filter-name>Myfilter3</filter-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </filter-mapping>
      <filter>
      	<filter-name>Myfilter2</filter-name>
      	<filter-class>filter.MyFilter2</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>Myfilter2</filter-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </filter-mapping>
      <filter>
      	<filter-name>Myfilter1</filter-name>
      	<filter-class>filter.MyFilter1</filter-class>
      </filter>
      <filter-mapping>
      	<filter-name>Myfilter1</filter-name>
      	<url-pattern>/MyServlet2</url-pattern>
      </filter-mapping>
    
  • 1.MyFilter1.java
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		// TODO Auto-generated method stub
    		// place your code here
    		PrintWriter out = response.getWriter();
    		out.println("Hello MyFilter1 Before" + "<br/>");
    		// pass the request along the filter chain
    		chain.doFilter(request, response);
    		out.println("测试Hello MyFilter1 After" + "<br/>");
    	}
    
  • 2.MyFilter2.java
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		// TODO Auto-generated method stub
    		// place your code here
    		PrintWriter out = response.getWriter();
    		out.println("Hello MyFilter2 Before" + "<br/>");
    		// pass the request along the filter chain
    		chain.doFilter(request, response);
    		out.println("Hello MyFilter2 After" + "<br/>");
    	}
    
  • 3.MyFilter3.java
    public class MyFilter3 implements Filter {
    	private String characterEncoding;
    	FilterConfig fc;
        public MyFilter3() {
            // TODO Auto-generated constructor stub
        }
    	public void destroy() {
    		// TODO Auto-generated method stub
    	}
    
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		// TODO Auto-generated method stub
    		// place your code here
    		response.setContentType("text/html;charset=UTF-8");
    		PrintWriter out = response.getWriter();
    			
    		characterEncoding = fc.getInitParameter("encoding");
    	
    		Enumeration e = fc.getInitParameterNames();
    		while(e.hasMoreElements()) {
    			String name = (String) e.nextElement();
    			out.println(name + "<br/>");
    		}
    		String name = fc.getFilterName();
    	
    		out.println(name + "<br/>");
    		// pass the request along the filter chain
    		out.println("encoding初始化参数的值为:" + characterEncoding + "<br/>");
    		chain.doFilter(request, response);
    	}
    	public void init(FilterConfig fConfig) throws ServletException {
    		// TODO Auto-generated method stub
    		this.fc = fConfig;
    	}
    }
    
  • 4.MyServlet.java
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		// TODO Auto-generated method stub
    		PrintWriter out = response.getWriter();
    		out.println("Hello MyServlet" + "<br/>");
    	}
    
    在这里插入图片描述
  • 语法说明:
    • 1.Tomcat服务器启动时会加载所有的Web应用,当加载到该应用时,MyFilter3就会被初始化调用init()方法,从而可以得到FIlterConfig,然后在doFilter()方法中通过调用FilterConfig对象的getInitParameter()方法便可以获取在web.xml文件中配置的某个参数信息
    • 2.配置初始化参数一般在< xxx-class>后面配置,一个参数需要一个< init-param>

5.使用Filter实现用户自动登录

6.使用Filter实现统一全站编码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值