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 容器
Servlet的执行过程
浏览器向服务器发出GET/POST请求
服务器上的Servlet容器接收到该URL,根据该URL判断为Servlet请求,此时Servlet容器将产生两个对象:请求对象(HttpServletRequest)和响应对象(HttpServletResponce)
Servlet容器根据URL检索与请求匹配的 Servlet 实例,并且创建一个线程;如果实例不存在就加载并实例化出该类Servlet
的一个实例对象,接着Servlet容器调用该实例的 init() 方法来对实例做一些初始化工作(每个Servlet容器原则上只有一个实例)
Servlet容器将刚才创建的请求对象和响应对象传递给线程
Servlet容器调用Servlet的service()方法
service()方法根据请求类型调用doGet()/doPost()方法
doGet()/doPost()执行完后,将结果返回给Servlet容器
线程销毁或放在线程池中等待回收
MVC架构
JSP充当页面角色,Servlet扮演控制器角色,两者组合构建基本的MVC三层架构模式
Servlet的生命周期
- Servlet容器加载Servlet类
- Servlet容器实例化Servlet(Servlet无参构造函数执行)
- 执行init()方法(在Servlet生命周期中,只执行一次,且在service()方法执行前执行)
- 执行service()方法,处理客户请求,doPost()或doGet()
- 执行destroy(),销毁线程
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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