美文网首页
看似简单的Servlet,搞定它让你web开发道路一片光明

看似简单的Servlet,搞定它让你web开发道路一片光明

作者: 一眼万年的星空 | 来源:发表于2022-09-10 15:54 被阅读0次

    Servlet入门

    今日目标

    1. 创建servlet
        xml
        anno(注解)
        
    2. servlet执行原理
    
    3. servlet生命周期
    
    4. servlet体系结构
    

    一 Servlet概述

    • servlet= server+applet 运行在服务器端的java小程序。

    • Servlet是一个接口(规范),一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口

    作用

    接收请求,处理业务,响应结果

    1

    二 Servlet快速入门

    目标:编写一个普通的java类,通过浏览器可以访问

    #编写步骤
        1. 定义一个类,实现Servlet接口,重写所有的抽象方法(特别是service方法)
        2. 配置web.xml文件
    

    2.1 代码编写

    ① 创建web项目

    1

    ② 编写普通java类,实现servlet接口

    重写抽象方法(service方法)

    package com.itheima01.servlet;
    
    import javax.servlet.*;
    import java.io.IOException;
    
    /*
    *  ctrl+i(implements) : 提示重写所有抽象方法
    *   ctrl+ enter: 万能提示
    * */
    public class MyServlet implements Servlet {
    
        /*
        * servletRequest : 请求
        * servletResponse : 响应
        * */
        @Override
        public void service(ServletRequest servletRequest,
                            ServletResponse servletResponse) throws ServletException, IOException {
    
            System.out.println("接收到请求"); //控制台打印
            //网页上显示出来,不要写中文,会乱码
            servletResponse.getWriter().print("hello servlet");//响应给浏览器
        }
    
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        @Override
        public String getServletInfo() {
            return null;
        }
    
        @Override
        public void destroy() {
    
        }
    }
    

    ③ 配置web.xml

    配置servlet网络访问路径

    <?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-mapping标签里都有servlet-name子标签
                内部文本可以随意命名,但是必须一致
            2.  servlet-class标签: 写Servlet实现类的全限定名(包名+类名)
            3. url-pattern : 指定的是该Servlet的虚拟路径
        -->
        <servlet>
            <servlet-name>MyServlet01</servlet-name>
            <servlet-class>com.itheima01.servlet.MyServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>MyServlet01</servlet-name>
            <url-pattern>/myServlet</url-pattern>
        </servlet-mapping>
    </web-app>
    

    ④ 部署web项目

    1

    ⑤ 启动测试

    1

    2.2 执行原理

    1

    三 Servlet相关API

    3.1 生命周期方法

    3.1.1 思想介绍

    • 生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
    // 1. servlet对象创建时,调用此方法
    public void init(ServletConfig servletConfig);
    // 2. 用户访问servlet时,调用此方法 (每次访问都会调用一次)
    public void service(ServletRequest servletRequest, ServletResponse servletResponse);
    // 3. servlet对象销毁时,调用此方法
    public void destroy();
    
    1
    * 创建
        1)默认情况下
            用户第一次访问时,创建servlet,执行init方法
        2)修改创建时机
            <load-on-startup></load-onstartup>
                正数:5-N  【服务器启动时,创建】
                    补充:Tomcat的web.xml里有1,4 所以推荐5-n 
                负数(默认值):-1 【用户第一次访问时,创建】
        
    * 运行(提供服务)
            用户每次访问时,都执行service方法
    
    * 销毁
            服务器正常关闭时,销毁servlet,执行destroy方法
    

    3.1.2 代码演示

    ① LifeServlet

    package com.itheima02.life;
    
    import javax.servlet.*;
    import java.io.IOException;
    /*
        # 观察
        1. 第一次访问LifeServlet
            init
            service
    
        2. 再次访问LifeServlet
            service
    
        3. 关闭tomcat之前
            destroy
    
       # Servlet中的API
       1. 生命周期方法(lifecycle)
            对象从创建到销毁的整个过程
    
          1). init : 初始化
                a. 默认情况下,浏览器第一次访问时调用
                b. 适合执行初始化相关的操作: 加载初始配置
          2). service : 服务
                a. 浏览器每次访问,都会执行一次
                b. 处理业务
          3). destroy
                a. tomcat在关闭之前,先执行此方法
                b. 适合释放资源,保存数据
    
       2. 启动加载
           1). 问题:   init方法默认浏览器第一次访问才调用,
                            如果这时候执行加载数据,为时太晚, 用户体验不好
    
           2). 解决: tomcat一启动就加载这个Servlet,并且调用init方法
           3). 方式:
                    在web.xml的servlet下配置
     */
    public class LifeServlet implements Servlet {
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
            System.out.println("LifeServlet init");
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("service");
        }
    
        @Override
        public void destroy() {
            System.out.println("destroy");
        }
    
        @Override
        public ServletConfig getServletConfig() {
            System.out.println("getServletConfig");
            return null;
        }
    
    
    
        @Override
        public String getServletInfo() {
            System.out.println("getServletInfo");
            return null;
        }
    
    
    }
    

    ② 配置web.xml

    <servlet>
            <servlet-name>LifeServlet</servlet-name>
            <servlet-class>com.itheima02.life.LifeServlet</servlet-class>
            <!--
                load-on-startup (写在servlet标签内)
                1. 取值是整数n
                2. 默认 n=-1,表示不启动加载(第一次访问才会被加载)
                3. 当n>=0的时候, 启动加载(数字越小,优先级越高)
            -->
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>LifeServlet</servlet-name>
            <url-pattern>/life</url-pattern>
        </servlet-mapping>
    

    3.1.3 启动加载

    # 启动加载
    *       1)问题: 发现 init 默认第一次被访问的时候才调用,适合用来初始化项目数据
    *           如果项目数据很多, 加载就需要一定的时间,这样就会给第一个用户的体验不好,因为要等比较久
    *
    *       2)解决: 服务器一启动,就执行init方法
    *       
    *       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">
        <servlet>
            <servlet-name>MyServlet_sb</servlet-name>
            <servlet-class>com.itheima01.servlet.MyServlet</servlet-class>
            <load-on-startup>6</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>MyServlet_sb</servlet-name>
            <url-pattern>/myServlet</url-pattern>
        </servlet-mapping>
    
        <!--
           # 启动加载
           1)问题: 发现 init 默认第一次被访问的时候才调用,适合用来初始化项目数据
               如果项目数据很多, 加载就需要一定的时间,这样给第一个用户打来的体验不好,因为要等比较久
    
           2)解决: 服务器一启动,就执行init方法
    
           3) 实现: 要在web.xml配置
                1). servlet标签内补充一个子标签 load-on-startup (启动时加载)
                2). 在load-on-startup里写一个非负整数
                    n >= 0  , 数字越小,优先级越高 (我们自己写n=5开始写, 0~4被tomcat使用掉了)
                    默认n=-1, 表示启动时不加载
        -->
        <servlet>
            <servlet-name>LifecycleServlet</servlet-name>
            <servlet-class>com.itheima02.life.LifecycleServlet</servlet-class>
            <load-on-startup>5</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>LifecycleServlet</servlet-name>
            <url-pattern>/LifecycleServlet</url-pattern>
        </servlet-mapping>
    </web-app>
    

    四 Servlet体系结构

    快捷键:
        1. ctrl + alt + u : 查看一个类的继承结构图
        2. ctrl + h : 这个类的简化版继承结构(类)
    
    1

    4.1 GenericServlet

    1. 问题: 
        Servlet中使用频率最高,最重要的方法是service方法(大部分场景)
        但是我们每次编写Servlet实现类,都是直接实现Servlet接口,重写5个抽象方法(太冗余了)
    
    2. 需求: 如果我们以后编写Servlet实现类,只要重写service方法就好了
    3. 解决:
            1). 建立一个抽象类GenericServlet, 继承Servlet接口,重写除了service之外的四个抽象方法,空实现 
            2). 以后编写其他Servlet,只要继承 GenericServlet, 这时候就只要重写service方法
    
    4. 发现 : 很巧, 开发包已经有了这个类GenericServlet
    

    ① 编写普通java类,继承GenericServlet抽象类

    public class GoodServlet extends GenericServlet {
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            System.out.println("GoodServlet被访问");
        }
        
    }
    

    ② 配置web.xml

        <servlet>
            <servlet-name>GoodServlet</servlet-name>
            <servlet-class>com.itheima03.generic.GoodServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>GoodServlet</servlet-name>
            <url-pattern>/goodServlet</url-pattern>
        </servlet-mapping>
    

    4.2 HttpServlet

    1. 问题: 
          我们在前端的form表单中,method属性, 学习过有两种常用的请求方式(get/post)
          我们现在的service方法是这样的: 用户发送请求,无论是什么请求方式,都会统一的执行service方法, 我们无法很好的区别是哪一种请求方式
          
    2. 需求: 我们如果想确切的知道是哪一种请求方式,必须要先了解HttpServletRequest
    
    3. 解决: 自己封装了一个MyHttpServlet  -> 开发包 HttpServlet
    

    ① 编写前端html

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
            <a href="http://localhost:8080/day04-servlet/HahaServlet">HahaServlet</a>
            <form action="http://localhost:8080/day04-servlet/HahaServlet" method="post">
                <input type="submit">
            </form>
    </body>
    </html>
    

    ② 编写普通java类,继承HttpServlet抽象类

    package com.itheima04.http;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /*
        HttpServlet是GenericServlet的子类
    
        1. HttpServlet重写了service方法
        2. 在service方法中,根据请求方式(http协议)的不同,将service拆分成不同的方法
             1). 有两种常用的请求方式
                    get
                    post
             2). 用户发送请求时(用户在浏览器中访问servlet的地址)
                    service方法就会执行 (接着就会判断)
                        get请求方式 -> doGet
                        post请求方式 -> doPost
    
     */
    public class HahaServlet extends HttpServlet {
    
        //这是post请求方式的service方法
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("post请求方式");
        }
        //基本上请求方式默认都是get
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("get请求方式");
        }
    }
    

    ③ 配置web.xml

     <servlet>
            <servlet-name>HahaServlet</servlet-name>
            <servlet-class>com.itheima04.http.HahaServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>HahaServlet</servlet-name>
            <url-pattern>/HahaServlet</url-pattern>
        </servlet-mapping>
    

    4.3 经验值分享

    ① 响应状态码405

    请求方法没有重写.....

        /*
            注意: 如果我们不重写doGet/doPost方法, 那么父类的doGet/doPost方法会执行(继承)
                给浏览器响应一个错误: 状态码405 (http1.1)
         */
    
    1

    ② 响应状态码500

    java代码写错了...

    1

    五 Servlet路径

    5.1 url-pattern

    作用:将一个请求网络地址和servlet类建立一个映射关系

    1

    5.1.1 Servlet映射多个url

    1

    5.1.2 url映射模式【了解】

    配置 url地址取值可以是:

    1. 精确匹配(掌握) 
            /servletDemo3  
    2. 目录匹配 
            /aa/*
    3. 后缀匹配 
            *.xxx   例如:*.do
    
    <servlet-mapping>
            <servlet-name>PathServlet</servlet-name>
            <!--
                Servlet的路径(虚拟路径)
                1. 一个Servlet可以配置多个虚拟路径  -> 了解 (在Filter中有用)
                2. 一个Servlet的路径有三种写法
                    2.1  精确匹配(掌握)
                            /servletDemo3
                    2.2  目录匹配
                            /aa/*
                    2.3 后缀匹配
                            *.xxx   例如:*.do
    
            -->
            <url-pattern>/bbb/ccc</url-pattern>
            <url-pattern>/aa/*</url-pattern>
            <url-pattern>*.do</url-pattern>
        </servlet-mapping>
    <servlet-mapping>
        <servlet-name>PathServlet</servlet-name>
        <url-pattern>/pathServlet03</url-pattern>
    </servlet-mapping>
    

    5.2 相对/绝对路径

    ● 现阶段我们访问资源的方式越来越多,请求路径在编写时难免出现混淆

    1. 浏览器的地址栏 (输入服务器某个资源地址,敲回车会发送请求)
    2. a标签的href属性 (超链接被点击的时候会发送请求)
    3. form表单的action属性 (form中的submit按钮被点击的时候,发送请求)
    4. js的loation.href属性 (只要设置, 触发相应的)
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <a href="http://www.baidu.com">超链接</a> <br>
    
        <form action="http://www.baidu.com">
            <input type="text" name="username"> <br>
            <input type="submit">
        </form>
    
        <input type="button" value="按钮" id="myid">
        <script>
            //js
            document.getElementById("myid").onclick = function () {
                //bom对象: window,location地址栏
                location.href = "http://www.baidu.com"
            }
        </script>
    </body>
    </html>
    

    这里我们复习下路径规则:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
            <!--
                html页面中,难免书写url
    
                1. 绝对路径
                    a. http://localhost:8080/day01-servlet/PathServlet
                    b. /day01-servlet/PathServlet (省略了三要素,前提: 当前页面和所访问的资源必须在同一服务器上)
                            内部资源, 推荐!!!
    
                2. 相对路径
                    1) ../ 是上一级
                    2) ./ 是平级,可以省略
            -->
            <a href="http://www.baidu.com">百度</a> <br>
            <a href="http://localhost:8080/day01-servlet/PathServlet">我的PathServlet</a> <br>
            <a href="/day01-servlet/PathServlet">我的PathServlet2</a> <br>
    
            <a href="http://localhost:8080/day01-servlet/doc/aaa.html">aaa.html绝对路径写法</a>
            <a href="doc/aaa.html">aaa.html相对写法</a>
    </body>
    </html>
    

    六 Servlet3.0

    ● 通过注解配置Servlet,简化web.xml配置Servlet复杂性,提高开发效率,几乎所有的框架都在使用注解

    ① 创建web工程【注解】

    1

    ② 编写普通java类,继承HttpServlet

    public class QuickServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("QuickServlet....3.0");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("QuickServlet....3.0");
        }
    }
    
    1
    // @WebServlet(name = "QuickServlet",urlPatterns = "/quickServlet")
    // @WebServlet(urlPatterns = "/quickServlet")
    // @WebServlet(value = "/quickServlet")
    @WebServlet("/quickServlet") // 注解中有且仅有一个属性,名为value时,属性名可以省略...
    public class QuickServlet extends HttpServlet {
        
    }
    

    idea创建web模块的规律

    1

    tomcat可以同时运行多个web模块,但是现在一般只运行一个模块

    注意: project structure中要设置这两项

    1

    青山不改,绿水常流。谢谢大家!

    相关文章

      网友评论

          本文标题:看似简单的Servlet,搞定它让你web开发道路一片光明

          本文链接:https://www.haomeiwen.com/subject/ftutortx.html