方法名称 | 调用时机 |
---|---|
init | 在 HttpServlet 实例化之后被调用一次 |
destory | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/… | 收到其他请求的时候调用(由 service 方法调用) |
我们实际开发的时候很少会重写 init / destory / service
这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程)
这里会有一道面试题: 说一下 Servlet 的生命周期
- Servlet 在实例化之后调用一次 init()
- Servlet 在每次收到请求调用一次 service()
- Servlet 在销毁之前,调用一次 destroy()
java代码
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;
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("GET 响应");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.getWriter().write("POST 响应");
}
}
使用前端代码进行测试.
doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<button onclick="getMethod()">发送 GET 请求button>
<button onclick="postMethod()">发送 POST 请求button>
<script src="https://releases.jquery.com/git/jquery-3.x-git.min.js">script>
<script>
function getMethod() {
$.ajax({
type: "get",
url: "method",
success: function(data,status){
console.log(data);
}
})
}
function postMethod() {
$.ajax({
type: "post",
url: "method",
data: "request body",
success:function(data,status){
console.log(data);
}
})
}
script>
body>
html>
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本。 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。 |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分。 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串。 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。 |
String getParameter(String name) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回null。 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象. |
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.Enumeration;
@WebServlet("/show")
public class ShowServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 将 生成的响应的body 放入到 respBody 中
StringBuilder respBody = new StringBuilder();
respBody.append(req.getProtocol()+"
");
respBody.append(req.getMethod()+"
");
respBody.append(req.getRequestURI()+"
");
respBody.append(req.getContextPath()+"
");
respBody.append("headers:
");
Enumeration<String> enumeration = req.getHeaderNames();
while(enumeration.hasMoreElements()){
String headerName = enumeration.nextElement();
respBody.append(headerName + ": ");
respBody.append(req.getHeaders(headerName)+"
");
}
resp.getWriter().write(respBody.toString());
}
}
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;
@WebServlet("/parameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId: " + userId + "," + "classId: " + classId);
}
}
在浏览器中输入 http://127.0.0.1:8080/Servlet/parameter
,此时是null,因为当前没有 query string
在浏览器中输入 http://127.0.0.1:8080/Servlet/parameter?userId=500&classId=1
java代码
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;
@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId: "+userId+","+"classId: "+classId);
}
}
html 代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="postParameter" method="POST">
<input type="text" name="userId">
<input type="text" name="classId">
<input type="submit" value="提交">
form>
body>
html>
import com.fasterxml.jackson.databind.ObjectMapper;
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.io.InputStream;
class JsonData{
public int userId;
public int classId;
}
@WebServlet("/Json")
public class PostJsonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
String respBody = readBody(req);
ObjectMapper objectMapper = new ObjectMapper();
JsonData jsonData = objectMapper.readValue(respBody,JsonData.class);
resp.getWriter().write("userId: "+ jsonData.userId+","+"classId: "+jsonData.classId);
}
private String readBody(HttpServletRequest req) throws IOException {
int contentLength = req.getContentLength();
byte[] buffer = new byte[contentLength];
InputStream inputStream = req.getInputStream();
inputStream.read(buffer);
return new String(buffer,"utf-8");
}
}
方法 | 描述 |
---|---|
void setStatus(int sc) | 为该响应设置状态码。 |
void setHeader(String name,String value) | 设置一个带有给定的名称和值的 header. 如果 name 已经存在,则覆盖旧的值. |
void addHeader(String name, String value) | 添加一个带有给定的名称和值的 header. 如果 name 已经存在,不覆盖旧的值, 并列添加新的键值对 |
void setContentType(String type) | 设置被发送到客户端的响应的内容类型。 |
void setCharacterEncoding(String charset) | 设置被发送到客户端的响应的字符编码MIME 字符集)例如,UTF-8。 |
void sendRedirect(String location) | 使用指定的重定向位置 URL 发送临时重定向响应到客户端。 |
PrintWriter getWriter() | 用于往 body 中写入文本格式数据. |
OutputStream getOutputStream() | 用于往 body 中写入二进制格式数据. |
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;
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String status = req.getParameter("status");
if (status != null){
resp.setStatus(Integer.parseInt(status));
}
resp.getWriter().write("status: "+status);
}
}
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;
@WebServlet("/refresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Refresh","1");
long time = System.currentTimeMillis();
resp.getWriter().write(time+"");
}
}
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;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(302);
// resp.setHeader("Location","http://www.baidu.com");
resp.sendRedirect("http://www.baidu.com");
}
}
直接从http://127.0.0.1:8080/Servlet/redirect
跳转到了https://www.baidu.com/
方法 | 描述 |
---|---|
Part getPart(String name) | 获取请求中给定 name 的文件 |
Collection getParts() | 获取所有的文件 |
方法 | 描述 |
---|---|
String getSubmittedFileName() | 获取提交的文件名 |
String getContentType() | 获取提交的文件类型 |
long getSize() | 获取文件的大小 |
void write(String path) | 把提交的文件数据写入磁盘文件 |
首先写好前端代码
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<form action="upload" method="POST" enctype="multipart/form-data">
<input type="file" name="myImage">
<input type="submit" value="提交图片">
form>
body>
html>
写java代码,一定要写一个注解@MultipartConfig
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
@MultipartConfig
@WebServlet("/upload")
public class uploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1. 从 req 对象中,读取 Part 对象
Part part = req.getPart("myImage");
// 2. 读取到 Part 对象中的一些参数
// 这里是打印 上传文件的真实文件名
System.out.println(part.getSubmittedFileName());
// 这里是打印 文件的类型
System.out.println(part.getContentType());
// 这里是打印 文件的大小
System.out.println(part.getSize());
// 3. 将文件写入指定目录
part.write("D:/gihub创库/JavaEE_CODE/image/myImage.jpg");
// 4. 返回一个响应
resp.getWriter().write("upload successful");
}
}
结果演示:
选择一个图片,点击提交
查看抓包的结果
请求:
响应:
服务器运行结果
DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Applicationdisplay-name>
web-app>
首先创建一个 Confession
类
class Confession{
public String from;
public String to;
public String message;
}
创建一个 confessionServlet
类 继承 HttpServlet
重写 doGet
和 doPost
方法,注解@WebServlet("/confession")
创建一个objectMapper对象
用于转换 JSON 字符串
private ObjectMapper objectMapper = new ObjectMapper();
这里是为了处理从服务器上获取到消息.
// 这个用来处理从服务器获取到消息数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
// 这里的 load() 是用来 读取服务器上的数据
List<Confession> confessionList = load();
objectMapper.writeValue(resp.getWriter(),confessionList);
}
这是为了处理提交留言到服务器上
// 这个用来处理客户端提交数据给服务器
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Confession confession = objectMapper.readValue(req.getInputStream(),Confession.class);
// 这里的 save() 是用来 提交数据在服务器上
save(confession);
resp.setContentType("application/json;charset=utf-8");
resp.getWriter().write("{\"ok\":1}");
}
由于每次刷新页面,数据就不见了.想要每次输入的数据都在,就要将数据存起来.有两种方法.一种是存文件的方法,一种是存数据库的方法.
创建一个filePath
保存文件的存储路径
private String filePath = "d:/confessionWall.txt";
约定好存文件的格式.每行是一个数据,每个数据的内容之间用\t
隔开
/**
* 向文件夹中加载数据
* @return
*/
private List<Confession> load() {
List<Confession> confessionList = new ArrayList<>();
// 此处我们需要按行读取. FileReader 本身不支持. 需要套上一层 BufferedReader
try(BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
while(true){
String line = bufferedReader.readLine();
// line=null的时候 读完了
if (line == null){
break;
}
// 设定存储的时候每行的内容是按 \t 的方法存储
// 所以读取每行,然后按 \t的方法进行 分割
String[] res = line.split("\t");
Confession confession = new Confession();
confession.from = res[0];
confession.to = res[1];
confession.message = res[2];
confessionList.add(confession);
}
} catch (IOException e) {
e.printStackTrace();
}
return confessionList;
}
/**
* 向文件夹中写入数据
* @param confession
*/
private void save1(Confession confession) {
// 这里的 true 表示追加写状态,表示不清空文件,而是从文件后面继续写
try(FileWriter fileWriter = new FileWriter(filePath,true)) {
// 按照约定好的方法写入数据
fileWriter.write(confession.from+"\t"+confession.to+"\t"+confession.message+"\n");
} catch (IOException e) {
e.printStackTrace();
}
}
首先创建一个类 ConnectionDB
用来连接数据库
在pom.xml
中引入mysql jdbc
的依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.17version>
dependency>
类 ConnectionDB
import com.mysql.cj.jdbc.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConnectionDB {
private static final String URL="jdbc:mysql://127.0.0.1:3306/confessionWall?characterEncoding=utf-8&useSSL=true&serverTimezone=UTC";
private static final String USERNAME = "root";
private static final String PASSWORD = "0000";
// 这里的volatile 和 synchronized 相当于懒汉模式
private static volatile DataSource dataSource = null;
public static DataSource getDataSource() {
if(dataSource == null){
synchronized (ConnectionDB.class){
if(dataSource == null) {
dataSource = new MysqlDataSource();
((MysqlDataSource) dataSource).setURL(URL);
((MysqlDataSource) dataSource).setUser(USERNAME);
((MysqlDataSource) dataSource).setPassword(PASSWORD);
}
}
}
return dataSource;
}
public static Connection getConnection() throws SQLException {
return getDataSource().getConnection();
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
if(resultSet != null){
try{
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement != null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
数据库中的代码
create database confessionWall;
use confessionWall;
create table confession(
`from` varchar(1024),
`to` varchar(1024),
`message` varchar(1024)
);
/**
* 从数据库中读取数据
* @return
*/
private List<Confession> load() {
List<Confession> confessionList = new ArrayList<>();
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try{
// 和数据库建立连接
connection = ConnectionDB.getConnection();
// 借助 PreparedStatement 拼接 SQL 语句
String sql = "select * from confession";
statement = connection.prepareStatement(sql);
// 执行 SQL 语句
resultSet = statement.executeQuery();
// 遍历结果集
while (resultSet.next()){
Confession confession = new Confession();
confession.from = resultSet.getString("from");
confession.to = resultSet.getString("to");
confession.message = resultSet.getString("message");
confessionList.add(confession);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 关闭释放资源
ConnectionDB.close(connection,statement,resultSet);
}
return confessionList;
}
/**
* 从数据库中写入数据
* @param confession
*/
private void save(Confession confession) {
Connection connection = null;
PreparedStatement statement = null;
try {
// 1. 先和数据库建立连接
connection = ConnectionDB.getConnection();
// 2. 构造拼装 SQL
String sql = "insert into confession values (?,?,?)";
// 这里的 ? 号是占位符,下标是从1开始
statement = connection.prepareStatement(sql);
statement.setString(1,confession.from);
statement.setString(2,confession.to);
statement.setString(3,confession.message);
// 3. 执行 SQL
int ret = statement.executeUpdate();
// 这里 ret 表示的是受影响的行数,如果为1才是插入成功
if(ret == 1){
System.out.println("插入成功!");
}else {
System.out.println("插入失败!");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
// 4. 关闭释放资源
ConnectionDB.close(connection,statement,null);
}
}
首先加入 jquery
<script src="https://releases.jquery.com/git/jquery-git.min.js">script>
<script>
// 1. 在页面加载的时候,访问服务器,从服务器获取到的消息列表,并展示出来
function load() {
$.ajax({
// 类型约定好了的是 GET ,url也约定好了是 confession
type: "GET",
url: "confession",
success: function(data,status){
// data 是响应的 body
// 这里的 .parent 是根据之前写的代码来决定的
let parent = document.querySelector('.parent');
// 由于data存储的时候自动变成了数组的形式
// 如果没有变还需要 自己进行解析 JSON.parse(data);
let messages = data;
for (let message of messages){
let row = document.createElement('div');
row.className = 'elem';
row.innerHTML = message.from + '对' + message.to + '说: ' + message.message;
parent.appendChild(row);
}
}
});
}
load();
script>
<script>
// 这里需要构造一个 HTTP 请求.把消息发送给服务器保存起来
$.ajax({
type: "POST",
url: "confession",
// 将body的内容变成json的格式
data: JSON.stringify({from: user1,to: user2,message: message}),
contentType: "application/json; charset=utf-8",
success: function(data,status){
if (data.ok == 1){
console.log("提交消息成功!");
}else {
console.log("提交失败!");
}
}
});
script>
首次进入页面没有内容
输入 小明 对 小强 说 hello
输入 小强 对 小红 说 你真好
刷新页面或者重启服务器.该页面的内容都在. 查看路径 d:/confessionWall.txt
下的文件内容
首次访问还没有数据
输入 小明 对 小红 说 你好
输入 小红 对 小明 说 你也好
刷新页面或者重启服务器.该页面的内容都在.查看数据库