第五章 Servlet 技术

目录

Servlet 基础

1.Servlet 与 Servlet 容器

2.Servlet 技术特点

(1)方便、使用的API方法

(2)高效的处理方式

(3)跨平台

(4)更加灵活、扩展

(5)安全性

3.Servlet 技术功能

4.Servlet 与 JSP 的区别

5.Servlet 代码结构

Servlet 开发

Servlet 配置

1.声明 Servlet 对象

2.映射 Servlet

Servlet API 编程常用的接口和类

1.Servlet 接口

2.ServletConfig 接口

3.HttpServletRequest 接口

4.HttpServletResponse 接口

5.GenericServlet 类

Servlet 过滤器

过滤器概述

2.Filter API

(1)Filter 接口

(2)FilterChain 接口

(3)FilterConfig 接口

3.过滤器的配置

4.过滤器典型应用

上机测试


Servlet 基础

Servlet 是使用 Java Servlet 接口 (API) 运行在 Web 应用服务器上的 Java 程序。与普通 Java 程序不同,它是位于 Web 服务器内部的服务器端的 Java 应用程序,可以对 Web 浏览器或其他 HTTP 客户端程序发送的请求进行处理。

1.Servlet 与 Servlet 容器

Servlet 对象与普通的 Java 对象不同,它可以处理 Web 浏览器或其他 HTTP 客户端程序发送的 HTTP 请求,但前提条件是把 Servlet 对象布置到 Servlet 容器之中,也就是说,其运行需要 Servlet 容器的支持。

通常情况下,Servlet 容器也就是指 Web 容器,如 Tomcat、Jboss、Resin、WebLogic 等,它们对 Servlet 进行控制。当一个客户端发送 HTTP 请求时,由容器加载 Servlet 对其进行处理并作出响应。在 Web 容器中,Servlet 主要经历 4 个阶段,如图:

Servlet 与 Web 容器的关系是非常密切的,在 Web 容器中 Servlet 主要经历了 4 个阶段,这 4 个阶段实质是 Servlet 的生命周期,由容器进行管理。

(1)在 Web 容器启动或客户机第一次请求服务时,容器将加载 Servlet 类并将其放入到 Servlet 实例池。

(2)当 Servlet 实例化后,容器将调用 Servlet 对象的 init() 方法完成 Servlet 的初始化操作,主要是为了让 Servlet 在处理请求之前做一些初始化工作。

(3)容器通过 Servlet 的 service() 方法处理客户端请求。在 service() 方法中,Servlet 实例根据不同的 HTTP 请求类型做出不同处理,并在处理之后做出相应的响应。

(4)在Web 容器关闭时,容器调用Servlet 对象的 destroy() 方法对资源进行释放。在调用此方法后,Servlet 对象将被垃圾回收器处理。

2.Servlet 技术特点

Servlet 采用 Java 语言编写,继承了 Java 语言中的诸多优点,同时还对 Java 的 Web 应用进行了扩展。 Servlet具有以下特点。

(1)方便、使用的API方法

Servlet 对象对 Web 应用进行了封装,针对HTTP请求提供了丰富的API方法,它可以处理表单提交数据、会话追踪、读取和设置HTTP头信息等,对HTTP请求数据的处理非常方便,只需要调用相应的API方法即可。

(2)高效的处理方式

Servlet 的一个实例对象可以处理多个线程的请求。当多个客户端请求一个Servlet对象时,Servlet 为每一个请求分配一个线程,而提供服务的 Servlet 对象只有一个,因此我们说 Servlet 的多线程处理方式是非常高效的。

(3)跨平台

Servlet 采用 Java 语言编写,因此它继承了 Java 的跨平台性,对于已编写好的 Servlet 对象,可运行在多种平台之中。

(4)更加灵活、扩展

Servlet 与 Java 平台的关系密切,它可以访问 Java 平台丰富的类库;同时由于它采用 Java 语言编写,支持封装、继承等面向对象的优点,使其更具应用的灵活性;此外,在编写过程中,它还对 API 接口进行了适当扩展。

(5)安全性

