• 10 Servlet


    引言

    本章节,将进入javaWeb开发技术中,最核心的部分,我们将使用最原始的技术上构建Web系统,这部分原始的技术在实际开发的中并不会直接使用,通常都是使用基于此技术封装的框架。简单的说就是,它是JavaWeb的本质,是每个Java程序员都应该理解和掌握的内容。

    一、什么1是JavaWeb?

    web(World Wide Web)即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统。是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图形化的、易于访问的直观界面,其中的文档及超级链接将Internet上的信息节点组织成一个互为关联的网状结构。

    通俗的说 就是网站。

    在Sun的Java Servlet规范中,对Java Web应用作了这样定义:“Java Web应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的 Servlet容器(Tomcat) 中运行。”Java Web应用中可以包含Servlet、JSP、实用类、静态文档如HTML、图片等描述Web应用的信息(web.xml).

    通俗的说 就是用Java相关技术(比如 _servlet jdbc jsp _等 )开发的web应用。

    JavaEE有是什么呢?
    Java语言在企业级开发中使用的技术规范的总和,一共规定了13项大的规范。
    1、JDBC(java Database Connectivity)2、JNDI(Java Name and Directory Interface)3、EJB(Enterprise JavaBean)4、RMI(RemoteMethod Invoke)5、Java IDL(接口定义语言)/CORBA6、JSP(Java Server Pages)7、Java Servlet、8、XML(Extensible Markup Language)9、JMS(Java Message Service)10、JTA(Java Transaction Architecture)11、JTS(Java Transaction Service):12、JavaMail13、JAF(JavaBeans Activation Framework)

    简单的说 就是JavaEE 包含 JavaWeb 。

    1.1 软件架构模式

    • CS 架构(桌面应用)

    ![image.png](https://img-blog.csdnimg.cn/img_convert/244bb536d8295a2eac189e3199052aae.png#crop=0&crop=0&crop=1&crop=1&height=207&id=vQyu0&margin=[object Object]&name=image.png&originHeight=320&originWidth=1005&originalType=binary&ratio=1&rotation=0&showTitle=false&size=36220&status=done&style=none&title=&width=649)

    • BS 架构(web应用)

    image.png

    C/S 对比 B/S
    优点:

    1. cs 体验好,流畅。
    2. bs 无需升级维护,(服务器更新即可)。

    缺点:

    1. cs 更新麻烦
    2. 体验没有客户端好。(对应企业系统这都不重要)

    1.2 服务器概念

    • 硬件服务器
      • 配置非常高的计算机

    ![image.png](https://img-blog.csdnimg.cn/img_convert/90a7b35075456a980f8604b8e09b756f.png#crop=0&crop=0&crop=1&crop=1&height=198&id=uU5CH&margin=[object Object]&name=image.png&originHeight=324&originWidth=583&originalType=binary&ratio=1&rotation=0&showTitle=false&size=314121&status=done&style=none&title=&width=356)

    • 应用程序服务器
      • 一个软件(程序)

    image.png

    Web应用服务器 = 硬件 + 软件

    1.3 资源

    一个Web站点就是一个资源集合,无论是一个网页,一张图片,一个样式文件,视频…,都是资源,网站就是提供这些资源展现给用户,这些资源都被服务器管理了起来。这些资源都是可以被访问到了( 当然服务器也可以限制访问 )。

    • 静态资源
      • 已经存在且内容不变的文件
        • html 文件
        • 样式 文件
        • 脚本 文件
        • 图片 文件
    • 动态资源
      • 由服务端动态生成的内容
        • 由动态语言 执行相应逻辑 最后组装 生成响应内容
    • 使用URL访问资源

    二、Web应用服务器


    ### 2.1 JavaWeb服务器 1.Tomcat 服务器
      目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目,是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器,也是初学者学习开发JSP应用的首选。
    2 Resin 服务器
      Resin是Caucho公司的产品,是一个非常流行的支持Servlet和JSP的服务器,速度非常快。Resin本身包含了一个支持HTML的Web服务器,这使它不仅可以显示动态内容,而且显示静态内容的能力也毫不逊色,因此许多网站都是使用Resin服务器构建。
    3 JBoss服务器
    JBoss是一个种遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器,对于J2EE有很好的支持。JBoss采用JML API实现软件模块的集成与管理,其核心服务又是提供EJB服务器,不包含Servlet和JSP的Web容器,不过它可以和Tomcat完美结合。
    4 WebSphere 服务器
      WebSphere是IBM公司的产品,可进一步细分为 WebSphere Performance Pack、Cache Manager 和WebSphere Application Server等系列,其中WebSphere Application Server 是基于Java 的应用环境,可以运行于 Sun Solaris、Windows NT 等多种操作系统平台,用于建立、部署和管理Internet和Intranet Web应用程序。
    5 WebLogic 服务器
      WebLogic 是BEA公司的产品,可进一步细分为 WebLogic Server、WebLogic Enterprise 和 WebLogic Portal 等系列,其中 WebLogic Server 的功能特别强大。WebLogic 支持企业级的、多层次的和完全分布式的Web应用,并且服务器的配置简单、界面友好。对于那些正在寻求能够提供Java平台所拥有的一切应用服务器的用户来说,WebLogic是一个十分理想的选择。

    2.2 Tomcat 概述

    目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目,是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器,也是初学者学习开发JSP应用的首选。
    下载地址 https://tomcat.apache.org/download-80.cgi

    版本选择问题:
    Tomcat 作为 javaweb运行的容器,它与JavaEE中的各种技术版本存在 关联对应。
    ![image.png](https://img-blog.csdnimg.cn/img_convert/869c47ccaeefb302af9bd177150cd537.png#crop=0&crop=0&crop=1&crop=1&height=298&id=PTe7d&margin=[object Object]&name=image.png&originHeight=298&originWidth=1044&originalType=binary&ratio=1&rotation=0&showTitle=false&size=33846&status=done&style=none&title=&width=1044)

    2.3 Tomcat 安装

    解压到指定的目录,就完成了安装,需要保证本地有JAVA_HOME环境。

    tomcat 这个软件就是用java语言开发,它的运行需要jre,所以需要保证本地有 JRE_HOME 或者 JAVA_HOME。
    如果没有JAVA_HOME环境变量,则启动不了。
    Neither the JAVA_HOME nor the JRE_HOME environment variable is defined At least one of these environment variable is needed to run this program

    2.4 Tomcat 目录解析

    image.png

    2.5 Tomcat 启动停止

    双击执行 bin/startup.bat4
    测试访问 浏览器地址栏 : http://localhost:8080/

    image.png

    双击执行 bin/shutdown.bat

    2.6 Tomcat 配置

    1 控制台乱码配置

    修改 conf/logging.properties

    java.util.logging.ConsoleHandler.encoding = GBK // 47行
    
    • 1

    配置文件修改都必须重启 ,然后才有效果

    2 配置端口

    修改 conf/server.xml

      <Connector  port="9090" protocol="HTTP/1.1"    connectionTimeout="20000"   redirectPort="8443" />
    
    • 1

    port 可以自己定义 80端口 http协议默认端口,访问时可以不输入端口号。

    3 配置管理账号

    修改 conf/tomcat-users.xml

    <role rolename="manager-gui"/>
    <user username="tomcat" password="12345" roles="manager-gui"/>
    
    • 1
    • 2

    2.7 IDEA 集成Tomcat

    ![image.png](https://img-blog.csdnimg.cn/img_convert/b6124e1a55a27dd389ed4cb6bf1ff651.png#crop=0&crop=0&crop=1&crop=1&height=537&id=rAccc&margin=[object Object]&name=image.png&originHeight=537&originWidth=689&originalType=binary&ratio=1&rotation=0&showTitle=false&size=45640&status=done&style=none&title=&width=689)

    ![无标题.png](https://img-blog.csdnimg.cn/img_convert/ac13413bafe5ee1be93c9b40b707280a.png#crop=0&crop=0&crop=1&crop=1&height=460&id=jZKel&margin=[object Object]&name=无标题.png&originHeight=719&originWidth=1112&originalType=binary&ratio=1&rotation=0&showTitle=false&size=63305&status=done&style=none&title=&width=712)

    三、Servlet 快速上手

    3.1 创建工程

    ![无标题.png](https://img-blog.csdnimg.cn/img_convert/a02bab2590a151a5a3df66b59119507a.png#crop=0&crop=0&crop=1&crop=1&height=314&id=QNTRQ&margin=[object Object]&name=无标题.png&originHeight=560&originWidth=1233&originalType=binary&ratio=1&rotation=0&showTitle=false&size=42628&status=done&style=none&title=&width=692)
    Web工程结构
    image.png

    3.2 编写Servlet代码

    import java.util.Date;
    
    /**
     * 编写第一个Servlet
     */
    public class MyServletPage extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // req : 携带请求数据
            // resp: 携带响应数据
    
            resp.getWriter().print("");
            resp.getWriter().print("");
            resp.getWriter().print("");
            resp.getWriter().print("我的第一个动态网页");
            resp.getWriter().print("");
            resp.getWriter().print("");
            resp.getWriter().print("
    "+ new Date() +"
    "
    ); resp.getWriter().print(""); resp.getWriter().print(""); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    3.3 编写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">
    
        <!--1. 注册动态资源-->
        <servlet>
            <servlet-name>ABC</servlet-name>
            <servlet-class>servlet.MyServletPage</servlet-class>
        </servlet>
        <!--2.给动态资源配置请求url-->
        <servlet-mapping>
            <servlet-name>ABC</servlet-name>
            <url-pattern>/user/zmf</url-pattern> 
        </servlet-mapping>
    </web-app> 
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    配置必须 以斜杠 / 开头 否则服务器启动 报错 。
    自己命名,但是不可重复, 也不可重复。

    3.4 启动程序

    ![image.png](https://img-blog.csdnimg.cn/img_convert/74e60d3b4dfb05403755ecfa991a81bd.png#crop=0&crop=0&crop=1&crop=1&height=61&id=Rat8w&margin=[object Object]&name=image.png&originHeight=61&originWidth=409&originalType=binary&ratio=1&rotation=0&showTitle=false&size=4725&status=done&style=none&title=&width=409)

    3.5 访问测试

    http://localhost/myfristweb_war_exploded/zmf
    
    • 1

    结果
    image.png

    ![image.png](https://img-blog.csdnimg.cn/img_convert/5bc7ddda9a7df51a8c0de7a6bda36466.png#clientId=u67ec0bd2-4f49-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=487&id=u200ab3cb&margin=[object Object]&name=image.png&originHeight=609&originWidth=1420&originalType=binary&ratio=1&rotation=0&showTitle=false&size=28175&status=done&style=none&taskId=u81449327-8ac3-4c78-9c23-321ea4cda9b&title=&width=1136)

    四、Http协议★ ★ ★

    image.png

    4.1 概念

    • HTTP协议(HyperText Transfer Protocol,超文本传输协议)它的底层基于TCP协议,但是做了改进,HTTP不是长连接。它的特点是无状态,短连接。

    4.2 请求

    请求消息格式

    • 方法 URL 版本 [回车换行] — 请求行
    • _key : value _
    • [回车换行]…
    • 请求正文

    image.png

    4.3 响应

    响应消息格式

    • 版本 状态码 短语 [回车换行] —状态行
    • key:value …
    • 响应正文

    ![image.png](https://img-blog.csdnimg.cn/img_convert/43df23bf1a8dc3605afb27c840f6a863.png#crop=0&crop=0&crop=1&crop=1&height=153&id=r6ZsN&margin=[object Object]&name=image.png&originHeight=153&originWidth=304&originalType=binary&ratio=1&rotation=0&showTitle=false&size=8702&status=done&style=none&title=&width=304)

    4.4 请求方式

    • Http1.0
      • **GET, POST ** HEAD(只提交请求头)
    • Http1.1
      • DELETE PUT OPTIONS PATCH TRACE CONNECT

    Get和Post区别
    get:

    1. 请求数据走地址栏( 地址栏可以看见发送的数据 ) 不安全。
    2. 数据量有限制 不同浏览器实现可能不同。1024字节

    post:

    1. 数据走后台(正文)地址栏不可见,安全。
    2. 数据量没有限制。

    4.5 文档类型

    文档类型用于声明响应文档的格式,方便浏览器解析和处理。

    • text/html:HTML格式
    • text/plain:纯文本格式
    • text/xml:XML格式
    • image/gif:gif图片格式
    • image/jpeg:jpg图片格式
    • image/png:png图片格式
    • application/xhtml+xml:XHTML格式
    • application/xml:XML数据格式
    • application/atom+xml:Atom XML聚合格式
    • application/json:JSON数据格式
    • application/pdf:pdf格式
    • application/msword:Word文档格式
    • application/octet-stream:二进制流数据(常见的文件下载)
    • application/x-www-form-urlencoded:表单中默认的encType,表单数据被编码为key/value格式发送到服务器

    4.6 状态码

    状态码用于说明本次请求响应的状态,不同的情况对应不同的状态码。

    • 1XX 临时 100-199
    • 2XX 成功 比如:200 200-299
    • 4XX 找不到资源 比如:404
    • 3XX 重定向 比如:304 302 重定向
    • 5XX 发生错误 比如: 500

    ![image.png](https://img-blog.csdnimg.cn/img_convert/8a2b21ac1d6cda2eb618ed3869be91bd.png#clientId=u67ec0bd2-4f49-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=728&id=ua191af9f&margin=[object Object]&name=image.png&originHeight=910&originWidth=1274&originalType=binary&ratio=1&rotation=0&showTitle=false&size=29366&status=done&style=none&taskId=ucd9d140c-92a0-4089-b18a-6def93d1e34&title=&width=1019.2)

    五、Servlet 核心编程

    5.1 简介

    Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

    5.2 创建方式

    1. **Servlet 接口 **

    Sun对于动态资源(动态Web页面)最原始的抽象,是一个接口,定义了5个抽象方法,这些抽象方法,表示的是一个Servlet的声明周期。

    1. GenericServlet 抽象类

    通用的Servlet,它是Servlet接口的普通(通用)实现类,可以理解为对Servlet接口做了简单实现。

    1. HttpServlet 抽象类 (推荐)

    它是 GenericServlet 子类 ,基于Http协议实现,和Http协议绑定,全面支持Http协议的一切规范和要求,提供了处理Http请求的方法。
    image.png

    ============================继承 HttpServlet========================================
    
    public class MyServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("执行GET");
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("执行Post");
        }
    }
    
    ============================继承 GenericServlet========================================
    
    public class MyServlet extends GenericServlet {
        @Override
        public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException {
            System.out.println("执行方法");
        }
    }
    
    ============================直接实现 Servlet接口========================================
    
    public class MyServlet implements Servlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {}
        @Override
        public ServletConfig getServletConfig() {return null;}
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("执行方法");
        }
        @Override
        public String getServletInfo() {  return null;}
        @Override
        public void destroy() {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    5.3 配置方式

    • xml配置
    
        ABC
        servlet.MyServlet
    
    
        ABC
        /hello
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • **注解配置 **
    @WebServlet("/hello")
    public class MyServlet extends HttpServlet {
     
    }
    
    • 1
    • 2
    • 3
    • 4

    5.4 接受请求参数 ★ ★ ★

    通常情况下,动态资源的作用就是接收来自前段页面的请求,同时获得请求中的数据,这些数据都是name=value的形式。通过下面的方法可以根据name 获取对应的 value。

    前端发送数据
    前端发送数据的形式常见的有3种,①表单 ②超链接 ** ** ③ajax (后面单独专题)

    1. ** 表单方式**★★
    <form action="动态资源url" method="post|get" >
         <input name="username"  />
         <input name="password"  />
         .......
    form>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1. 超链接方式★★
    <a href='动态资源url?id=123&age=100&age=45' > 删除 a>
    
    • 1

    超链接请求默认为get请求方式。?后为查询字符串多个值用&连接。比如 /xxx.do?name=kangkang&age=10

    后端接收数据★★

    • getParameter( String name ): String

    获取单个数据值

    • getParameterValues( String name ): String[ ]

    获取多个数据值(复选框)

    Servlet 对于前端的请求方式和方法 不关心 , 取值的方法是相同的。

    5.5 处理乱码

    • 请求乱码处理
    // 防止请求数据乱码
    req.setCharacterEncoding("UTF-8");
    
    • 1
    • 2

    这里必须注意,必须在获取数据前也就是getParameter() 前执行,否则无效。

    • 响应乱码处理
    // 防止响应数据乱码
    resp.setCharacterEncoding("UTF-8");
    resp.setContentType("text/html;charset=utf-8");
    
    • 1
    • 2
    • 3

    这里必须注意 ①必须在输出数据前设置,否则无效 ②响应类型根据实际设置,不一定全是 text/html。

    5.6 整合JDBC

    步骤与流程

    1创建工程
    _ 02Servlet-Jdbc_

    2引入jar包和工具类
    image.png
    3工具类与配置文件

    自己封装的工具类代码
    
    • 1

    image.png

    4编写实体类

     
    /**
     * 实体类
     */
    public class Teacher {
    
        private Integer id;
        private String  name;
        private String level;
        private Integer gender;
        private Double cost;
        private String state;
        private Date practice_date;
        private String information;
         。。。。。。。。。。。。
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    5编写Dao

    /**
     * 技师持久化功能接口
     */
    public interface TeacherDao {
        /**
         * 查全部
         * @return
         * @throws SQLException
         */
          List<Teacher> selectAll() throws SQLException;
        /**
         * 根据ID 查一个
         * @param id
         * @return
         * @throws SQLException
         */
          Teacher selectById( int id ) throws SQLException;
        /**
         * 录入技师
         * @param teacher
         * @return
         * @throws SQLException
         */
          int insert( Teacher teacher ) throws SQLException;
    
    
        /**
         * 根据ID删除技师
         * @param id
         * @return
         * @throws SQLException
         */
        int delete(int id) throws SQLException;
    
    }
    ===============================================================
    
    /**
     *  技师表持久化功能具体实现
     */
    public class TeacherDaoImpl implements TeacherDao {
        @Override
        public List<Teacher> selectAll() throws SQLException {
            String sql = "select * from technician ";
            return JdbcUtil.query(sql, new BeanListHandler<>(Teacher.class));
        }
    
        @Override
        public Teacher selectById(int id) throws SQLException {
            String sql = "select * from technician where id=? ";
            return JdbcUtil.query(sql,new BeanHandler<>(Teacher.class),id);
        }
    
        @Override
        public int insert(Teacher t) throws SQLException {
            String sql = "insert into technician(`name`,`level`,`gender`,`information`,`state`,`cost`,`practice_date`) values(?,?,?,?,?,?,?)  ";
            return JdbcUtil.update(sql,t.getName(),t.getLevel(),t.getGender(),t.getInformation(),t.getState(),t.getCost(),t.getPractice_date());
        }
    
        @Override
        public int delete(int id) throws SQLException {
            String sql = "delete from technician  where id=?";
            return JdbcUtil.update(sql,id);
        }
    }
        
        
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    6编写Service

    /**
     * 技师功能接口
     */
    public interface TeacherService {
    
        /**
         * 查询全部技师
         * @return
         * @throws Exception
         */
        List<Teacher> findAllTeacher() throws Exception;
    
        /**
         * 添加一个技师
         * @param t
         * @return
         * @throws Exception
         */
        int add( Teacher t ) throws Exception;
    
    
        /**
         * 根据id删除技师信息
         * @param id
         * @return
         * @throws Exception
         */
        int delete( int id ) throws Exception;
    }
    ===============================================
     
    /**
     * 业务逻辑实现
     */
    public class TeacherServiceImpl implements TeacherService {
    
        //需要Dao协助
        private TeacherDao teacherDao = new TeacherDaoImpl();
    
        @Override
        public List<Teacher> findAllTeacher() throws Exception {
            try{
                return teacherDao.selectAll();
            }finally {
                JdbcUtil.close(null,null,JdbcUtil.getConnection());
            }
    
        }
    
        @Override
        public int add(Teacher t) throws Exception {
            try{
                return teacherDao.insert(t);
            }finally {
                JdbcUtil.close(null,null,JdbcUtil.getConnection());
            }
        }
    
        @Override
        public int delete(int id) throws Exception {
            try{
                return teacherDao.delete(id);
            }finally {
                JdbcUtil.close(null,null,JdbcUtil.getConnection());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    7编写Servlet

     package com.qfedu.wash.servlet;
    
    import com.qfedu.wash.entity.Teacher;
    import com.qfedu.wash.service.TeacherService;
    import com.qfedu.wash.service.impl.TeacherServiceImpl;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.List;
    
    @WebServlet("/teacher/list.do")
    public class QueryTeacherServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //1.处理乱码
            req.setCharacterEncoding("utf-8");
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html;charset=utf-8");
            //2.获得前端数据(有可能发也可能不发)
            //3. 业务逻辑协助
            TeacherService teacherService = new TeacherServiceImpl();
            try {
                List<Teacher> allTeacher = teacherService.findAllTeacher();
                //遍历结果并输出给客户端
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");
                resp.getWriter().println("");for(Teacher teacher : allTeacher){
                    resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                        resp.getWriter().println("");
                       resp.getWriter().println("");
                    resp.getWriter().println("");}
                resp.getWriter().println("
    编号姓名性别等级费用从业日期信息操作
    " +teacher.getId()+ "" +teacher.getName()+ "" +teacher.getGender()+ "" +teacher.getLevel()+ "" +teacher.getCost()+ "" +teacher.getPractice_date()+ "" +teacher.getInformation()+ "删除
    "
    ); resp.getWriter().println(" 继续添加 "); } catch (Exception e) { e.printStackTrace(); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    8测试

    localhost:8080/teacher/list.do
    
    • 1

    5.7 转发与重定向

    ★ 请求转发

    请求转发,指的是Servlet接收到请求后,经过部分处理后,再次把请求转到其它Servlet或者视图去的过程。它是服务器内部的一个行为,只能转发到本站资源。地址栏不变化,转发前后是一次请求。转发后使用的就是 转发前的 请求 响应对象。

    req.getRequestDispatcher( String url ).forword( HttpServeltRequest req, HttpServlet response )
    
    • 1

    ![image.png](https://img-blog.csdnimg.cn/img_convert/667b2d4b9bbab13fc2825993ebdad1bd.png#crop=0&crop=0&crop=1&crop=1&height=134&id=piWiW&margin=[object Object]&name=image.png&originHeight=134&originWidth=558&originalType=binary&ratio=1&rotation=0&showTitle=false&size=13568&status=done&style=none&title=&width=558)


    ★ 请求重定向

    请求重定向,指的是Servlet接收到请求后,**处理完请求 ,**然后立即响应客户端,发送302状态码,和一个重定向地址。客户端立即请求新地址。它是客户端行为,地址栏改变,可以跳转到任意资源。

    resp.sendRedirect(String url)
    
    • 1

    image.png

    ★ Request 作用域

    作用域,简单说就是一块内存空间,这个空间可以存放数据,这个空间的数据结构就是一个Map。 数据以name=value 形式存储。Value是Object类型。name 是 String 类型。

    • setAttribute( String name , Object value ) 存数据,name重复则会覆盖值
    • getAttribute( String name ) : Object 取数据
    • removeAttribute( String name ): 移除数据
    //存(转发前)
    req.setAttribute("date", new Date() );
    req.setAttribute("ip", req.getRemoteAddr() );
    
    //取(转发后)
    resp.getWriter().println(req.getAttribute("date"));
    resp.getWriter().println(req.getAttribute("ip"));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    由于转发前后是同一个Request 所以,可以使用 Request域来传数据。

    思考重定向如何传参数呢?
    URL重写
    通过 在重定向地址后面携带数据。

      resp.sendRedirect("/page/success.do?date=xxx&ip=xxxx");
    
    • 1

    如果数据是中文的,需要使用 xxx=URLEncoder.encode(“中文数据”, “utf-8”);编码后发送。

    success.do 取数据

    req.getParameter("date")
    req.getParameter("ip")
    
    • 1
    • 2

    5.8 会话管理

    5.8.1 什么是会话Session?

    会话指的是客户端与服务端多次交互的连接抽象。Http 无状态短连接,客户端与服务端,一次请求和响应后,就立马断开了,这就导致了,服务器记不住客户端,实际上这是不行的,我们需要把客户端与服务端的多次通信过程,视为在一个连接中,要实现这种方案,就是会话保持,会话管理。
    ![image.png](https://img-blog.csdnimg.cn/img_convert/397e858c6d4b53f2abe084bf43ca4c63.png#crop=0&crop=0&crop=1&crop=1&height=253&id=FoWjv&margin=[object Object]&name=image.png&originHeight=253&originWidth=783&originalType=binary&ratio=1&rotation=0&showTitle=false&size=32340&status=done&style=none&title=&width=783)

    简单理解就是 客户端与服务器的多次通信过程的集合 就是会话。

    5.8.2 Cookie

    可以使用Cookie存储简单键值对信息,存储在浏览器本地,由服务器负责 存和取,减轻服务端保存数据的压力,这些数据,不是重要数据,通常是存储的是用户的行为偏好。典型的,比如记住账号密码 商品推荐 临时购物车 ,切记Cooke存在客户端

    • 创建Cookie
     Cookie ck = new Cookie( "hobby","Ball");
    
    • 1
    • 设置Cooke属性
    ck.setMaxAge(60*5);  //正数:存活时间 s秒    0删除cookie  负值:存在再浏览器内存中,关闭就没了
    
    • 1
    • 添加到响应头
    resp.addCookie(ck);
    
    • 1
    • 读取Cookie
    Cookie[] cookies = req.getCookies();
    if( cookies!=null ){
        for ( Cookie ck :cookies ){
            resp.getWriter().println(ck.getName()+":"+ ck.getValue()+":"+ck.getPath());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    5.8.3 HttpSession 与 Session域★★★

    HttpSession的实例表示的就是一个会话,Session 作用域,简单说就是一块内存空间,这个空间可以存放数据,这个空间的数据结构就是一个Map。 数据以name=value 形式存储。Value是Object类型。name 是 String 类型,这个空间是HttpSession 对象的空间,服务端 ,每个客户端都有一个,相互隔离。切记Session存在服务器端

    Session 与 Cookie 的关系,Session需要使用cookie作为通信凭证。


    • setAttribute( String name , Object value ) 存数据,name重复则会覆盖值
    • getAttribute( String name ) : Object 取数据
    • removeAttribute( String name ): 移除数据

    Session 生命周期

    1. 默认 30 分钟 , 超过30分钟不操作自动过期
    2. 关闭浏览器 自动过期
    3. 执行 session.invalidate() 注销功能

    5.9 ServletContext 与 全局作用域

    1 ServletContext 理解

    tomcat 服务本质上是实现了Servlet 规范的一个容器,支持Servlet程序执行,众多的Servlet被部署到容器中,Tomcat 通过 Context(上下文)对网站进行隔离,一个网站就是一个Context, 也就是Context对应一个Web应用。在JavaWeb程序中 ServletContext 就是一个表示一个Web应用。
    image.png

    获得ServletContext对象

    • this.getServletContext():ServerletContext this指的是Servlet实例,这句话写在Servlet中
    • req.getServletContext():ServerletContext

    2 全局作用域

    全局作用域,也是一块内存空间,是整个网站的空间,所有用户都可以使用,由于是全局的,生命周期和网站一样,要谨慎使用,一般都不用,网站全局的配置信息。Sevlet 有三大作用域。作为域通常存在下面3个方法管理数据。

    • setAttribute( String name , Object value ):void 存数据,name重复则会覆盖值
    • getAttribute( String name ) : Object 取数据
    • removeAttribute( String name ):void 移除数据

    3 获得网站信息的方法

    • getContextPath() 获得网站上下文路径
    • getRealPath(String path ) 获得网站实际发布路径

    4 读取配置文件中的数据

    有时候整个项目会需要一些初始化信息,或者全局配置信息,这时就可以把数据配置在配置文件中,在程序中通过API来获取数据。

    web.xml

    <context-param>
      <param-name>OSparam-name>
      <param-value>Windows7param-value>
    context-param>
    <context-param>
      <param-name>Javaparam-name>
      <param-value>123param-value>
    context-param>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    读取方法

    • getInitParameter(String name) : String ;
     String os = context.getInitParameter("OS");
     String os = context.getInitParameter("Java");
    
    • 1
    • 2

    5三大作用域★

    HttpServletRequest : 请求域: 生命周期同request对象。转发传值。
    HttpSession: 会话域:每个浏览器的空间,用于保存用户 状态信息。比如用户标识
    ServletContext: 全局域,整个网站的空间,保存全局信息,比如网站的配置信息。

    六、Servlet 生命周期与线程安全

    所谓Servlet生命周期就是指Servlet从生到死的各个阶段,主要分为 ① 创建 ②初始化 ③服务 ④销毁 几个阶段
    如果我们需要在生命周期时间点上 做事情。就需要预留生命周期钩子( 回调 ),Servlet 提供了以下几种回调钩子

    public interface Servlet {
        // 初始化
        void init(ServletConfig var1) throws ServletException;
        // 处理请求(服务)
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
        // 销毁
        void destroy();
        
        ServletConfig getServletConfig(); // 获得Servlet配置信息
        String getServletInfo();          // 获得Servlet信息
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    HttpServlet实现的过程中把 Service细分为doGet doPost

    6.1 HttpServlet 生命周期

    /**
     * 测试生命周期
     */
    @WebServlet("/life.do")
    public class LifeServlet  extends HttpServlet {
    
        public LifeServlet() {
            System.out.println("构造器....");
        }
    
        @Override
        public void init() throws ServletException {
            System.out.println("初始化....");
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           System.out.println("服务....");
        }
    
        @Override
        public void destroy() {
            System.out.println("销毁....");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.2 生命周期总结

    第一请求Servlet 创建并初始化再调用服务,以后每次请求只调用服务方法,最后容器卸载web应用调用销毁。
    _构_造器 执行1
    _init() _ 执行1
    service() 执行N
    destory() 执行1

    6.3 线程安全性问题

    Servlet 被设计为一个单例(多线程)模式,一个Servlet一旦被创建就一直驻留在内存,提供服务,直到销毁,每个请求服务器开启一个单独的线程处理。所以Servlet是线程不安全的,尽量避免使用实例变量。或者实在要使用实例变量用ThreadLocal包装,或者实现SingleThreadModel 。

    SingleThreadModel 可以使Servlet编程单线程模式。

    6.4 Servlet 配置

    配置Servlet 初始化参数

    • xml配置
    <servlet>
      <servlet-name>LifeServletservlet-name>
      <servlet-class>servlet.LifeServletservlet-class>
      <init-param>
        <param-name>numparam-name>
        <param-value>998param-value>
      init-param>
      <init-param>
        <param-name>nameparam-name>
        <param-value>tomparam-value>
      init-param>
    servlet>
    <servlet-mapping>
      <servlet-name>LifeServletservlet-name>
      <url-pattern>/life.dourl-pattern>
    servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 注解配置
    @WebServlet( value = "/life.do",
            initParams = { @WebInitParam(name = "num",value = "888"),
                          @WebInitParam(name = "name",value = "jack")})
    
    • 1
    • 2
    • 3

    在Serlvet代码中读取

    @Override
    public void init(ServletConfig config) throws ServletException {
        String num = config.getInitParameter("num");
        String name = config.getInitParameter("name");
        System.out.println("初始化...."+num+" "+name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    配置Servlet 创建时机
    希望服务器启动就立即加载并初始Serlvet

    • XML配置
    <servlet>
      <servlet-name>LifeServletservlet-name>
      <servlet-class>servlet.LifeServletservlet-class>
      <load-on-startup>1load-on-startup>
    servlet>
    <servlet-mapping>
      <servlet-name>LifeServletservlet-name>
      <url-pattern>/life.dourl-pattern>
    servlet-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 注解配置
    @WebServlet( value = "/life.do", loadOnStartup = 1   )
    
    • 1

    loadOnStartup = 1 数字越大优先级越高

    6.5 理解Servlet各种方法回调

    通常我们会有一个疑问,就是我们重写了doGet 和 doPost 以后,我们并没有调用,只要浏览器请求,它就执行了。那么,它是什么时候调用的呢?谁调用的呢?

    // 理解回调原理
    //Tomcat{
    //    run(  Servlet  xx  ){
    //        //服务器 接收客户端 tcp 连接
    //        ServerSocker xx = new ServerSocker(8080)
    //        Socket soket =xx.accetp();
    //        //服端 通过 io流读取客户数据
    //        InputStream is = socket.getInputStreamt();
    //        String username =  is.read()
    //        String passowrd =  is.read()
    //        //服务端构造 请求 和 响应对象
    //        HttpServletRequest req = new HttpServletRequest();
    //        HttpServletResponse resp = new HttpServletResponse();
    //        req.setParameter( "username",username )
    //        req.setParameter( "passowrd",passowrd )
    //        //服务端调用 服务方法
    //         //做个事情
    //          if(method=="get")
    //           { 
                    xx.doGet(req,resp)
    //           }
    //           if(method=="post")
    //           { 
                     xx.doPost(req,resp)
    //           }
              //销毁(调用钩子)
               // xx.destory();
    //        // 断开操
    //    }
    //}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    通过上面的伪代码,我们可以这样理解,是tomcat 监听客户端连接,接收到浏览器数据后,自己把数据封装到请求对象和响应对象中,然后创建了我们提供的Serlvet 对象,然后调用doGet 或者doPost方法,由于多态,实际执行的就是我们提供了方法逻辑了,简单的说,我们编写的Servlet 就是提供了回调代码。由于这部份代码tomcat无法完成封装( 因为不同的客户端请求服务端做的事情都不一样 ) 。

    七、JavaWeb 其他组件

    7.1 Filter ★★★

    7.1.1 过虑器概念

    Filter 是JavaWeb 中的过滤器,所谓过虑器,就是可以对请求做预处理,在请求每抵达目标资源前做一些操作。比如 设置编码呀 验证权限呀 参数校验呀 连接黑名单 等等。 这种思想就是 想把目标方法中一些与业务逻辑无关的代码,提到过滤器中提前处理。
    ![image.png](https://img-blog.csdnimg.cn/img_convert/62d6397429358402b71ea4248251fedf.png#crop=0&crop=0&crop=1&crop=1&height=376&id=Qo0Zl&margin=[object Object]&name=image.png&originHeight=376&originWidth=941&originalType=binary&ratio=1&rotation=0&showTitle=false&size=46279&status=done&style=none&title=&width=941)

    7.1.2 编写过滤器

    实现一个Filter接口并重写3个抽象方法其中只需要关注 doFilter() 方法。

    public class AFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("AFilter 初始化");
        }
        @Override
        public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
            System.out.println("执行过虑");
            chain.doFilter(req,resp);//放行(把请求往下一级传递)
            System.out.println("FilterA完成过虑");
        }
    
        @Override
        public void destroy() {
            System.out.println("AFilter 销毁");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行完过虑 希望传递到下一级, 通过 FilterChain 过虑链 放行。

    7.1.3 配置过滤器

    过滤器的作用是对请求做预处理。
    xml配置

    <filter>
      <filter-name>AFilterfilter-name>
      <filter-class>filter.AFilterfilter-class>
    filter>
    <filter-mapping>
      <filter-name>AFilterfilter-name>
      <url-pattern>/user/*url-pattern>
    filter-mapping>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    url-pattern 配置需要连接的 请求路径 *是一个通配符
    多个Filter 注册顺序决定了执行顺序。

    注解配置 (掌握)

    @WebFilter(value="/user/*")
    public class AFilter implements Filter {
        ......
    
    • 1
    • 2
    • 3

    注解配置没有直接控制 优先级的配置, 通过Filter类名决定优先级,默认安装字母顺序。

    7.1.4 Filter生命周期

    启动网站理解创建并初始化,以后只要请求满足自己的url-patten 则直接过虑, tomcat 容器卸载应用时,执行销毁方法。

    思考? 为什么Filter 必须是随着网站的启动而初始化

    补充: 如果使用处理编码问题,导致静态资源乱码可以只用一下方式处理,在tomcat 的conf/web.xml中 做如下配置 指定默认servlet的读取静态文件的编码方式。

        <servlet>
            <servlet-name>defaultservlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServletservlet-class>
             ..........
    		    <init-param>
                <param-name>fileEncodingparam-name>
                <param-value>utf-8param-value>
            init-param>
             ............
            <load-on-startup>1load-on-startup>
        servlet>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.2 Listener(了解)

    7.2.1 监听器概念

    监听器,可以实现对 域(HttpServletRequest, HttpSession, ServletContext)对象生命周期,以及域中数据变化_,做监控。它的作用就可以建立一种事件机制,如果一旦这些对象状态发生改变,我们可以感知到。可以做出响应的处理。 比如 _早期Spring 框架整合Web项目时,需要监听网站加载完成然后创建Spring容器。

    7.2.2 监听器类型


    • HttpSession

    • _HttpSessionListener 生命周期监听 _

    • _HttpSessionAttributeListener 属性变化监听 _

    • HttpServletRequest

    • ServletRequestListener 生命周期监听

    • ServletRequestAttributeListener 属性变化监听


    • ServletContext
    • ServletContextListener 生命周期监听
    • ServletContextAttributeListener 属性变化监听

    7.2.3 创建监听器

    以HttpSession为例,编写一个JAVA类实现 相关接口。

    @WebListener
    public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
    
        //  监听Session 创建
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
            System.out.println("session 创建了");
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
            System.out.println("session 销毁了");
        }
    
        @Override
        public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("添加数据");
        }
    
        @Override
        public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("移除数据");
        }
    
        @Override
        public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("修改数据");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    7.2.4 监听器配置

    注解配置

    @WebListener
    public class MySessionListener implements HttpSessionListener, HttpSessionAttributeListener {
    ......
    
    • 1
    • 2
    • 3

    XML 配置

    <listener>
     <listener-class>listener.MySessionListenerlistener-class>
    listener>
    
    • 1
    • 2
    • 3
    1. 页面展现能力不足
    2. 客户端渲染(AJAX- html+数据 ) (JSP- 服务器端渲染)
  • 相关阅读:
    线程的状态
    【Business Touch Kit】服务号消息发送接口返回401如何解决?
    Leetcode.174 地下城游戏
    【考研高数】学习笔记分享
    【Vue基础】Vue路由,实现页面跳转
    矩阵置零00
    【数字测图原理与方法】第三章水准测量原理和仪器
    安全评估报告怎么写 安全风险评估报告流程 安全评估报告认定
    基于SSM的高速公路的智能交通管理系统
    2023青岛大学计算机考研信息汇总
  • 原文地址:https://blog.csdn.net/yc_Cabbage/article/details/126295420