【JavaWeb】Servlet详解

1. 前置知识

  • 服务器启动时,servlet对象是否被创建出来?
package com.sdnu.javaweb;

import jakarta.servlet.*;

import java.io.IOException;

/**
 * 实现servlet接口
 *
 * @author Beyong
 * @date 2023/03/03 20:44
 **/
public class AServlet implements Servlet {
    public AServlet() {
        System.out.println("A的无参构造方法");
    }

    @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 {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
package com.sdnu.javaweb;

import jakarta.servlet.*;

import java.io.IOException;

/**
 * 实现Servlet
 *
 * @author Beyong
 * @date 2023/03/03 20:49
 **/
public class BServlet implements Servlet {
    public BServlet() {
        System.out.println("B的无参构造方法");
    }

    @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 {

    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
<?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_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>aServlet</servlet-name>
        <servlet-class>com.sdnu.javaweb.AServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>aServlet</servlet-name>
        <url-pattern>/a</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>bServlet</servlet-name>
        <servlet-class>com.sdnu.javaweb.BServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>bServlet</servlet-name>
        <url-pattern>/b</url-pattern>
    </servlet-mapping>
</web-app>

在这里插入图片描述
在控制台发现没有执行构造方法,说明服务器启动的时候,构造方法没有执行。

  • 如何使得服务器启动的时候,创建servlet对象
    在这里插入图片描述
    在代码中添加
<load-on-startup>数字</load-on-startup>

数字越小,则优先级越高。

2.servlet生命周期

package com.sdnu.javaweb;

import jakarta.servlet.*;

import java.io.IOException;

/**
 * 实现servlet接口
 *
 * @author Beyong
 * @date 2023/03/03 20:44
 **/
public class AServlet implements Servlet {
    public AServlet() {
        System.out.println("A的无参构造方法");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("AServlet'init method execute");
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("AServlet'service method execute");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {
        System.out.println("AServlet'destroy method execute ");
    }
}

2.1 默认情况下,服务器启动时,servlet对象并没有被创建

2.2 用户执行一次请求

在这里插入图片描述
结论:

  • 用户在第一次请求的时候,Servlet对象被实例化,AServlet的构造方法被执行,并且执行的是无参构造。
  • AServlet对象被创建出来后,AServlet马上执行init方法
  • 第一次请求时,init方法执行后,马上执行service方法

2.3用户执行第二次请求

控制台输出:

AServlet’service method execute

2.4 3,4,5,6…次请求

后面的请求,Servlet对象并没有创建,而是使用之前的创建好的Servlet对象,调用该对象的方法。

  • servlet对象是单例的,但是servlet类不符合单例模式(假单例)。

  • 无参构造方法只执行一次,init方法也只执行一次,即第一次。

  • 只要用户发送请求,service必然执行。

2.5 关闭服务器

在这里插入图片描述
服务器在关闭前,执行servlet对象的destroy方法,destroy方法执行结束后,AServlet对象的才会被销毁,AServlet对象内存才会释放。

3.servlet方法解析

  • 构造方法
    javaweb不建议手动编写构造方法,因为手动编写构造方法容易导致错误,所以init方法很有必要。
  • init
    很少有,使用在初始化的时候,使用初始化数据连接池,线程池。
  • service
    一定要有,处理用户的请求。
  • destroy
    进行资源关闭。

4.适配器模式改造servlet

4.1不使用servlet模式

接口

package com.sdnu.javaweb.adapter;

/**
 * 接口
 * @author Beyong
 * @date 2023/03/04 11:08
 **/
public interface MyInterface {
    void m1();
    void m2();
    void m3();
    void m4();
    void m5();
    void m6();
    void m7();
    void core();
}

UserService:

package com.sdnu.javaweb.adapter;

/**
 * 用户
 *
 * @author Beyong
 * @date 2023/03/04 11:10
 **/
public class UserService implements MyInterface{
    @Override
    public void m1() {

    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }

    @Override
    public void m5() {

    }

    @Override
    public void m6() {

    }

    @Override
    public void m7() {

    }

    @Override
    public void core() {
        System.out.println("UserService'core method execute!!!");
    }
}

CustomerService:

package com.sdnu.javaweb.adapter;

/**
 * CustomerService
 *
 * @author Beyong
 * @date 2023/03/04 11:13
 **/
public class CustomerService implements MyInterface{
    @Override
    public void m1() {

    }

    @Override
    public void m2() {
        System.out.println("Customer'm2 method execute");
    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }

    @Override
    public void m5() {

    }

    @Override
    public void m6() {

    }

    @Override
    public void m7() {

    }

    @Override
    public void core() {

    }
}

不使用适配器模式下,则代码每一个service都要取实现接口。

4.2使用适配器模式

接口:

package com.sdnu.javaweb.adapter2;

/**
 * 接口
 * @author Beyong
 * @date 2023/03/04 11:24
 **/
public interface MyInterface {
    void m1();
    void m2();
    void m3();
    void m4();
    void m5();
    void m6();
    void m7();
    void core();
}

用户适配器:

package com.sdnu.javaweb.adapter2;

/**
 * UserService适配器
 *
 * @author Beyong
 * @date 2023/03/04 11:26
 **/
public abstract class UserAdapter implements MyInterface{
    @Override
    public void m1() {

    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }

    @Override
    public void m5() {

    }

    @Override
    public void m6() {

    }

    @Override
    public void m7() {

    }

    public abstract void core();
}

顾客适配器:

package com.sdnu.javaweb.adapter2;

/**
 * 客户适配器
 *
 * @author Beyong
 * @date 2023/03/04 11:28
 **/
public abstract class CustomerAdapter implements MyInterface{

    public abstract void m1();

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }

    @Override
    public void m5() {

    }

    @Override
    public void m6() {

    }

    @Override
    public void m7() {

    }

    @Override
    public void core() {

    }
}

用户:

package com.sdnu.javaweb.adapter2;

/**
 * 普通用户
 *
 * @author Beyong
 * @date 2023/03/04 11:34
 **/
public class UserService extends UserAdapter{
    @Override
    public void core() {

    }
}

顾客:

package com.sdnu.javaweb.adapter2;

/**
 * 顾客
 *
 * @author Beyong
 * @date 2023/03/04 11:35
 **/
public class CustomerService extends CustomerAdapter{
    @Override
    public void m1() {

    }
}

5.GenericServlet

我们写一个通用的GenericServlet

package com.sdnu.javaweb.servlet;

import jakarta.servlet.*;

import java.io.IOException;

/**
 * servlet适配器
 *
 * @author Beyong
 * @date 2023/03/04 11:48
 **/
public abstract class GenericServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    
    public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse);

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

LoginServlet

package com.sdnu.javaweb.servlet;

import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;

/**
 * c的servlet
 *
 * @author Beyong
 * @date 2023/03/04 11:49
 **/
public class LoginServlet extends GenericServlet{
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) {
        System.out.println("c'service method execute");
    }
}

web.xml

    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.sdnu.javaweb.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

地址:http://127.0.0.1:8080/lifecycle/login
在这里插入图片描述

进一步改造:

package com.sdnu.javaweb.servlet;

import jakarta.servlet.*;

import java.io.IOException;

/**
 * servlet适配器
 *
 * @author Beyong
 * @date 2023/03/04 11:48
 **/
public abstract class GenericServlet implements Servlet {
    private ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    /**
     * 这个init方法供子类重写
     */
    public void init(){

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException;

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

6.ServletConfig详解

  • 什么是ServletConfig
    ServletConfig是Servlet规范中的一员。
  • Tomcat实现了ServletConfig接口
  • 一个Servlet对应一个ServletConfig
  • Servlet对象是Tomcat创建的,同时创建了ServletConfig.
  • 创建一个Servelt对象,就有一个ServletConfig(Servlet对象信息)。
  • Tomcat解析web.xml文件,将web.xml文件中
 <servlet></servlet>

标签中的配置信息自动包装到ServletConfig对象中去。

  • ServletConfjg有哪些方法?
    getInitParameterNames
    getInitParameter
package com.sdnu.javaweb.servlet;

import jakarta.servlet.*;
import sun.plugin2.util.ParameterNames;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;

/**
 * servletConfig测试2
 *
 * @author Beyong
 * @date 2023/03/06 13:05
 **/
public class ConfigServletTest2 extends GenericServlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        servletResponse.setContentType("text/html");
        PrintWriter out = servletResponse.getWriter();
        ServletConfig config = this.getServletConfig();
        out.print("servletConfig对象是:" + config.toString());
        out.print("</br>");

        String servletName = config.getServletName();
        out.print("<servlet>" + servletName + "</servlet>");
        out.print("</br>");

        Enumeration<String> initParameterNames = config.getInitParameterNames();
        while(initParameterNames.hasMoreElements()){
            String parameterName = initParameterNames.nextElement();
            String parameterVal = config.getInitParameter(parameterName);
            out.print(parameterName + "=" + parameterVal);
            out.print("<br>");
        }
        String driver = config.getInitParameter("driver");
        out.print(driver);
        
//        Enumeration<String> names = this.getInitParameterNames();
//        while(names.hasMoreElements()){
//            String name = names.nextElement();
//            String value = this.getInitParameter(name);
//            out.print(name + " = " + value);
//            out.print("<br>");
//        }
    }
}

<?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_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>configTest</servlet-name>
        <servlet-class>com.sdnu.javaweb.servlet.ConfigServletTest</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>configTest</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>configTest2</servlet-name>
        <servlet-class>com.sdnu.javaweb.servlet.ConfigServletTest2</servlet-class>
        <init-param>
            <param-name>driver</param-name>
            <param-value>com.mysql.cj.jdbc.Driver</param-value>
        </init-param>
        <init-param>
            <param-name>url</param-name>
            <param-value>jdbc:mysql://localhost:3306/sdnu</param-value>
        </init-param>
        <init-param>
            <param-name>user</param-name>
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <param-name>password</param-name>
            <param-value>root123</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>configTest2</servlet-name>
        <url-pattern>/test2</url-pattern>
    </servlet-mapping>
</web-app>

7.ServletConfig接口有四个方法

  • public String getInitParameter(String name);
  • public Enumeration getInitParameterNames();
  • public ServletContext getServletContext();
  • public String getServletName();
    以上四个方法可以在自己编写的Servlet类中使用this调用,这个Servlet继承了GenericServlet

8.ServletContext

  • ServletContext是接口,是Servlet规范的一员。
  • Tomcat实现了ServletContext接口。
  • ServletContext是服务器创建的,在服务器启动的时候创建,在服务器关闭的时候销毁,对于一个WebApp来说,ServletContext只有一个。
  • ServletContext对象对应整个web.xml。
  • ServletContext接口的方法:
    (1)
Enumeration<String> initParameterNames = application.getInitParameterNames();
String value = application.getInitParameter(name);

以上两个方法获取context-param标签中的name和value

    <context-param>
        <param-name>startIndex</param-name>
        <param-value>2</param-value>
    </context-param>

(2获取应用的根路径

String contextPath = application.getContextPath();

在这里插入图片描述
(3)获取文件的绝对路径

public String getRealPath(String path)

(4)访问日志

public void log(String message);
public void log(String message, Throwable t);

Tomcat服务器的Log目录下都有哪些日志信息?

catalina.2023-02-28.log 服务器的java程序运行的控制信息
localhost.2023-03-07.log ServletContext对象的log方法记录的日志存储到这个文件中
localhost_access_log.2023-02-28.txt 访问日志

  • ServletContext又叫应用域,放到ServletContext中的数据一般是数据量小,所以用户共享的,不经常修改的。

存:public void setAttribute(String name, Object value);
取:public void getAttribute(String name);
删:public void removeAttribute(String name);

User user = new User("jack", "123456");
application.setAttribute("UserObj", user);
Object userObj = application.getAttribute("UserObj");
out.print(userObj);
out.print("</br>");

9.HttpServlet

jakarta.servlet.Servlet 【接口】
jakarta.servlet.GenericServlet implements Servlet 【抽象类】
jakarta.servlet.http.HttpServlet extends GenericServlet 【类】

以后编写程序继承HttpServlet

在这里插入图片描述

作者:Beyong    
出处:Beyong博客
github地址:https://github.com/beyong2019

本博客中未标明转载的文章归作者Beyong有,欢迎转载,但未经作者同意必须保留此段声明,且在文章明显位置给出原文连接,否则保留追究法律责任的权利。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值