Servlet

1、Servlet概述

  Servlet是Java Web的三大组件(Servlet,Filter,Listener)之一,属于动态资源 ,运行在 Web 服务器或应用服务器上的程序作用为处理请求,服务器会把接收的请求交给Servlet来处理,在Servlet中通常需要:

  • 接收请求数据;
  • 处理请求;
  • 完成响应。

  例如:客户端发出登录请求,或输出注册请求,这些请求都应该有Servlet来完成处理。每个Servlet都必须实现javax.servle.Servlet接口。

2、实现Servlet的方式

  三种实现方式:

    • 实现javax.servlet.Servlet接口
    • 继承javax.servlet.GenericServlet类
    • 继承javax.servlet.http.HttpServlet类

  通常会去继承HttpServlet类来完成Servlet。

3、Servlet生命周期方法:

  • void init(ServletConfig servletConfig):Servlet对象创建之后马上执行的初始化方法,只执行一次;
  • void service(ServletRequest servletRequest, ServletResponse servletResponse):每次处理请求都是在调用这个方法,它会被调用多次;
  • void destroy():在Servlet被销毁之前调用,负责释放Servlet对象占用的资源的方法;

  特性:

  • 单例,一个类只有一个对象,当然可能存在多个Servlet类
  • 线程不安全的,所以它的效率高。

  Servlet类由自己编写,但对象由服务器来创建,并由服务器来调用相应的方法。

 

 

/**
 * Servlet接口方法介绍
 * 类由我们自己创建(可变部分),Servlet中的方法大多数由Tomcat来调用,并且Servlet对象也由Tomcat来创建。
 */
public class AServlet implements Servlet {
    /*
    * 它是生命周期方法
    * 它会在Servlet对象创建之后马上执行,并只执行一次。
    * 负责Servlet初始化工作。
    */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init()...");
    }
    /*
    * 用来获取Servlet的配置信息
    */
    @Override
    public ServletConfig getServletConfig() {
        System.out.println("getServletConfig()...");
        return null;
    }
    /*
    * 它是生命周期方法
    * 它会被调用多次
    * 每次处理请求都是在调用这个方法
    */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
      throws ServletException, IOException { System.out.println("service()..."); } /* * 获取Servlet的信息 */ @Override public String getServletInfo() { System.out.println("getServletInfo()..."); return null; } /* * 它是生命周期方法 * 它会在Servlet被销毁之前调用,负责释放Servlet对象占用的资源,并且它只会被调用一次。 */ @Override public void destroy() { System.out.println("destroy()..."); } }

 

Servlet细节:
1、Servlet与线程安全
一个类型的Servlet只有一个实例对象,那么就有可能会出现一个Servlet同时处理多个请求,线程不安全,但Servlet工作效率高。
解决方法:
  • 不要在Servlet中创建成员,创建局部变量变量即可!
  • 可以创建无状态成员!
  • 可以创建有状态的成员,但状态必须位为只读的!
 1 public class Servlet extends HttpServlet {
 2     //无状态成员
 3     /*public class User {
 4         public void hello() {
 5             System.out.println("Hello");
 6         }
 7     }*/
 8     //创建有状态的成员,但状态必须位为只读的
 9     /*public class User {
10         private String name = "zhangsan";
11         public String getName() {
12             return name;
13         }
14     }*/
15     private User user = new User();
16 
17     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
18         System.out.println("doPost()...");
19     }
20     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
21         System.out.println("doGet()...");
22     }
23 }

2、让服务器在启动时就创建Servlet对象

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5          version="3.1">
 6     <servlet>
 7         <servlet-name>Servlet</servlet-name>
 8         <servlet-class>web.servlet.Servlet</servlet-class>
 9         <load-on-startup>0</load-on-startup>
10     </servlet>
11     <servlet-mapping>
12         <servlet-name>Servlet</servlet-name>
13         <url-pattern>/Servlet</url-pattern>
14     </servlet-mapping>
15     <servlet>
16         <servlet-name>Servlet2</servlet-name>
17         <servlet-class>web.servlet.Servlet2</servlet-class>
18         <load-on-startup>1</load-on-startup>
19     </servlet>
20     <servlet-mapping>
21         <servlet-name>Servlet2</servlet-name>
22         <url-pattern>/Servlet2</url-pattern>
23     </servlet-mapping>
24 </web-app>