Servlet 采用了 Java 的安全框架,同时Servlet 容器还为 Servlet 提供了额外的功能,其安全性是非常高的。

3.Servlet 技术功能

Servlet 是位于 Web 服务器内部的服务器端的 Java 应用程序,它对 Java Web 的应用进行了扩展,可以对 HTTP 请求进行处理及响应,功能十分强大。

(1)Servlet 与普通 Java 应用程序不同,它可以处理 HTTP 请求以获取 HTTP 头信息,通过 HttpServletRequest 接口与 HTTP ServletResponse 接口对请求进行处理及回应。

(2)Servlet 可以在处理业务逻辑之后,将动态的内容通过返回并输出到 HTML 页面中,与用户请求进行交互。

(3)Servlet 提供了强大的过滤器功能,可针对请求类型进行过滤设置,为 Web 开发提供灵活性与扩展性。

(4)Servlet 可与其他服务器资源进行通信。

4.Servlet 与 JSP 的区别

Servlet 是一种运行在服务器端的 Java 应用程序,先于 JSP的产生。在 Servlet 的早期版本中,业务逻辑代码与网页代码写在一起,给Web程序的开发带来了很多不便。如网页设计的美工人员,需要学习 Servlet 技术进行页面设计;而在程序设计中,其代码又过于复杂,Servlet 所产生的动态网页需要在代码中编写大量输出 HTML 标签的语句。针对早期版本 Servlet 的不足,Sun 提出了 JSP 技术。

JSP 是一种在 Servlet 规范之上的动态网页技术,通过 JSP 页面中嵌入的 Java 代码,可以产生动态网页。也可以将其理解为是 Servlet 技术的扩展,在 JSP 文件被第一次请求时,它会被编译成 Servlet 文件,再通过容器调用 Servlet 进行处理。由此可以看出,JSP 与 Servlet 技术的关系是十分紧密的。

JSP 虽是在 Servlet 的基础上产生的,但与 Servlet 也存在一定的区别。

(1)Servlet 承担客户请求与业务处理的中间角色,需要调用固定的方法,将动态内容混合到静态之中产生 HTML;而在 JSP 页面中,可直接使用 HTML 标签进行输出,要比 Servlet 更具显示层的意义。

(2)Servlet 中需要调用 Servlet API 接口处理 HTTP 请求,而在 JSP 页面中,则直接提供了内置对象进行处理。

(3)Servlet 的使用需要进行一定的配置,而 JSP 文件通过” .jsp " 扩展名部署在容器之中,容器对其自动识别,直接编译成 Servlet 进行处理。

5.Servlet 代码结构

在 Java 中,通常所说的 Servlet 是指 HttpServlet 对象,在声明一个对象为 Servlet 时,需要继承 HttpServlet 类。HttpServlet 类是 Servlet 接口的一个实现类,继承此类后,可以重写 HttpServlet 类中的方法对 HTTP 请求进行处理。其代码结构如下:

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class MyServlet extends HttpServlet {
	
	//初始化方法
	public void init(ServletConfig config) throws ServletException {

	}

	//销毁方法
	public void destroy() {
		super.destroy();
	}

	//处理 HTTP Get 请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	//处理 HTTP Post 请求
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	//处理 HTTP Put 请求
	protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

	//处理 HTTP Delete 请求
	protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
	}

}

上述代码显示了一个 Servlet 对象的代码结构, MyServlet 类通过继承 HttpServlet 类被声明为一个 Servlet 对象。此类中包含6个方法,其中 init() 方法与 destroy() 方法为 Servlet 初始化与生命周期结束所调用的方法,其余的4个方法为 Servlet 针对处理不同的 HTTP 请求类型所提供的方法,其作用如注释所示。

在一个 Servlet 对象中,最常用的方法是 doGet() 与 doPost() 方法,这两个方法分别用于处理 HTTP 的 Get 与 Post 请求。例如,<form> 表单对象所声明的 method 属性为 “ post ”,提交到 Servlet 对象处理时,Servlet 将调用 doPost() 方法进行处理。

Servlet 开发

Servlet 配置

