Java Web中的Servlet及Filter

  • 文章来源:优才学院
  • 发布时间:2017-09-28
  • 作者:小强

  在Servlet到底是什么的文章中已经做了说明,下面简单说下Servlet,以便和Filter做个对比

  一、Servlet

  Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础。

  1.1Servlet的介绍

  


  


  1.2Servlet的使用

  通常情况下,我们自己定义的 servlet 并不是直接去实现 javax.servlet.servlet 接口,而是去继承更简单的 HttpServlet 类或者 GenericServlet 类,我们可以有选择的覆盖相应方法去实现我们要完成的工作。

  HttpServlet 类包含 init()、destroy()、service() 等方法。其中 init() 和 destroy() 方法是继承的。

  (1) init() 方法

  在 Servlet 的生命期中,仅执行一次 init() 方法。它是在服务器装入 Servlet 时执行的。 可以配置服务器,以在启动服务器或客户机首次访问 Servlet 时装入 Servlet。 无论有多少客户机访问 Servlet,都不会重复执行 init() 。

  缺省的 init() 方法通常是符合要求的,但也可以用定制 init() 方法来覆盖它,典型的是管理服务器端资源。 例如,可能编写一个定制 init() 来只用于一次装入 GIF 图像,改进 Servlet 返回 GIF 图像和含有多个客户机请求的性能。另一个示例是初始化数据库连接。缺省的 init() 方法设置了 Servlet 的初始化参数,并用它的 ServletConfig 对象参数来启动配置, 因此所有覆盖 init() 方法的 Servlet 应调用 super.init() 以确保仍然执行这些任务。在调用 service() 方法之前,应确保已完成了 init() 方法。

  (2) service() 方法

  service() 方法是 Servlet 的核心。每当一个客户请求一个HttpServlet 对象,该对象的service() 方法就要被调用,而且传递给这个方法一个"请求"(ServletRequest)对象和一个"响应"(ServletResponse)对象作为参数。 在 HttpServlet 中已存在 service() 方法。缺省的服务功能是调用与 HTTP 请求的方法相应的 do 功能。例如, 如果 HTTP 请求方法为 GET,则缺省情况下就调用 doGet() 。Servlet 应该为 Servlet 支持的 HTTP 方法覆盖 do 功能。因为 HttpServlet.service() 方法会检查请求方法是否调用了适当的处理方法,不必要覆盖 service() 方法。只需覆盖相应的 do 方法就可以了。

  Servlet 的响应可以是下列几种类型:

  一个输出流,浏览器根据它的内容类型(如 text/html)进行解释。

  一个 HTTP 错误响应,重定向到另一个 URL、servlet、JSP。

  (3) doGet() 方法

  当一个客户通过 HTML 表单发出一个 HTTP GET 请求或直接请求一个 URL 时,doGet() 方法被调用。与 GET 请求相关的参数添加到 URL 的后面,并与这个请求一起发送。当不会修改服务器端的数据时,应该使用 doGet() 方法。

  (4) doPost() 方法

  当一个客户通过 HTML 表单发出一个 HTTP POST 请求时,doPost() 方法被调用。与 POST 请求相关的参数作为一个单独的 HTTP 请求从浏览器发送到服务器。当需要修改服务器端的数据时,应该使用 doPost() 方法。

  (5) destroy() 方法

  destroy() 方法仅执行一次,即在服务器停止且卸装 Servlet 时执行该方法。典型的,将 Servlet 作为服务器进程的一部分来关闭。缺省的 destroy() 方法通常是符合要求的,但也可以覆盖它,典型的是管理服务器端资源。例如,如果 Servlet 在运行时会累计统计数据,则可以编写一个 destroy() 方法,该方法用于在未装入 Servlet 时将统计数字保存在文件中。另一个示例是关闭数据库连接。

  当服务器卸装 Servlet 时,将在所有 service() 方法调用完成后,或在指定的时间间隔过后调用 destroy() 方法。一个 Servlet 在运行 service() 方法时可能会产生其它的线程,因此请确认在调用 destroy() 方法时,这些线程已终止或完成。

  (6) getServletConfig() 方法

  getServletConfig() 方法返回一个 ServletConfig 对象,该对象用来返回初始化参数和 ServletContext。ServletContext 接口提供有关 servlet 的环境信息。

  (7) getServletInfo() 方法

  getServletInfo() 方法是一个可选的方法,它提供有关 servlet 的信息,如作者、版本、版权。

  当服务器调用 sevlet 的 service()、doGet() 和 doPost() 这三个方法时,均需要 “请求”和“响应”对象作为参数。“请求”对象提供有关请求的信息,而“响应”对象提供了一个将响应信息返回给浏览器的一个通信途径。

  javax.servlet 软件包中的相关类为 ServletResponse 和 ServletRequest,而 javax.servlet.http 软件包中的相关类为 HttpServletRequest 和 HttpServletResponse。Servlet 通过这些对象与服务器通信并最终与客户端通信。Servlet 能通过调用"请求"对象的方法获知客户端环境,服务器环境的信息和所有由客户机提供的信息。Servlet 可以调用“响应”对象的方法发送响应,该响应是准备发回客户端的。

  web.xml配置

  <servlet>

  <servlet-name>HelloServlet</servlet-name>

  <servlet-class>com.hhl.servlet.HelloServlet</servlet-class>

  </servlet>

  <servlet-mapping>

  <servlet-name>HelloServlet</servlet-name>

  <url-pattern>/</url-pattern>

  </servlet-mapping>

  servlet实现

  public class HelloServlet extends HttpServlet {

  /**

  *

  */

  private static final long serialVersionUID = -468861535655735406L;

  /**

  * Constructor of the object.

  */

  public HelloServlet() {

  super();

  }

  /**

  * Destruction of the servlet. <br>

  */

  public void destroy() {

  super.destroy(); // Just puts "destroy" string in log

  // Put your code here

  }

  /**

  * The doGet method of the servlet. <br>

  *

  * This method is called when a form has its tag value method equals to get.

  *

  * @param request the request send by the client to the server

  * @param response the response send by the server to the client

  * @throws ServletException if an error occurred

  * @throws IOException if an error occurred

  */

  public void doGet(HttpServletRequest request, HttpServletResponse response)

  throws ServletException, IOException {

  // response.setContentType("text/html");

  PrintWriter out = response.getWriter();

  // out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");

  // out.println("<HTML>");

  // out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");

  // out.println(" <BODY>");

  out.print(" This is ");

  out.print(this.getClass());

  out.println(", using the GET method");

  // out.println(" </BODY>");

  // out.println("</HTML>");

  out.flush();

  out.close();

  }

  /**

  * The doPost method of the servlet. <br>

  *

  * This method is called when a form has its tag value method equals to post.

  *

  * @param request the request send by the client to the server

  * @param response the response send by the server to the client

  * @throws ServletException if an error occurred

  * @throws IOException if an error occurred

  */

  public void doPost(HttpServletRequest request, HttpServletResponse response)

  throws ServletException, IOException {

  response.setContentType("text/html");

  PrintWriter out = response.getWriter();

  out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");

  out.println("<HTML>");

  out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");

  out.println(" <BODY>");

  out.print(" This is ");

  out.print(this.getClass());

  out.println(", using the POST method");

  out.println(" </BODY>");

  out.println("</HTML>");

  out.flush();

  out.close();

  }

  /**

  * Initialization of the servlet. <br>

  *

  * @throws ServletException if an error occurs

  */

  public void init() throws ServletException {

  System.out.println("servlet init");

  }

  }

  1.3 说明

  Servlet 的确已经能够帮我们完成所有的工作了,但是现在的 web 应用很少有直接将交互全部页面都用 servlet 来实现,而是采用更加高效的 MVC 框架(例如struts、SpringMVC)来实现。这些 MVC 框架基本的原理都是将所有的请求都映射到一个 Servlet,然后去实现 service 方法,这个方法也就是 MVC 框架的入口。

  二、 Filter

  Filter也称之为过滤器,它是Servlet技术中比较激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

  2.2 使用

  Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截。简单说,就是可以实现web容器对某资源的访问前截获进行相关的处理,还可以在某资源向web容器返回响应前进行截获进行处理。

  1> 通过控制对chain.doFilter的方法的调用,来决定是否需要访问目标资源。

  比如,可以在用户权限验证等等。判断用户是否有访问某些资源的权限,有权限放行,没权限不执行chain.doFilter方法。

  2> 通过在调用chain.doFilter方法之前,做些处理来达到某些目的。

  比如,解决中文乱码的问题等等。可以在doFilter方法前,执行设置请求编码与响应的编码。甚至可以对request接口进行封装装饰来处理get请求方式的中文乱码问题(重写相应的request.getParameter方法)。

  3> 通过在调用chain.doFilter方法之后,做些处理来达到某些目的。

  比如对整个web网站进行压缩。在调用chain.doFilter方法之前用类A对response对象进行封装装饰,重写getOutputStream和重写getWriter方法。在类A内部中,将输出内容缓存进ByteArrayOutputStream流中,然后在chain.doFilter方法执行后,获取类A中ByteArrayOutputStream流缓存数据,用GZIPOutputStream流进行压缩下。

  web.xml中配置

  <filter>

  <filter-name>baseFilter</filter-name>

  <filter-class>com.mango.filter.BaseFilter</filter-class>

  </filter>

  <filter-mapping>

  <filter-name>baseFilter</filter-name>

  <url-pattern>/*</url-pattern>

  </filter-mapping>

  实现

  public class BaseFilter implements Filter {

  @Override

  public void init(FilterConfig filterConfig) throws ServletException {

  // TODO Auto-generated method stub

  }

  @Override

  public void doFilter(ServletRequest request, ServletResponse response,

  FilterChain chain) throws IOException, ServletException {

  HttpServletRequest httpRequest = (HttpServletRequest) request;

  String context = httpRequest.getContextPath();

  request.setAttribute("CONTEXT", context);

  chain.doFilter(request, response);

  }

  @Override

  public void destroy() {

  // TODO Auto-generated method stub

  }

  }

  2.3原理

  Filter接口中有一个doFilter方法,当开发人员编写好Filter类实现doFilter方法,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前(服务器内部对资源的访问机制决定的),都会先调用一下filter的doFilter方法。

  2.4生命周期

  和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。

  注意:init方法与destroy方法只会直接一次。