• Java之Servlet


    Servlet规范了JavaWeb项目的结构
    Servlet的规范约束了服务器如何来实现Servlet规范,如何解析JavaWeb项目的结构。

    Java就是通过接口来约束

    Servlet规范的jar就在tomcat的lib目录下面,文件名:servlet-api.jar,其中还有webSocket-api.jar
    创建servlet先只用servlet-api.jar即可。

    一、开始使用Servlet规范开发JavaWeb项目:

    然后开始配置:

    注意:<url-pattern>里面的资源名称必须要用"/"开头

    源码:

     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
     5                       http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     6   version="3.1"
     7   metadata-complete="true">
     8   
     9   <servlet>
    10       <!-- 配置Servlet类的全限定名 -->
    11       <servlet-name>HelloServlet</servlet-name>
    12       <servlet-class>com.demo.testServlet.HelloServlet</servlet-class>
    13   </servlet>
    14   
    15   <!-- Servlet映射,用来访问资源名称,通过helloHeYang就可以访问资源 -->
    16   <servlet-mapping>
    17       <servlet-name>HelloServlet</servlet-name>
    18       <url-pattern>/helloHeYang</url-pattern>
    19   </servlet-mapping>
    20 
    21    
    22 </web-app>

    另外:

    Servlet中的方法含义:

    public void init(ServletConfig config):Servlet的初始化操作方法

    public void service(ServletRequest req, ServletResponse res):处理请求和响应的方法

    public void destroy():资源回收

    public ServletConfig getServletConfig():获取Servlet的配置信息

    public String getServletInfo():获取Servlet的相关的信息(作者/版本)

     1     @Override
     2     public void init(ServletConfig config) throws ServletException {
     3         // TODO Auto-generated method stub
     4         System.out.println("init初始化方法");
     5     }
     6 
     7     @Override
     8     public ServletConfig getServletConfig() {
     9         // TODO Auto-generated method stub
    10         System.out.println("getServletConfig获取Servlet配置信息");
    11         return null;
    12     }
    13 
    14     @Override
    15     public void service(ServletRequest req, ServletResponse res)
    16             throws ServletException, IOException {
    17         // TODO Auto-generated method stub
    18         System.out.println("service(ServletRequest req, ServletResponse res)处理请求和响应");
    19     }
    20 
    21     @Override
    22     public String getServletInfo() {
    23         // TODO Auto-generated method stub
    24         System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");
    25         return null;
    26     }
    27 
    28     @Override
    29     public void destroy() {
    30         // TODO Auto-generated method stub
    31         System.out.println("destroy():资源回收");
    32     }

    启动tomcat服务器之后,然后打开浏览器:

    ---------------------------------------------------------------------------------------------------------------

    Servlet的生命周期方法:

    public void init(ServletConfig config):Servlet的初始化操作方法(在被第一次访问的时候执行)

    public void service(ServletRequest req, ServletResponse res):处理请求和响应的方法(每次访问都会执行)

    public void destroy():资源回收(在服务器正常关闭的时候执行)

    ----------------------------------------------------------------------------------------------

    Servlet的生命周期方法的执行顺序:

    Servlet是单例的(在其整个应用中只有一个对象)

    执行顺序:

    1.调用公共无参数的构造器创建对象(只会在第一次访问的时候执行)

    2.执行init方法(只会在第一次访问的时候执行)

    3.执行服务方法(每次访问都会执行)

    4.执行destroy方法(在服务器被正常关闭的时候执行),不要将关闭资源的操作放到该方法中

    注意:在Servlet类中必须保证有一个公共的无参数的构造器(使用反射创建对象,类的Class实例.newInstance())

       类中的默认构造器的访问权限和类的访问权限一致

    二、Servlet的请求流程:

    1.通过浏览器发送请求

    http://localhost:8080/demo/helloHeYang

    2.Tomcat解析请求路径

    协议:http

    主机地址:localhost

    端口:8080,确定访问的是该主机上的哪一个程序

    上下文的路径:server.xml文件中配置的信息,/demo

    资源名称:访问的资源是什么,/helloHeYang,在项目下的web.xml文件中配置的<url-pattern>的文本

    3.根据上下文的路径去找到server.xml文件中的<Context>节点,确定项目的根路径

        如果没有找到,返回404错误

        反之,执行第4步

    4.根据资源名称去项目下的WEB-INF下的web.xml文件中找到<url-pattern>文本内容为/hello的节点

    可以确定找到Servlet对应的<servlet-name>

       

    5.根据<Servlet-name>找到Servlet 的全限定名

    6.使用反射创建对象

    Tomcat中的缓存池:

    Map<String, Servlet> cache=new HashMap<>();

    Servlet obj = cache.get("类的全限定名");

    if(obj==null){

         //如果是第一次访问:

         Object obj2 = Class.forName("类的全限定名").newInstance();

        //将创建好的对象放到缓存池中

        cache.put("类的全限定名",obj2);

    } else {

        //不是第一次访问:

        //GOTO 7;

    }

    7.调用init方法进行初始化操作

        创建ServletConfig对象,调用init(config)

    8.执行service(ServletRequest req, ServletResponse resp),

        执行之前先创建ServletRequest , ServletResponse 两个对象

    9.给浏览器一个响应信息

    三、Servlet初始化参数

    在Servlet类中定义初始化参数,会将代码写死,应该将配置信息放到web.xml文件中

    问题:如何将配置好的初始化参数获取到?

    解决方案:使用ServletConfig来获取

    ------------------------------------------------------------------------------------

    ServletConfig中的常用方法:

    public String getServletName():获取Servlet的名称,配置中的<servlet-name>文本

    public ServletContext getServletContext():获取Servlet的上下文信息

    -------------------------------------

    获取初始化参数的相关方法:

    public String getInitParameter(String name):根据指定的名称获取当前的Servlet中的初始化参数

    public Enumeration<String> getInitParameterNames():获取当前Servlet中的所有的初始化参数的名称

    Enumeration:迭代器(Iterator)

    关键代码:

     1     @Override
     2     public void init(ServletConfig config) throws ServletException {
     3         // TODO Auto-generated method stub
     4         System.out.println("init初始化方法");
     5         
     6         // 初始化方法的参数
     7         System.out.println(config.getServletName());
     8         System.out.println(config.getInitParameter("encoding"));
     9         System.out.println("----------------------------------");
    10         Enumeration<String> inits = config.getInitParameterNames();
    11         while (inits.hasMoreElements()) {
    12             String name = inits.nextElement();
    13             System.out.println("name");
    14             System.out.println(name+"--->"+config.getInitParameter(name));
    15         }
    16         
    17     }

     ------------------------------------------------------------

    目前的初始化参数只是为当前的Servlet做的配置,如果在多个Servlet中有相同的配置,那么该配置就重复了---解决方案(使用全局的初始化参数)。

    四、Servlet继承体系

    其实我们实际开发中需要继承HttpServlet这个关键的类,下面我们就来自己实现这个类,然后体会它里面的继承体系,了解它内部的关联性。

    首先是自定义一个 HelloServlet,并且实现Servlet,ServletConfig两个接口以及接口的所有的方法。

     1 import java.io.IOException;
     2 import java.util.Enumeration;
     3 
     4 import javax.servlet.Servlet;
     5 import javax.servlet.ServletConfig;
     6 import javax.servlet.ServletContext;
     7 import javax.servlet.ServletException;
     8 import javax.servlet.ServletRequest;
     9 import javax.servlet.ServletResponse;
    10 
    11 public class HelloServlet implements Servlet,ServletConfig{
    12 
    13     // 声明私有的全局变量
    14     private ServletConfig config;
    15     
    16     public void init(){
    17         // 事实上,如果子类没有用super方法,就不会被调用
    18         System.out.println("调用了父类的init方法");
    19     }
    20     
    21     @Override
    22     public void init(ServletConfig config) throws ServletException {
    23         // TODO Auto-generated method stub
    24         System.out.println("HelloServlet:init初始化方法");
    25         this.config = config;
    26         init();
    27     }
    28     @Override
    29     public ServletConfig getServletConfig() {
    30         // TODO Auto-generated method stub
    31         System.out.println("HelloServlet:getServletConfig获取Servlet配置信息");
    32         return config;// 在这里直接返回ServletConfig对象
    33     }
    34     @Override
    35     public void service(ServletRequest req, ServletResponse res)
    36             throws ServletException, IOException {
    37         // TODO Auto-generated method stub
    38         System.out.println("HelloServlet:service(ServletRequest req, ServletResponse res)处理请求和响应");
    39         
    40     }
    41     @Override
    42     public String getServletInfo() {
    43         // TODO Auto-generated method stub
    44         System.out.println("getServletInfo():获取Servlet的相关的信息(作者/版本)");
    45         return null;
    46     }
    47     @Override
    48     public void destroy() {
    49         // TODO Auto-generated method stub
    50         System.out.println("HelloServlet:destroy():资源回收");
    51     }
    52 
    53     
    54     // 为什么要实现ServletConfig的接口,为了使用接口里面的方法,方便子类调用
    55     
    56     @Override
    57     public String getServletName() {
    58         // TODO Auto-generated method stub
    59         return config.getServletName();
    60     }
    61 
    62     @Override
    63     public ServletContext getServletContext() {
    64         // TODO Auto-generated method stub
    65         return config.getServletContext();
    66     }
    67 
    68     @Override
    69     public String getInitParameter(String name) {
    70         // TODO Auto-generated method stub
    71         return config.getInitParameter(name);
    72     }
    73 
    74     @Override
    75     public Enumeration<String> getInitParameterNames() {
    76         // TODO Auto-generated method stub
    77         return config.getInitParameterNames();
    78     }
    79 
    80 }

    然后再创建一个MyHttpServlet继承HelloServlet,来处理http请求和响应的类

     1 import java.io.IOException;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.ServletRequest;
     5 import javax.servlet.ServletResponse;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 // 单独一个子类处理service方法
    10 
    11 public class MyHttpServlet extends HelloServlet {
    12     @Override
    13     public void service(ServletRequest req, ServletResponse res)
    14             throws ServletException, IOException {
    15         // TODO Auto-generated method stub
    16         
    17         
    18         // 如果要访问http协议的方法,需要强转类型
    19         HttpServletRequest request = (HttpServletRequest) req;
    20         HttpServletResponse response = (HttpServletResponse) res;
    21         service(req, res);
    22     }
    23     
    24     public void service(HttpServletRequest req,HttpServletResponse res){
    25 //        super.service(req, res);
    26     }
    27 }

    最后再创建一个子类HelloSubServlet,直接继承自MyHttpServlet,注意不是继承最前面的HelloServlet基类哦。

     1 import java.io.IOException;
     2 
     3 import javax.servlet.ServletException;
     4 import javax.servlet.ServletRequest;
     5 import javax.servlet.ServletResponse;
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 public class HelloSubServlet extends MyHttpServlet {
    10     
    11     /*
    12     @Override
    13     public void init(ServletConfig config) throws ServletException {
    14         // TODO Auto-generated method stub
    15         super.init(config);
    16     }
    17     * 由于config已经作为父类中全局变量来处理了,所以以上方法其实是多余了
    18     * 但是又需要调用父类的初始化servlet方法init(ServletConfig...)方法,
    19     * 如果子类没有实现,就会去找父类方法,如果子类实现了,而子类中没有用super调用父类方法,父类方法就不会执行
    20     * 所以就采用在父类中声明一个init空的方法,然后在init(ServletConfig...)调用,然后子类只要重写init()方法即可
    21     * 
    22     * 但是,前提是:如果子类重写了init(ServletConfig...),就一定要记得要用super调用父类同样的方法
    23     */
    24     
    25     @Override
    26     public void init() {
    27         // 所有初始化的方法写在这里
    28         System.out.println("HelloSubServlet初始化方法");
    29     }
    30     
    31     @Override
    32     public void service(HttpServletRequest req, HttpServletResponse res) {
    33         super.service(req, res);
    34         
    35         // 因为子类实现了ServletConfig的接口方法,所以可以直接调用即可。
    36         String name = this.getInitParameter("name");
    37         System.out.println(name);
    38     };   40 }

    然后仔细体会他们之间的关系。

    下面是展示直接开发需要知道的继承体系:

    五、HttpServletRequest常用的方法

    HttpServletRequest接口:处理基于HTTP协议的请求信息

    常用的方法:

    String getContextPath()  :获取上下文的路径

    String getHeader(String name)  :根据名称获取请求头信息

    String getMethod()  :获取请求的类型

    String getRequestURI()  :获取请求的资源路径

    StringBuffer getRequestURL():获取请求的全路径

    String getParameter(String name)  :根据名称获取请求参数的值

    String getRemoteAddr()  :获取请求的客户端的地址

    ---------------------------------------------------------------

    ServletConfig中的getInitParameter(String name)

    获取web.xml文件中配置的初始化参数的值

    HttpServletRequest中的getParameter(String name)

    获取用户提交的参数值

    六、简单案例

    一般情况下,一个表单对应一个Servlet。

    在webapp目录下创建一个register.html

     1 <!DOCTYPE html>
     2 <html>
     3 <head>
     4 <meta charset="UTF-8">
     5 <title>Insert title here</title>
     6 </head>
     7 <body>
     8 <!-- action:表单提交到哪个页面
     9 method: 提交方式
    10     get:提交之后,表单中的数据会显示到地址栏中(不安全)
    11     post:提交之后,表单中的数据不会显示到地址中
    12 enctype:application/x-www-form-urlencoded(默认)
    13     上传文件:multipart/form-data
    14  -->
    15 <form action="/demo/register" method="post" enctype="application/x-www-form-urlencoded">
    16 姓名:<input type="text" name="name">
    17 <br>
    18 密码:<input type="password" name="password">
    19 <br>
    20 <br>
    21 性别:
    22 <input type="radio" name="sex" value="男" checked>23 <input type="radio" name="sex" value="女">24 <br>
    25 职业:
    26 <input type="checkbox" name="java" value="java">Java
    27 <input type="checkbox" name="c" value="c">C
    28 <input type="checkbox" name="IOS" value="ios">IOS
    29 
    30 <br>
    31 <br>
    32 城市:
    33 <select name="address">
    34 <option value="1">成都</option>
    35 <option value="2" selected="selected">上海</option>
    36 <option value="3">广州</option>
    37 </select>
    38 
    39 <br>
    40 <br>
    41 评论:
    42 <textarea name="textarea" rows="10" cols="40">在这里输入文本。。。</textarea>
    43 
    44 <br>
    45 <br>
    46 <input type="submit" value="提交">
    47 <input type="reset" value="重置">
    48 <br>
    49 
    50 </form>
    51 
    52 </body>
    53 </html>

    然后创建一个RegisterServlet.class

     1 package com.demo.request;
     2 
     3 import java.io.IOException;
     4 import java.util.Map;
     5 
     6 import javax.servlet.ServletException;
     7 import javax.servlet.http.HttpServlet;
     8 import javax.servlet.http.HttpServletRequest;
     9 import javax.servlet.http.HttpServletResponse;
    10 
    11 public class RegisterServlet extends HttpServlet {
    12 
    13     /**
    14      * 
    15      */
    16     private static final long serialVersionUID = 1L;
    17 
    18     
    19     @Override
    20     protected void service(HttpServletRequest req, HttpServletResponse resp)
    21             throws ServletException, IOException {
    22         // TODO Auto-generated method stub
    23         
    24         System.out.println("开始执行这段代码。");
    25         
    26         // 1、获取请求参数
    27         String name = req.getParameter("name");
    28         String password = req.getParameter("password");
    29         
    30         System.out.println("name"+name+" password"+password);
    31         
    32         Map<String,String[]> map = req.getParameterMap();
    33         String name2 = map.get("name")[0];
    34         System.out.println("name2"+name2);
    35         // 2、调用方法来处理业务逻辑
    36         
    37         // 3、控制页面跳转
    38     }
    39     
    40 }

    还要在web.xml中写好配置代码:

     1 <!-- 配置的是子类Servlet -->
     2   <servlet>
     3       <!-- 配置Servlet类的全限定名 -->
     4       <servlet-name>RegisterServlet</servlet-name>
     5       <servlet-class>com.demo.request.RegisterServlet</servlet-class>
     6       <init-param>
     7           <param-name>encoding</param-name>
     8           <param-value>UTF-8</param-value>
     9           <param-name>name</param-name>
    10           <param-value>hahaha</param-value>
    11       </init-param>
    12   </servlet>
    13   
    14   <!-- Servlet映射,用来访问资源名称,通过helloHeYang就可以访问资源 -->
    15   <servlet-mapping>
    16       <servlet-name>RegisterServlet</servlet-name>
    17       <url-pattern>/register</url-pattern>
    18   </servlet-mapping>

    Toncat中默认处理请求参数的编码方式默认是ISO-8859-1,只有一个字节,所以中文会乱码。

    --解决方案:

      方式一:

      方式二:

        Post:

          // 将处理请求参数的编码改为UTF-8

          req.setCharacterEncoding("UTF-8");

        Get:

          在service.xml文件中需要设置的配置(可能默认是URIEncoding="ISO-8859-1"):

    1 <Connector port="8080" protocol="HTTP/1.1"
    2                connectionTimeout="20000"
    3                redirectPort="8443"  URIEncoding="UTF-8"/>

    另外规定:提交表单只能用POST请求。

    HttpServletResponse接口:处理基于HTTP协议的响应信息

    常用的方法:

    PrintWriter getWriter()  :向页面输出字符流

    ServletOutputStream getOutputStream()  :向页面输出字节流,实现文件下载

    以上两个方法不能被同时调用

     void setCharacterEncoding(String charset)  :设置响应信息的字符编码

    向页面输出一个html内容,必须要下面两个设置

    resp.setCharacterEncoding("UTF-8");

    resp.setContentType("text/html");:MIME的类型

    上面两个设置可以合在一行代码中

    resp.setContentType("text/html; charset=UTF-8");

             // 处理响应
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter out = resp.getWriter();
            
            out.print("<thml>");
            out.print("<head>");
            out.print("<title>");
            out.print("你好");
            out.print("</title>");
            out.print("</head>");
            out.print("<body>");
            out.print("<font color='red'>你好</font>,世界");
            out.print("</body>");
            out.print("</html>");    
  • 相关阅读:
    java 事务
    JPA概述以及它和Hibernate之间的关系
    [转]JavaWeb之 Servlet执行过程 与 生命周期
    j2EE的web.xml详解
    安装PyTorch 0.4.0
    [转]springmvc常用注解标签详解
    hibernate的dialect大全
    Hibernate快速入门
    DBUtils使用详解
    用户密码初始化
  • 原文地址:https://www.cnblogs.com/goodboy-heyang/p/6477113.html
Copyright © 2020-2023  润新知