要使 Servlet 对象正常地运行,需要进行适当的配置,以告知 Web 容器哪一个请求调用哪一个 Servlet 对象处理,对 Servlet 起到一个注册的作用。Servlet 的配置包含在 web.xml 文件中,主要通过以下两步进行设置。

1.声明 Servlet 对象

在 web.xml 文件中,通过 <servlet> 标签声明一个 Servlet 对象。在此标签下包含两个主要子元素,分别为<servlet-name>与<servlet-class>。其中,<servlet-name>元素用于指定 Servlet 的名称,此名称可以为自定义的名称;<servlet-class>元素用于指定 Servlet 对象的完整位置,包含 Servlet 对象的包名与类名。其声明语句如下:

<servlet>
    <servlet-name>SimpleServlet</servlet-name>
    <servlet-class>com.lyq.SimpleServlet</servlet-class>
</servlet>

2.映射 Servlet

在 web.xml 文件中声明了 Servlet 对象后,需要映射访问 Servlet 的URL。此操作使用 <servlet-mapping>标签进行了配置。<servlet-mapping>标签包含两个子元素,分别为<servlet-name>与<url-pattern>。其中,<servlet-name>元素与<servlet>标签中的

<servlet-name>元素相对应,不可以随意命名;<url-pattern>元素用于映射访问URL。其配置方法如下:

<servlet_mapping>
    <servlet-name>SimpleServlet</servlet-name>
    <url-pattern>/SimpleServlet</url-pattern>
</servlet-mapping>

测试:Servlet 的创建及配置

(1) 创建名为 MyServlet 的 Servlet 对象,继承 HttpServlet 类。在此类中重写 doGet() 方法,用于处理 HTTP 的 get 请求,通过 PrintWriter 对象进行简单输出。关键代码如下:

//处理HTTP Get 请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		
		response.setContentType("text/html");
		response.setCharacterEncoding("GBK");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>servlet实例</title></head>");
		out.println("<body>");
		out.print("servlet实例:"+this.getClass());
		out.println("</body>");
		out.println("</html>");
	}

(2)在 web.xml 文件中对 MyServlet 进行配置,其中访问 URL 的相对路径为:"/servlet/MyServlet"。其关键代码如下:

<servlet>
  	<servlet-name>MyServlet</servlet-name>
  	<servlet-class>com.my.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>MyServlet</servlet-name>
  	<url-pattern>/servlet/MyServlet</url-pattern>
  </servlet-mapping>

(3) 创建 index.jsp 页面。关键代码如下:

<body>
	<form action="servlet/MyServlet" method="get">
	<input type="submit" value="提交" />
	</form>
</body>

运行效果:

Servlet API 编程常用的接口和类

Servlet 是运行在服务器端的 Java 应用程序,由 Servlet 容器对其进行管理,当用户对容器发送 HTTP 请求时,容器将通知相应的 Servlet 对象进行处理,完成用户与程序之间的交互。在 Servlet 编程中,Servlet API 提供了标准的接口与类,这些对象对 Servlet 的操作非常重要,它们为 HTTP 请求与程序回应提供了丰富的方法。 

1.Servlet 接口

Servlet 的运行需要 Servlet 容器的支持,Servlet 容器通过调用 Servlet 对象提供了标准的 API 接口,对请求进行处理。在 Servlet 开发中,任何一个 Servlet 对象都要直接或间接地实现 javax.servlet.Servlet 接口。在此接口中包含 5 种方法,其功能及作用:

方法说明
public void init(ServletConfig config)Servlet 实例化后,Servlet 容器调用此方法来完成初始化工作。

public void service(ServletRequest request,ServletResponse response)

此方法用于处理客户端请求。
public void destroy()当 Servlet 对象应该从 Servlet 容器中移除时,容器调用此方法,以便释放资源。
public ServletConfig getServletConfig()此方法用于获取 Servlet 对象的配置信息,返回 ServletConfig 对象。
public String getServletInfo()此方法返回有关 Servlet 的信息,它是纯文本格式的字符串,如作者、版本等。

2.ServletConfig 接口

ServletConfig 接口位于 javax.servlet 包中,它封装了 Servlet 的配置信息,在 Servlet 初始化期间被传递。每一个 Servlet 都有且只有一个 ServletConfig 对象。此对象定义了 4 个方法。说明如下:

