zoukankan      html  css  js  c++  java
  • Servlet入门实践

    1servlet介绍:

      Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。 

    手把手教你建立一个继承servlet的类: 

      (1)建立一个servlet类:

    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    public class ServletStudy extends HttpServlet {
    
        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();
        }
    
        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();
        }
    
    }

      (2)修改web.xml

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <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"
             version="3.0">
      <display-name>Archetype Created Web Application</display-name>
    
    
      <!--servlet-->
      <servlet>
        <description>This is the description of my J2ee component</description>
        <display-name>This is the display name of my J2ee component</display-name>
        <servlet-name>ServletStudy</servlet-name>
        <servlet-class>com.servlet.study.ServletStudy</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>ServletStudy</servlet-name>
        <url-pattern>/servlet/ServletStudy</url-pattern>
      </servlet-mapping>
    <!--同一个Servlet可以被映射到多个URL上,也可以用通配符,一种是*.扩展名,一种是/* -->
    <servlet-mapping>
    <servlet-name>ServletStudy</servlet-name>
    <url-pattern>/servlet/1.html</url-pattern>
    </servlet-mapping>
    <!-- 将ServletDemo2配置成缺省Servlet -->
    <servlet-mapping>
    <servlet-name>ServletStudy</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>
    </web-app>

    或者在类定义上加上webServlet的注解(注意两者只能有一个) 

    WebServlet("/ServletStudy")//设置servlet的访问路径为/ServletStudy;或者这样写@WebServlet(name="ServletStudy",urlPatterns={"/ServletStudy"})

    2servlet的路径映射:

    <url-pattern>/ServletStudy</url-pattern>或者:@WebServlet(urlPatterns={"/ServletStudy"})
    匹配方式 url-pattern 地址栏
    精确匹配 /ServletStudy
    /ServletStudy/test
    http://localhost:8080/HttpSer/ServletStudy
    http://localhost:8080/HttpSer/ServletStudy/test
    模糊匹配 /*
    /ServletStudy/*
    /*.do
    http://localhost:8080/HttpSer/任意路径
    http://localhost:8080/HttpSer/ServletStudy/任意路径
    http://localhost:8080/HttpSer/任意路径.do

    注意 
    1)url-pattern要么以 / 开头,要么以*开头。 例如, TestServlet是非法路径。 
    2)不能同时使用两种模糊匹配,例如 /TestServlet/*.do是非法路径 
    3)当有输入的URL有多个servlet同时被匹配的情况下: 
      3.1 精确匹配优先。(长的最像优先被匹配) 
      3.2 以后缀名结尾的模糊url-pattern优先级最低!!!

    3servlet生命周期:

      1. 生命周期的引入: 
        Servlet的生命周期: servlet类对象什么时候创建,什么时候调用什么方法,什么时候销毁。 
        以前的对象: new Student(); stu.study(); stu=null; 
        Servlet程序的生命周期由tomcat服务器控制的!!!!
      2. Servlet重要的四个生命周期方法: 
        构造方法: 创建servlet对象的时候调用。默认情况下,第一次访问servlet的时候创建servlet对象 只调用1次。证明servlet对象在tomcat是单实例的。 
        init方法: 创建完servlet对象的时候调用。只调用1次。 
        service方法: 每次发出请求时调用。调用n次。 
        destroy方法: 销毁servlet对象的时候调用。停止服务器或者重新部署web应用时销毁servlet对象。只调用1次。
      3. 代码演示:
    @WebServlet(name="TestServlet",urlPatterns={"/TestServlet"})
    public class TestServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
         int i=0;
        /**
         * 1.构造方法,只被调用一次
         */
        public TestServlet() {
            super();
            System.out.println("构造方法>>>>");
        }
        /**
         * 2.init初始化方法,在构造方法后只被调用一次
         * 有参数的init方法会调用init方法;;一般覆盖无参数的init方法;
         */
         @Override
        public void init() throws ServletException {
            // TODO Auto-generated method stub
            super.init();
            System.out.println("inti>>>>");
        }
      /**
         * 3.service方法,发生请求和响应时调用的方法,次数不限
         * 一般是重写doget和dopost,此去只是方便演示
         */
        @Override
        protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
            System.out.println("service>>>" +i++);
        }
      /**
       * 4.destory方法,只有在停止服务器和重新部署web应用时调用
       */
        @Override
        public void destroy() {
            System.out.println("destory");
            super.destroy();
        }
    }
    #输出结果:http://localhost:8080/HttpSer/TestServlet。连续访问四次,得到下面的结果:
    构造方法>>>>
    inti>>>>
    service>>>0
    service>>>1
    service>>>2
    service>>>3
    Oct 11, 2015 8:53:52 PM org.apache.catalina.core.StandardContext reload
    INFO: Reloading Context with name [/HttpSer] has started
    destory
    1. 伪代码演示:
    Tomtcat内部代码运行:
    1)通过映射找到到servlet-class的内容,字符串: com.rlovep.serlvet.TestServlet
    2)通过反射构造TestServlett对象
         2.1 得到字节码对象
             Class clazz = class.forName(" com.rlovep.serlvet.TestServlet");
        2.2 调用无参数的构造方法来构造对象
              Object obj = clazz.newInstance();     ---1.servlet的构造方法被调用
    3)创建ServletConfig对象,通过反射调用init方法
        3.1 得到方法对象
             Method m = clazz.getDeclareMethod("init",ServletConfig.class);
         3.2 调用方法
            m.invoke(obj,config);           --2.servlet的init方法被调用
    4)创建request,response对象,通过反射调用service方法
         4.1 得到方法对象
            Methodm m =clazz.getDeclareMethod("service",HttpServletRequest.class,HttpServletResponse.class);
        4.2 调用方法
        m.invoke(obj,request,response); --3.servlet的service方法被调用
    5)当tomcat服务器停止或web应用重新部署,通过反射调用destroy方法
         5.1 得到方法对象
            Method m = clazz.getDeclareMethod("destroy",null);
        5.2 调用方法
             m.invoke(obj,null);          --4.servlet的destroy方法被调用

    4自动加载servlet:

    默认情况下,第一次访问servlet的时候创建servlet对象。如果servlet的构造方法或init方法中执行了比较多的逻辑代码,那么导致用户第一次访问sevrlet的时候比较慢。 
    改变servlet创建对象的时机: 提前到加载web应用的时候!!! 
    在servlet的配置信息中,加上一个或者加上注解(loadOnStartup=1)即可:

    <servlet>
      <!-- servlet的内部名称,自定义。尽量有意义 -->
           <servlet-name>TestServlet</servlet-name>
            <!-- servlet的类全名: 包名+简单类名 -->
           <servlet-class>com.rlovep.serlvet.TestServlet</servlet-class>
           <load-on-startup>1</load-on-startup>
      </servlet>
    或者:
    @WebServlet(name="TestServlet",loadOnStartup=1,urlPatterns={"/TestServlet"})

    5多用户问题:

    注意: servlet对象在tomcat服务器是单实例多线程的。可以有多个用户; 
    因为servlet是多线程的,所以当多个线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。 
    解决办法: 
    1)把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步) 
    2)建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

    6Servlet常用对象:

    servlet:有几个比较有用的对象:

    1.HttpServletRequest   请求对象   http协议中已讲
    2.HttpServletResponse  响应对象  http协议中已讲
    3.ServletConfig       servlet配置对象
    4.ServletContext    Servlet的上下文对象。对整个web应用有效
    5.HttpSession        会话对象,当一个用户向服务器发送第一个请求时,服务器为其建立一个session,并为此session创建一个标识号;

    ServletConfig对象介绍:

    ServletConfig对象: 主要是用于加载servlet的初始化参数。在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象) 
    可以直接从getServletConfig方法;或者自己在有参的init中获得 . 
    在web.xml中创建参数:一样有两种方法:

    <servlet>
      <!-- servlet的内部名称,自定义。尽量有意义 -->
           <servlet-name>TestConfig</servlet-name>
            <!-- servlet的类全名: 包名+简单类名 -->
           <servlet-class>com.rlovep.serlvet.TestConfig</servlet-class>
           <init-param>
                <param-name>name</param-name>
                <param-value>peace</param-value>
           </init-param>
      </servlet>
    或者:
    @WebServlet(urlPatterns={"/TestConfig"},
            initParams={@WebInitParam(name="driver",value="com.mysql*")
                        ,@WebInitParam(name="url",value="jdbc*"),
                        @WebInitParam(name="user",value="root"),
                        @WebInitParam(name="pass",value="123456")})

    测试如下:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            ServletConfig servletConfig = getServletConfig();
            //得到servlet的名字
            System.out.println(servletConfig.getServletName());
            //根据参数名获取参数值
            String name=servletConfig.getInitParameter("user");
            System.out.println(name+">>>>>");
            //获取所有参数名称
            Enumeration<String> names = servletConfig.getInitParameterNames();
            while(names.hasMoreElements()){
                String s=names.nextElement();
                System.out.println(s+"="+servletConfig.getInitParameter(s));
            }
        }

    ServletContext对象介绍:

    1. 引入 
    ServletContext对象 ,叫做Servlet的上下文对象。表示一个当前的web应用环境。一个web应用中只有一 个ServletContext对象。 
    2. 对象引用的得到 
    创建时机:加载web应用时创建ServletContext对象。 
    得到对象: 从ServletConfig对象的getServletContext方法得到或者直接调用ServletContext servletContext = getServletContext(); 
    3. 核心api

    java.lang.String getContextPath()   --得到当前web应用的路径
    java.lang.String getInitParameter(java.lang.String name)  --得到web应用的初始化参数
    java.util.Enumeration getInitParameterNames()
    void setAttribute(java.lang.String name, java.lang.Object object) --域对象有关的方法
    java.lang.Object getAttribute(java.lang.String name)
    void removeAttribute(java.lang.String name)
    RequestDispatcher getRequestDispatcher(java.lang.String path) --转发(类似于重定向)
    java.lang.String getRealPath(java.lang.String path)     --得到web应用的资源文件
    java.io.InputStream getResourceAsStream(java.lang.String path)

    4. 演示如下

    ServletContext servletContext = getServletContext();
            //得到当前web应用路径
            System.out.println("路径:"+servletContext.getContextPath());
            //根据参数名获得参数值
            System.out.println("AAA="+servletContext.getInitParameter("AAA"));
            //获取所有参数名称
            Enumeration<String> names = servletContext.getInitParameterNames();
            while(names.hasMoreElements()){
                String s=names.nextElement();
                System.out.println(s+":"+servletContext.getInitParameter(s));
            }
            //设置域对象,整个web应用有效
            servletContext.setAttribute("name","peace");
            servletContext.setAttribute("age", "23");
            //获得域对象
            System.out.println("name"+servletContext.getAttribute("name"));
            System.out.println("age"+servletContext.getAttribute("age"));
            //删除域对象
            servletContext.removeAttribute("age");
            System.out.println("age"+servletContext.getAttribute("age"));

    7.转发和重定向;

    域对象介绍:

    域对象:作用是用于保存数据,获取数据。可以在不同的动态资源(servlet)之间共享数据。 
    案例:

    #通过重定向,使用实体内容传递数据,一般只能存储字符
    Servlet1 传数据:name=eric 
            response.sendRedirect("/Servlet2?name=eric")            
    Servlet2接收:
            String request.getParameter("name");
    #通过域对象传递:可以传递任何数据;
    ServletContext就是一个域对象,上面有介绍怎么用
        保存数据:void setAttribute(java.lang.String name, java.lang.Object object)
        获取数据: java.lang.Object getAttribute(java.lang.String name)
        删除数据: void removeAttribute(java.lang.String name)
    ServletContext域对象:作用范围在整个web应用中有效!!!
    所有域对象:
    HttpServletRequet 域对象  测试;
    ServletContext域对象
    HttpSession 域对象
    PageContext域对象

    重定向:

    重定向是服务器告诉浏览器,重新请求另一页面,请求信息丢失更新 
    a)地址栏会改变,变成重定向到地址。 
    b)重定向可以跳转到当前web应用,或其他web应用,甚至是外部域名网站。 
    c)不能在重定向的过程,把数据保存到request中。 
    测试如下:

    1.建立一个TestRedect servlet:
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            /**
             * 保存数据到request域对象
             */
            request.setAttribute("name", "rose");
                //重定向
                    /**
                     * 注意:可以跳转到web应用内,或其他web应用,甚至其他外部域名。
                     */
            //request域数据会丢失
            response.sendRedirect("/HttpSer/GetData");
            //重定向到外部域名:
            //response.sendRedirect("www.baidu.com");
        }
    2.建立一个GetData的servlet
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            PrintWriter out = response.getWriter();
            out.println("hello");
            System.out.println("获得域对象"+request.getAttribute("name"));
        }

    现象如下: 
    1.地址栏从http://localhost:8080/HttpSer/TestRedect变为http://localhost:8080/HttpSer/GetData; 
    2.request域对象数据丢失:获得域对象null

    转发:

    转发是服务器将请求信号封装后转发到另一个servlet页面,请求信息会保存 
    a)地址栏不会改变 
    b)转发只能转发到当前web应用内的资源 
    c)可以在转发过程中,可以把数据保存到request域对象中 
    测试如下:

    1.建立一个TestRedect servlet:
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        /**
             * 保存数据到request域对象
             */
            request.setAttribute("name", "rose");
            //转发    
            /**
             * 注意:不能转发当前web应用以外的资源。
             */
            /*RequestDispatcher rd = this.getServletContext().getRequestDispatcher("/GetDataServlet");
            rd.forward(request, response);*/
            this.getServletContext().
            getRequestDispatcher("/GetData").forward(request, response);
        }
    2.建立一个GetData的servlet
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            PrintWriter out = response.getWriter();
            out.println("hello");
            System.out.println("获得域对象"+request.getAttribute("name"));
        }

    现象如下: 
    1.地址栏没有变化 
    2.request域对象数据没有丢失:获得域对象rose 
    来自一条小鲨鱼(rlovep.com) 

    8.servlet编写过滤器

    建立一个类:

    import javax.servlet.*;
    
    public class LogFilter implements Filter {
        public void  init(FilterConfig config) throws ServletException {
            // 获取初始化参数
            String site = config.getInitParameter("Site");
    
            // 输出初始化参数
            System.out.println("网站名称: " + site);
        }
        public void  doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
    
            // 输出站点名称
            System.out.println("站点网址:http://www.runoob.com");
    
            // 把请求传回过滤链
            chain.doFilter(request,response);
        }
        public void destroy( ){
            /* 在 Filter 实例被 Web 容器从服务移除之前调用 */
        }
    }

    修改web.xml:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <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"
             version="3.0">
      <display-name>Archetype Created Web Application</display-name>
    
      <!--过滤器-->
      <filter>
        <filter-name>LogFilter</filter-name>
        <filter-class>com.servlet.study.LogFilter</filter-class>
        <init-param>
          <param-name>Site</param-name>
          <param-value>菜鸟教程</param-value>
        </init-param>
      </filter>
      <filter-mapping>
        <filter-name>LogFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
    
      <!--servlet-->
      <servlet>
        <description>This is the description of my J2ee component</description>
        <display-name>This is the display name of my J2ee component</display-name>
        <servlet-name>ServletStudy</servlet-name>
        <servlet-class>com.servlet.study.ServletStudy</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>ServletStudy</servlet-name>
        <url-pattern>/servlet/ServletStudy</url-pattern>
      </servlet-mapping>
      <!--同一个Servlet可以被映射到多个URL上,也可以用通配符,一种是*.扩展名,一种是/* -->
      <servlet-mapping>
        <servlet-name>ServletStudy</servlet-name>
        <url-pattern>/servlet/1.html</url-pattern>
      </servlet-mapping>
      <!-- 将ServletDemo2配置成缺省Servlet -->
      <servlet-mapping>
        <servlet-name>ServletStudy</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    
      
    </web-app>

    访问 

    http://localhost:8080/servlet/ServletStudy

    转自:https://blog.csdn.net/peace1213/article/details/49942971

  • 相关阅读:
    easyUI的formatter使用
    tomcat的CATALINA_HOME可以不用设置
    关于json解析中 解析多重json对象
    "i++"和"++i"浅析
    poj1050 To the Max(降维dp)
    2017年暑假ACM集训日志
    codevs1228 (dfs序+线段树)
    密钥登录服务器
    使用iwd联网
    idea和gradle创建android遇到的网络问题
  • 原文地址:https://www.cnblogs.com/heqiyoujing/p/9511212.html
Copyright © 2011-2022 走看看