第9、18行作用:用于指定Servlet被加载的时机和顺序,值必须为一个整数。如果这个值是一个负数或没有设定这个元素,Servlet容器将在客户端首次请求这个Servlet时加载它。如果设置此元素,值越小,越先被加载。

3、<url-pattern>

用来指定Servlet的访问路径,即URL。必须以“/”开头。

1)可以在<servlet-mapping>中给出多个<url-pattern>,即一对多,如

    <servlet-mapping>
        <servlet-name>Servlet2</servlet-name>
        <url-pattern>/Servlet2</url-pattern>
        <url-pattern>/Servlet3</url-pattern>
    </servlet-mapping>

此功能已被Filter替代。

2)还可以在<url-pattern>中使用通配符“*”,可以匹配任何URL前缀或后缀。

  • <url-pattern>/servlet/*</url-pattern>:/servlet/a、/servlet/b,都匹配/servlet/*;
  • <url-pattern>*.do</url-pattern>:/abc/def/gif.do、/a.do,都匹配*.do;
  • <url-pattern>/*</url-pattern>:匹配所有URL;

注意:通配符不能出现URL中间位置,也不能只有通配符且只能出现一个,如“/*.do”、"*.*"都是错误的

    优先匹配更具体的路径。

二、web.xml文件的继承(了解)

  每个完整的JavaWeb应用中都需要有web.xml,但我们不知道所有的web.xml都有一个共同的父文件,他在Tomcatd的conf/web.xml中。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 3          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 5          version="3.1">
 6     <servlet>
 7         <servlet-name>default</servlet-name>
 8         <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
 9         <init-param>
10             <param-name>debug</param-name>
11             <param-value>0</param-value>
12         </init-param>
13         <init-param>
14             <param-name>listings</param-name>
15             <param-value>false</param-value>
16         </init-param>
17         <load-on-startup>1</load-on-startup>
18     </servlet>
19 </web-app>

第7行,表示它的优先级最低,如果一个请求没有人处理,那么它来处理,显示404。

第8行,当访问路径不存在时,会执行该Servlet!我访问index.html时也执行这个Servlet。

三、ServletContext接口

1)ServletContext接口概述

  服务器会为每个应用(项目)创建一个ServletContext对象:

    • ServletContext对象的创建是在服务器启动时完成的。
    • ServletContext对象的销毁是在服务器关闭时完成的。

  ServletContext对象的作用是在整个Web应用的动态资源之间共享数据。例如在AServlet中向ServletContext对象中保存一个值,然后再BServlet中就可以获取这个值,这就是共享数据了。

2)获取ServletContext

  • ServletConfig#getServletContext();
  • GenericServlet#getServletContext();
  • HttpSessin#getServletContext();
  • ServletContextEvent#getServletContext();

  在Servlet中获取ServletContext对象:

  •   在void init(ServletConfig config)中:ServletContext context = config.getServletContext();

   ServletConfig类的getServletContext()可以获取ServletContext对象;

    在GenericeServlet或HttpServlet中获取ServletContext对象;

  •   GenericServlet类有getServletContext()方法,所以可以直接使用this.getServletContext()来获取;

3)域对象的功能

  • 域对象就是用来在多个Servlet中传递数据。
  • 域对象必须有存数据功能。
  • 域对象必须要有取数据功能。

  ServletContext是JavaWeb四大域对象之一:PageContext、ServletRequest、HttpSession、ServletContext;

  所有域对象都有存取数据的功能,因为域对象内部都有一个Map,用来储存数据,下面是ServletContext对象用来操作数据的方法:

  • void setAttribute(String name, Object value):用来储存一个对象,也称之为存储一个域属性,例如:servletContext.setAttribute("xxx","XXX"),在ServletContext中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并使用相同的name,那么会覆盖上一次的值,与Map特性相同。
  • Object getAttribute(String name):用来获取ServletContext中的数据,当前在获取之前需要先去存储才行。例如:String value = (String) servletContext.getAttribute("xxx"),获取名为xxx的域属性。
  • void removeAttribute(String name):用来移除ServletContext中的域属性,如果参数name指定的域属性不存在,那么方法什么都不做;
  • Eumeration getAttributeNames():获取所有域属性的名称。

4)获取应用初始化参数

  Servlet也可以获取初始化参数,但它是局部的参数;也就是说,一个Servlet只能获取自己的初始化参数,不能获取别人的,即初始化参数只为一个Servlet准备。

  可以配置公共的初始化参数,为所有Servlet而用,这需要ServletContext才能使用。

web.xml文档

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <servlet>
        <servlet-name>CServlet</servlet-name>
        <servlet-class>web.servlet.CServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>CServlet</servlet-name>
        <url-pattern>/CServlet</url-pattern>
    </servlet-mapping>
    <context-param>
        <param-name>context-param</param-name>
        <param-value>context-value</param-value>
    </context-param>
</web-app>
Java文档
public
class CServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /*1、得到ServletContext * 2、调用它的getInitParameter(String)得到初始化参数 * */ ServletContext application = this.getServletContext(); String value = application.getInitParameter("context-param"); System.out.println(value); } }