方法说明
public String getInitParameter(String name)此方法返回 String 类型名称为 name 的初始化参数值
public Enumeration getInitParameterNames()获取所有初始化参数名的枚举集合
public ServletContext getServletContext()用于获取 Servlet 上下文对象
public String getServletName()返回 Servlet 对象的实例名

3.HttpServletRequest 接口

HttpServletRequest 接口位于 javax.servlet.http包中,继承了 javax.servlet.ServletRequest 接口,是 Servlet 中重要对象,在开发过程中较为常用,其常用方法如下:

方法说明
public String getContextPath()返回请求的上下文路径,此路径以“ / ”开头
public Cookie[] getCookies()返回请求中发送的所有 cookie 对象,返回值为 cookie 数组
public String getMethod()返回请求所使用的 HTTP 类型,如 get、post 等
public String getQueryString()返回请求中参数的字符串形式,如请求 MyServlet?username=me,则返回 username=me
public String getRequestURI()返回主机名到请求参数之间部分的字符串形式
public StringBuffer getRequestURL()返回请求的URL,此 URL 中不包含请求的参数。注意此方法返回的数据类型为StringBuffer
public String getServletPath()返回请求URI中的Servlet 路径的字符串,不包含请求中的参数信息
public HttpSession getSession()返回与请求关联的 HttpSession 对象

测试:HttpServletRequest接口的使用

(1) 创建名为 MyServlet 的类(它是一个 Servlet),在此类中通过 PrintWriter 对象向页面中输出调用 HttpServletRequest 接口中的方法所获取的值。其关键代码如下:

//处理HTTP Get 请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		
		response.setContentType("text/html");
		response.setCharacterEncoding("GBK");
		PrintWriter out = response.getWriter();
		out.println("<p>上下文路径:"+ request.getServletPath()+"</p>");
		out.println("<p>HTTP请求类型:"+ request.getMethod()+"</p>");
		out.println("<p>请求参数:"+ request.getQueryString()+"</p>");
		out.println("<p>请求URI:"+ request.getRequestURI()+"</p>");
		out.println("<p>请求URL:"+ request.getRequestURL().toString()+"</p>");
		out.println("<p>请求Servlet路径:"+ request.getServletPath()+"</p>");
		out.flush();
		out.close();
	}

(2)在 web.xml 文件中,对 MyServlet 类进行配置。关键代码如下:

<servlet>
  	<servlet-name>MyServlet</servlet-name>
  	<servlet-class>com.my.MyServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>MyServlet</servlet-name>
  	<url-pattern>/servlet/MyServlet</url-pattern>
  </servlet-mapping>

在浏览器地址中输入"http://localhost:8080/MyWebTest/servlet/MyServlet?action=test"。运行效果:

4.HttpServletResponse 接口

HttpServletResponse 接口位于 javax.servlet.http 包中,它继承了javax.servlet.ServletResponse 接口,同样是一个非常重要的对象,其常用方法与说明如下:

方法说明
public void addCookie(Cookie cookie)向客户端写入 cookie 信息
public void sendError(int sc)发送一个错误状态码为 sc 的错误响应到客户端
public void sendError(int sc,String msg)发送一个包含错误状态码及错误信息的响应到客户端,参数sc为错误状态码,参数 msg 为错误信息
public void sendRedirect(String location)使用客户端重新定向到新的URL,参数 location 为新的地址

测试:在程序开发过程中,经常会遇到异常的产生,本实例使用 HttpServletResponse 向客户端发送错误信息。

(1)创建一个名为 MyServlet 的 Servlet 对象,在 doGet() 方法中模拟一个开发过程中的异常,并将其通过 throw 关键字抛出。其关键代码如下:

//处理HTTP Get 请求
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		
		try {
			//创建一个异常
			throw new Exception("数据库连接失败");
		} catch (Exception e) {
			response.sendError(500,e.getMessage());
		}
	}

(2)程序中的异常通过 catch 进行捕获,使用 HttpServletResponse 对象的 sendError() 方法向客户端发送错误信息,运行结果如下:

