Java Web03:Servlet

Servlet是开发动态Web的一门技术,提供一个接口Servlet,通常开发Servlet程序只需要两步:

  • 编写一个Java类,实现Servlet接口
  • 将类部署到Web服务器

把实现了Servle接口的Java程序叫做Servlet

GenericServlet类实现了Servlet接口,HttpServlet类继承了GenericServlet类,因此只需要继承HttpServlet类即可

第一个Servlet程序

1、构建一个Maven项目

  • 为了便于以后统一管理,创建一个干净的项目,删掉src目录
  • 统一配置pom.xml文件,将需要的依赖包导入进来
  • 这个空的项目称为Maven主项目,子项目放在单独创建的module里(也就是勾选"Create from archetype"创建Maven项目),就可以公用导入的依赖包了
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ServletStudy</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.2</version>
        </dependency>
    </dependencies>
</project>

2、创建子项目module(见上节)

  • 创建子项目以后,其pom.xml文件中会多出一个parent标签,而父项目的pom.xml文件则多出一个module标签
  • 子项目可以直接使用父项目导入的依赖包
  • 注意更换子项目的web.xml内容,创建java和resources目录

3、编写Java程序

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 继承HttpServlet类
 * HttpServlet继承了GenericServlet
 * GenericServlet实现了Servlet接口
 */
public class HelloServlet extends HttpServlet {

    /**
     * 重写doGet()和doPost()方法
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        /**
         * 响应的类型:html
         * 编码:utf-8
         */
        res.setContentType("text/html;charset=utf-8");

        /**
         * 获取响应的输出流
         */
        PrintWriter out = res.getWriter();
        out.println("<html>");
        out.println("<head>");
        out.println("<title>HelloServlet</title>");
        out.println("</head>");
        out.println("<body>");
        out.println("<h1>Servlet访问成功!</h1>");
        out.println("</body>");
        out.println("</html>");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

4、编写Servlet的映射

  • Java程序要通过浏览器访问
  • 而浏览器需要连接Web服务器,因此需要在服务器中注册Servlet(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_4_0.xsd"
         version="4.0"
         metadata-complete="true">
    <!--web.xml用来配置核心应用-->
    <!--注册Servlet-->
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
    <!--映射Servlet,给定访问的相对路径:localhost:8080/Servlet01/Hello-->
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/Hello</url-pattern>
    </servlet-mapping>
</web-app>

5、在webapp目录编写一个header.html文件,在Tomcat中配置项目路径为"localhost:8080/Servlet01",然后启动Tomcat

  • 访问"localhost:8080/Servlet01",读取的是index.jsp
  • 访问"localhost:8080/Servlet01/Hello",读取的是Servlet映射的Java程序
  • 访问"localhost:8080/Servlet01/header.html",读取的header.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>导航栏</h1>
</body>
</html>

Servlet原理

Servlet运行在Servlet容器中,它的运行需要容器的支持,由容器管理从创建到销毁的整个过程

而Tomcat 是最常用的JSP/Servlet 容器

image

Servlet的执行过程

  1. 浏览器向服务器发出GET/POST请求

  2. 服务器上的Servlet容器接收到该URL,根据该URL判断为Servlet请求,此时Servlet容器将产生两个对象:请求对象(HttpServletRequest)和响应对象(HttpServletResponce)

  3. Servlet容器根据URL检索与请求匹配的 Servlet 实例,并且创建一个线程;如果实例不存在就加载并实例化出该类Servlet

    的一个实例对象,接着Servlet容器调用该实例的 init() 方法来对实例做一些初始化工作(每个Servlet容器原则上只有一个实例

  4. Servlet容器将刚才创建的请求对象和响应对象传递给线程

  5. Servlet容器调用Servlet的service()方法

  6. service()方法根据请求类型调用doGet()/doPost()方法

  7. doGet()/doPost()执行完后,将结果返回给Servlet容器

  8. 线程销毁或放在线程池中等待回收

MVC架构

JSP充当页面角色Servlet扮演控制器角色,两者组合构建基本的MVC三层架构模式

img

Servlet的生命周期

  1. Servlet容器加载Servlet类
  2. Servlet容器实例化Servlet(Servlet无参构造函数执行)
  3. 执行init()方法(在Servlet生命周期中,只执行一次,且在service()方法执行前执行)
  4. 执行service()方法,处理客户请求,doPost()或doGet()
  5. 执行destroy(),销毁线程

img

ServletContext对象

Servlet容器在启动时,会为每个项目创建一个对应的ServletContext对象,它代表了当前的Web应用

因为每个Servlet容器只有一个实例,如果有多个Java程序实现Servlet接口,为了可以复用其他类的一些内容,可以将这些内容存储

在ServletContext对象中,这样同一个Servlet容器中的类可以公用这个ServletContext对象

应用:数据共享、获取初始化参数、请求转发

共享数据

A类设置属性

setAttribute()

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class A extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) {

        /**
         * getServletContext()方法访问ServletContext对象
         */
        ServletContext servletContext = this.getServletContext();
        String username = "ty";

        /**
         * setAttribute()方法添加属性,让其他类复用
         */
        servletContext.setAttribute("username", username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

B类获取属性

getAttribute()

注意:每个类都需要在web.xml文件中注册和映射Servlet

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class B extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        res.setContentType("text/html;charset=utf-8");
        
        /**
         * getServletContext()方法访问ServletContext对象
         */
        ServletContext servletContext = this.getServletContext();

        /**
         * getAttribute()方法获取其他类定义的属性
         */
        String username = (String) servletContext.getAttribute("username");
        res.getWriter().println(username);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

获取初始化参数

getInitParameter()

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();
        
        /**
         * getInitParameter()方法获取初始化信息
         */
        String url = servletContext.getInitParameter("url");
        res.getWriter().println(url);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
<!--web.xml文件添加context-param标签,设置初始化参数-->
<context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>

请求转发

转发访问时URL不会变

getRequestDispatcher()、forward()

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();

        /**
         * getRequestDispatcher()设置要转发的路径,访问当前路径时会变成访问那个路径
         */
        RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher("/其他路径");

        /**
         * forward()方法实现请求转发
         */
        requestDispatcher.forward(req, res);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

读取资源文件

配置文件,放在resources目录下,打包后的相对路径,也就是classpath为"/WEB-INF/classes/db.properties"

因为资源文件需要经常读取,不能放在本地,所以需要放在打包好的Web文件中

/**
 * db.properties
 */
username=root
password=123456
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {

        res.setContentType("text/html;charset=utf-8");

        ServletContext servletContext = this.getServletContext();

        /**
         * getResourceAsStream()方法将资源转换为文件流
         */
        InputStream resourceAsStream = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");

        /**
         * Properties类读取文件流
         */
        Properties properties = new Properties();
        properties.load(resourceAsStream);
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");

        /**
         * 发送到网页
         */
        res.getWriter().println("用户名:" + username);
        res.getWriter().println("密码:" + password);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}

注:如果配置文件放在java目录,则导出配置文件会失败,需要在子项目的pom.xml文件的build标签中配置resources

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
posted @   振袖秋枫问红叶  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示