启动Tomcat,访问localhost:8080/CServlet,控制台输出“context-value”。

5)获取相关资源

 1 /*
 2 *使用ServletContext获取资源路径
 3 * */
 4 @WebServlet(name = "DServlet")
 5 public class DServlet extends HttpServlet {
 6     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 7         /*
 8         * 得到的是绝对路径
 9         * /Users/Shared/练习/day_03/out/artifacts/day_03_war_exploded/index.jsp
10         * */
11         String path = this.getServletContext().getRealPath("index.jsp");
12         System.out.println(path);
13         /*
14         * 获取资源的路径后,再创建出输入流对象
15         * */
16         InputStream input = this.getServletContext().getResourceAsStream("index.jsp");
17         /*
18         *获取当前路径下所有资源的路径
19         * */
20         Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
21         System.out.println(paths);
22     }
23 }

6)访问量统计小练习

  一个项目中所有的资源被访问都要对访问量进行累加。

  创建一个int类型的变量,用来保存访问量,然后把它保存到ServletContext的域中,这样可以保存所有的Servlet都可以访问到。

  • 最初时,ServletContext中没有保存访问量相关的属性
  • 当本站第一次被访问时,创建一个变量,设置其值为1;保存到ServletContext中;
  • 当以后的访问时,就可以从ServletContext中获取这个变量,然后再其基础上加1.
  • 获取ServletContext对象,查看是否存在名为count的属性,如果存在,说明不是第一次访问,如果不存在,说明是第一次访问。

1、第一次访问:调用ServletContext的setAttribute()传递一个属性,名为count,值为1;

2、第2~n次访问,调用ServletContext的getAttribute()方法获取原来的访问量,给访问量加1,再调用ServletContext的setAttribute()方法完成设置。

/**
 * 统计访问量
 */
@WebServlet(name = "Servlet")
public class Servlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext app = this.getServletContext();
        Integer count = (Integer) app.getAttribute("count");
        if (count==null){
            app.setAttribute("count",1);
        }else {
            app.setAttribute("count",count+1);
        }
        /*
        * 向浏览器输出
        * 需要使用响应对象
        * */
        PrintWriter pw = response.getWriter();
        pw.print("<h1>"+count+"</h>");
    }
}

注:当服务器关闭,计数重新开始。

7、获取类路径下的资源

  获取类路径资源,类路径对一个JavaWeb项目而言,就是/WEB-INF/classes和/WEB-INF/lib每个jar包。

  Class、ClassLoader

/*
* 演示获取类路径下的资源
* */
@WebServlet(name = "Servlet",urlPatterns = "/Servlet")
public class Servlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /*
        * 1、得到ClassLoader
        * 先得到Class,再得到ClassLoader
        * 2、调用器getResourceAsStream(),得到一个InputStream
        * */
//        ClassLoader c1 = this.getClass().getClassLoader();
        //相对/class
//        InputStream input = c1.getResourceAsStream("a.txt");
        Class c = this.getClass();
        //相对当前.class文件所在目录
        InputStream input = c.getResourceAsStream("a.txt");
        String str = IOUtils.toString(input,"utf-8");//问题所在之处,如何解决?
        System.out.println(str);
    }
}

 

  

posted @ 2017-10-03 20:03  gdwkong  阅读(443)  评论(0编辑  收藏  举报