5.GenericServlet 类

在编写一个 Servlet 对象时,必须实现 javax.servlet.Servlet 接口,但在 Servlet 接口中包含 5 种方法,也就是说创建一个 Servlet 对象要实现这 5 种方法,这样操作非常不方便。 javax.servlet.GenericServlet 类简化了此操作,实现了 Servlet 接口。

public abstract class HttpServlet
        extends GenericServlet implements Serializables

HttpServlet 类仍然是一个抽象类,实现了 service() 方法,并针对 HTTP 1.1 中定义的 7 种请求类型提供了相应的方法——doGet()方法、doPost()方法、doPut() 方法、doDelete() 方法、doHead() 方法、doTrace() 方法、doOptions() 方法。在这7种方法中,除了对 doTrace() 方法与 doOptions() 方法进行简单实现外,HttpServlet 类并没有对其他方法进行实现,需要开发人员在使用过程中根据实际需要对其进行重写。

HttpServlet 类继承了 GenericServlet 类,通过其对 GenericServlet 类的扩展,可以很方便地对 HTTP 请求进行处理及响应。

Servlet 过滤器

过滤器是 Web 程序中的可重用组件,在 Servlet 2.3 规范中被引入,应用十分广泛,给 Java Web 程序的开发带来了更加强大的功能。

过滤器概述

Servlet 过滤器是客户端与目标资源的中间层组件,用于拦截客户端的请求与响应信息。当 Web 容器接收到一个客户端请求时,将判断此请求是否与过滤器对象相关联,如果相关联,则将这一请求交给过滤器进行处理。在处理过程中,过滤器可以对请求进行操作,如更改请求中的信息数据。在过滤器处理完成之后,再将这一请求交给其他业务进行处理。当所有业务处理完成,需要对客户端进行响应时,容器又将响应交给过滤器进行处理,过滤器完成处理后将响应发送到客户端。如下:

在 Web 程序开发过程中,可以放置多个过滤器,如字符编码过滤器、身份验证过滤器等,Web 容器对多个过滤器的处理方式如下:

在多个过滤器的处理方式中,容器首先将客户端请求交给第一个过滤器处理,处理完成之后交给下一个过滤器处理,一次类推,直到最后一个过滤器。当需要对客户端回应时,将按照相反的方向对回应进行处理,直到交给第一个过滤器,最后发送到客户端回应。

2.Filter API

过滤器与 Servlet 非常相似,它的使用主要是通过 3 个核心接口分别为 Filter 接口、FilterChain 接口与 FilterConfig 接口进行操作。

(1)Filter 接口

Filter 接口位于 Javax.servlet 包中,与 Servlet 接口相似,当定义一个过滤器对象时需要实现此接口。在 Filter 接口中包含 3 个方法,其方法声明及作用如下:

方法说明
public void init(FilterConfig, filter Config)过滤器的初始化方法,容器调用此方法完成过滤的初始化。对于每一个 Filter 实例,此方法只能被调用一次
public void doFilter(ServletRequest request,ServletResponse response, FilterChain chain)此方法与Servlet的 service() 方法相类似,当请求及响应交给过滤器时,过滤器调用此方法进行过滤处理。
public void destroy()在过滤器生命周期结束时调用此方法,用于释放过滤器所占用的资源

(2)FilterChain 接口

FilterChain 接口位于 javax.servlet 包中,此接口由容器进行实现,在 FilterChain 接口只包含一个方法,其方法声明如下:

void doFilter(ServletRequest request,
                ServletResponse response)
                throws IOException,ServletException
    

此方法主要用于将过滤器处理的请求或响应传递给下一个过滤器对象。在多个过滤器的 Web 应用中,可以通过此方法进行传递。

(3)FilterConfig 接口

FilterConfig 接口位于 javax.servlet 包中。此接口由容器进行实现,用于获取过滤器初始化期间的参数信息,其方法及说明如下:

方法说明
public String getFilterName()返回过滤器的名称
public String geiInitParameter(String name)返回初始化名称为 name 的参数值
public Enumeration getInitParameterNames()返回所有初始化参数名的枚举集合
public ServletContext getServletContext()返回 Servlet 的上下文对象

了解了过滤器的这 3 个核心接口,就可以通过实现 Filter 接口来创建一个过滤器对象。其代码如下:

public class MyFilter implements Filter {
    
    //初始化方法
    public void init(FilterConfig arg0) throws ServletException {
    }

    
    //过滤处理方法
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)             
               throws IOException,ServletException{
        
        //传递给下一个过滤器
        chain.doFilter(request,response);
    }


    //销毁方法
    public void destroy(){
    }
}

3.过滤器的配置

在创建一个过滤器对象之后,需要对其进行配置才可以使用。过滤器的配置方法与 Servlet 的配置方法相似,都是通过 web.xml 文件进行配置,具体步骤如下。

(1) 声明过滤器对象

在 web.xml 文件中,通过<filter>标签声明一个过滤器对象。在此标签下包含3个常用子元素,分别为<filter-name>、<filter-class>和<init-param>。其中,<filter-name>元素用于指定过滤器的名称,此名称可以为自定义的名称;<filter-class>元素用于指定过滤器对象的完整位置,包含过滤器对象的包名与类名;<init-param>元素用于设置过滤器的初始化参数。其配置如下:

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>com.lyq.util.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>GBK</param-value>
    </init-param>
</filter>

<init-param>元素包含两个常用子元素,分别为 <param-name>和<param-value>。其中,<param-name>元素同于声明初始化参数的名称,<param-value>元素用于指定初始化参数的值。

(2) 映射过滤器

在 web.xml 文件中声明了过滤器对象后,需要映射访问过滤器过滤的对象。此操作使用<filter-mapping>标签进行配置。在<filter-mapping>标签中,主要需要配置过滤器的名称、过滤器关联的 URL 样式、过滤器对应的请求方式等。其配置方法如下:

<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

<filter-name>元素用于指定过滤器的名称,此名称与<filter-name>标签中的<filter-name>相对应。

<url-pattern>元素用于指定过滤器关联的URL样式,设置为" /* "表示关联所有的URL。

<dispatcher>元素用于指定过滤器对应的请求方式,其可选值及使用说明如下:

可选值说明
REQUEST当客户端直接请求时,通过过滤器进行处理
INCLUDE当客户端通过 RequestDispatcher 对象的 include() 方法请求时,通过过滤器进行处理
FORWARD当客户端通过 RequestDispatcher 对象的 forward() 方法请求时,通过过滤器进行处理
ERROR当声明式异常产生时,通过过滤器进行处理

4.过滤器典型应用

在 Java Web 项目的开发时,过滤器的应用十分广泛,其中比较典型的应用就是字符编码过滤器。由于 java 程序可以在多种平台下运行,其内部使用 Unicode 字符集来表示字符,所以处理中文数据会产生乱码的情况,需要对其进行编码转换才可以正常显示。

测试:字符编码过滤器

(1)创建字符编码过滤器类 CharacterEncodingFilter ,此类实现了 Filter 接口,并对其 3 中方法进行了实现。代码如下:

package com.xj;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class CharacterEncodingFilter implements Filter{

	//字符编码(初始化参数)
	protected String encoding = null;
	//FilterConfig 对象
	protected FilterConfig filterConfig = null;
	
	//销毁方法
	@Override
	public void destroy() {
		// 释放资源
		this.encoding = null;
		this.filterConfig = null;
		
	}

	//过滤器处理方法
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// 判断字符编码是否有效
		if(encoding != null) {
			//设置request 字符编码
			request.setCharacterEncoding(encoding);
			//设置 response 字符编码
			response.setContentType("text/html;charset="+encoding);
		}
		//传递给下一过滤器
		chain.doFilter(request, response);
		
	}

	//初始化方法
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//对 filterConfig 赋值
		this.filterConfig = filterConfig;
		//对初始化参数赋值
		this.encoding = filterConfig.getInitParameter("encoding");
		
	}

}

CharacterEncodingFilter 类的 init() 方法用于读取过滤器的初始化参数,这个参数(encoding)为本例所用到的字符编码;早 doFilter() 方法中,分别将 request 对象及 response 对象中的编码格式设置为读取到的编码格式;最后在 destroy() 方法中将其属性设置为 null,将被 java 垃圾回收器回收。

(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>MyServletTest</display-name>
  <!-- 声明字符编码过滤器 -->
  <filter>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<filter-class>com.xj.CharacterEncodingFilter</filter-class>
  	<!-- 设置初始化参数 -->
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
  </filter>
  
  <!-- 映射字符编码过滤器 -->
  <filter-mapping>
  	<filter-name>CharacterEncodingFilter</filter-name>
  	<!-- 与所有请求关联 -->
  	<url-pattern>/*</url-pattern>
  	<!-- 设置过滤器对应的请求方式 -->
  	<dispatcher>REQUEST</dispatcher>
  	<dispatcher>FORWARD</dispatcher>
  </filter-mapping>
  
  <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>

在 web.xml 配置文件中,需要对过滤器进行声明及映射,其中声明过程通过<init-param>制定了初始化参数的字符编码为UTF-8。

(3)通过请求对过滤器进行验证。本例使用表单向 Servlet 发送中文信息进行测试,其中表单信息放置在 index.jsp 页面中。其关键代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="MyServlet" method="post">
		请输入你的中文名字:<input type="text" name="name"/>
		<input type="submit" value="提交"/>
	</form>
</body>
</html>

这一请求由Servlet 对象 MyServlet 类进行处理,此类使用 doPost() 方法接收表单的请求,并将表单中的 name 属性输出到页面中。记得对 MyServlet 进行配置。其关键代码如下:

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		PrintWriter out = response.getWriter();
		//获取表单参数
		String name = request.getParameter("name");
		if(name != null && !name.isEmpty()) {
			out.print("你好,"+name);
			out.print("<br>欢迎来到我的主页");
		} else {
			out.print("请输入你的中文名字!");
		}
		out.print("<br><a href=index.jsp>返回</a>");
		out.flush();
		out.close();
	}

运行效果:

上机测试

统计网站的访问量。在浏览网站时,有些网站会有统计网站访问量的功能,也就是浏览者每访问一次网站,访问量计数器就累加一次。这可以通过在 Servlet 中获取 ServletContext 接口的对象来实现。获取 ServletContext 对象以后,整个 Web 应用的组件都可以共享 ServletContext 对象中存放的共享数据。

(1)创建 JavaWeb项目,命名为 MyPro_01。

(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>MyPro_01</display-name>
  <servlet>
  	<servlet-name>CounterServlet</servlet-name>
  	<servlet-class>com.lh.servlet.CounterServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>CounterServlet</servlet-name>
  	<url-pattern>/counter</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>counter</welcome-file>
    
  </welcome-file-list>
</web-app>

(3)新建名称为 CounterServlet 的 Servlet 类,在该类的 doPost() 方法中实现统计用户的访问次数,代码如下:

package com.lh.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletContext;
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 CounterServlet
 */
@WebServlet("/CounterServlet")
public class CounterServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CounterServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		//复用 doPost() 方法
				this.doPost(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		//获得 ServletContext 对象
		ServletContext context = getServletContext();
		//从ServletContext 中获得计数器对象
		Integer count = (Integer)context.getAttribute("counter");
		if(count==null) { //如果为空,则在ServletContext中设置一个计数器的属性
			count = 1;
			context.setAttribute("counter", count);
		} else { //如果不为空,则设置该计数器的属性值加1
			context.setAttribute("counter", count + 1 );
		}
		response.setContentType("text/html"); //响应正文的MIME类型
		response.setCharacterEncoding("UTF-8"); //响应的编码格式
		PrintWriter out = response.getWriter();
		out.print("<html>");
		out.print("<head><title>统计网站访问次数</title></head>");
		out.print("<body>");
		out.print("您是第 " + context.getAttribute("counter") + "位访客!");
		out.print("</body>");
		out.print("</html>");
		out.flush();
		out.close();
	}

}

(4)将项目部署到服务器,启动服务器,访问地址 "http://localhost:8080/MyPro_01"。运行效果如下:

 

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值