目录
- Servlet 是Tomcat给后端程序员提供的开发服务器程序的API合集,借助这个更方便搭建网站的后端。
- Servlet提供的类和方法有很多主要使用的就是三个(HttpServlet、HttpServletRequest和HttpServletResponse)
1.HttpServlet:
- HttpServlet,编写servlet代码的时候第一步就是先创建类继承自HttpServlet,并重写某些方法:
核心方法 说明 init 首次创建出HttpServlet实例会调用一次 destroy 在HttpServlet实例不使用时调用一次 service 收到HTTP请求的时候调用头一次 doGet 收到GET请求的时候service调用doGet doPost 收到POST请求的时候service来调用 doPut / doDelete 收到这些请求的时候service来调用 - init 方法:创建出HttpServlet实例会调用一次,init方法的作用就是用来初始化。注意:HttpServlet的实例只是在程序启动的时候创建一次,而不是每次收到HTTP请求都重新创建实例。
- destroy方法:不一定真的能调用到!如果Tomcat关闭了,则不再调用HttpServlet了。
Tomcat的关闭: 1.杀进程, 类似于拔电源 比如点击idea中的红色方框、cmd直接点×、任务管理器结束任务...... 2.通过8005端口给Tomcat发送一个关闭操作, 类似于走正常的程序关闭电脑 这个时候Tomcat就会正常关机就可以调用到destroy方法
- service方法:Tomcat收到请求实际上是先调用service,在service里面再去根据方法调用不同的doXxx。
- 【面试题】谈一谈Servlet的生命周期。
初始阶段实例化的时候,调用一次 init 结束销毁之前,调用一次 destroy 每次收到请求,调用 service
2.HttpServletRequest:
- 当Tomcat通过Socket api读取HTTP请求(字符串),并且按照HTTP协议的格式把字符串解析成HttpServletRequest对象。
- URL是唯一资源定位符;URI是唯一资源标识符。
- 常用方法:
方法 说明 String getProtocol() 返回请求协议的名称和版本号 String getMethod() 返回请求的HTTP方法 String getPrequestURI() 返回URL中的一部分 String getContextPath() 返回ContextPath String getQueryString() 返回查询字符串 Enumeration getParameterNames() String getParameter(String name) 返回请求参数的值,参数不存在返回null String[ ] getParameterValues(String name) 返回请求参数的所有值 Enumeration getHeaderNames() 返回包含请求中所有header的key的枚举 String getCharacterEncoding() 返回请求中使用的字符编码 String getContentType() 返回请求中使用的文本类型和字符编码 int getContentLength() 返回请求主体的长度,字节为单位 String getHeader(String name) 返回指定请求头的值 InputStream getInputStream() 用来读取query string和body的内容 - 请求的对象是服务器收到的内容,不应该修改;因此上面都是读的方法不是写的方法。
3.HttpServletRequest代码实例:
3.1.打印请求的内容:
代码如下:
-
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("/showRequest")
-
public
class
showRequest
extends
HttpServlet {
-
@Override
-
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//resp是响应的对象,setContentType给响应的ContentType设置了值html
-
//声明响应body是html结构的数据
-
resp.setContentType(
"text/html");
-
-
StringBuilder
stringBuilder
=
new
StringBuilder();
-
-
//getProtocol返回请求协议的版本
-
stringBuilder.append(req.getProtocol());
-
//要将\n 替换成 <br> 否则html无法识别
-
// stringBuilder.append("\n");
-
stringBuilder.append(
"<br>");
-
-
//getMethod返回请求中http方法的名称
-
stringBuilder.append(req.getMethod());
-
stringBuilder.append(
"<br>");
-
-
//getRequestURI返回请求的uri
-
stringBuilder.append(req.getRequestURI());
-
stringBuilder.append(
"<br>");
-
-
//getRequeatURL返回请求的url
-
stringBuilder.append(req.getRequestURL());
-
stringBuilder.append(
"<br>");
-
-
//返回Context Path
-
stringBuilder.append(req.getContextPath());
-
stringBuilder.append(
"<br>");
-
-
//返回查询字符串
-
stringBuilder.append(req.getQueryString());
-
stringBuilder.append(
"<br>");
-
-
-
//拼接header中的内容
-
//getHeaderNames返回一个包含请求中所有的键值对key的值
-
Enumeration<String> headerNames = req.getHeaderNames();
-
while(headerNames.hasMoreElements()){
-
String
name
= headerNames.nextElement();
-
//getHeader以字符串的形式返回key对应的value值
-
String
value
= req.getHeader(name);
-
stringBuilder.append(name+
": " + value);
-
stringBuilder.append(
"<br>");
-
}
-
-
resp.getWriter().write(stringBuilder.toString());
-
}
-
}
3.2.获取请求中的重要参数
(query string中的值):
- 对于获取query string来说,核心的方法就是getParameter 。
- 如果在浏览器页面上已经手动对特殊符号包括汉字encode编码了,那么servlet getParameter方法会自动的针对encode的结果进行decode解码操作,不需要手动处理。注意一点:浏览器地址栏里用户输入的查询字符串中包含汉字,也不一定会出错(有的浏览器自动编码)。
- getParameter方法使用时,如果键值对不存在,得到的就是 null;如果键值对的值不存在,得到的就是 “ ”,例如查询字符串为?studentId=1&studentName= )。
- 如果不写Content-Type,浏览器就不知道用什么方式什么格式来解析。
代码如下:
-
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("/getParameter")
-
public
class
getParameterServlet
extends
HttpServlet {
-
@Override
-
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//获取query string中的键值对
-
//取值的时候,如果键值对不存在返回的是 null
-
//如果键存在,值不存在那么返回 “ ”
-
String
studentId
= req.getParameter(
"studentId");
-
String
studentName
= req.getParameter(
"studentName");
-
-
System.out.println(studentId);
-
System.out.println(studentName);
-
-
//如果不加这行代码,浏览器就会显示出 ???,这里是 = ,不能是 -
-
resp.setContentType(
"text/html; charset=utf8");
-
-
resp.getWriter().write(studentId +
" , " + studentName);
-
}
-
}
3.3.获取请求中的重要参数
(body中的值):
分为俩种情况!
- (1)如果请求的body是x-www-form-urlencode格式,form表单、这里也使用getParameter来获取。
- 用 html 和 postman 分别来操作!
- 使用html来发送form请求,需要先在webapp目录下创建一个html。
- 服务器的代码:
- 上述的前端和后端代码运行后会出现问题
- 请求req这里设置的utf8是告诉servlet(tomcat)如何解析;响应resp这里设置的utf8是告诉浏览器如何解析。
- 请求req和响应resp的字符编码。
请求这里使用这个方法: req.setCharacterEncoding("utf8"); 响应建议使用第一种, 因为不止要设置字符集还要设置格式 resp.setContentType("text/html; charset = utf8"); //resp.setCharacterEncoding("utf8");
- 加字符编码的总体原则:不要让程序猜!最好的做法就是显示声明该声明的东西。
- 通过postman来构造一个POST请求,postman也是一个http客户端,和浏览器是对等的。请求req也要设置字符集,否则还是会有乱码。
后端代码如下:
-
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("/getParameter")
-
public
class
getParameterServlet
extends
HttpServlet {
-
@Override
-
protected
void
doPost
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//如果不加上这段代码,req就会随机解析,因此页面上显示的就是乱码
-
req.setCharacterEncoding(
"utf8");
-
-
String
studentId
= req.getParameter(
"studentId");
-
String
studentName
= req.getParameter(
"studentName");
-
-
System.out.println(studentId);
-
System.out.println(studentName);
-
-
resp.setContentType(
"text/html; charset = utf8");
-
resp.getWriter().write(studentId +
", " + studentName);
-
}
-
}
- (2)如果请求的body是json格式,需要先读取body中的内容,进一步的再来读取流对象(getInputStream),下一步解析json格式,但是servlet中没有内置json解析,因此我们需要到借助第三方库jackson。
- Jackson的使用需要我们知道一个类和俩个方法。一个ObjectMapper类,方法是readValue和writeValueAsString。
- readValue的作用是先读取输入流获取要解析的字符串,再把字符串按照json格式解析得到一组键值对(map),再根据类对象创建一个实例,再遍历类对象中的属性的名字,拿着名字去上面的map中查询,查到的value赋值到对应的对象的属性中,最后返回这个构造完成的对象。
- readValue要求键值对中键的名字和类的属性名要一一对应。
- 如果类属性多,请求的key少,不会报错,少的那个属性就是null。如果类属性少,请求的key多这里key的多指的是个数多,不是种类,结果就是最后那个。如果类属性少,请求的key多这里key多的是种类,那就会报错。
- 还可以使用writeValueAsString方法来返回响应。
- 对三种返回响应的代码抓包:
后端代码如下:
-
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;
-
-
-
class
Student{
-
//1.这个student类的属性必须是public或者带有 public 的getter 和 setter
-
// 否则jackson无法访问这个对象的属性
-
//2.这个类必须要有无参版本的构造方法
-
public
int studentId;
-
public String studentName;
-
public String studentSex;
-
}
-
-
@WebServlet("/json")
-
public
class
JsonServlet
extends
HttpServlet {
-
@Override
-
protected
void
doPost
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//此处假设请求中的body是json格式的
-
//{studentId:66,studentName:"王大锤"}
-
//jackson 一个类ObjectMapper 和俩个方法
-
//一个方法是readValue,把json格式的数据转换成 java 对象
-
//另外一个方法是writeValueAsString,把java对象转换成json格式的字符串
-
-
ObjectMapper
objectMapper
=
new
ObjectMapper();
-
//readValue的第一个参数可以是字符串,也可以是输入流
-
//第二个参数是类的对象
-
Student
s
= objectMapper.readValue(req.getInputStream(),Student.class);
-
System.out.println(s.studentId);
-
System.out.println(s.studentName);
-
System.out.println(s.studentSex);
-
-
// resp.setContentType("text/html; charset = utf8");
-
// resp.getWriter().write(s.studentId + ", " + s.studentName +", " + s.studentSex);
-
-
// //响应的数据是html格式的
-
// resp.setContentType("text/html; charset = utf8");
-
// resp.getWriter().write(objectMapper.writeValueAsString(s));
-
-
-
//响应的数据是json格式的
-
resp.setContentType(
"application/json; charset = utf8");
-
resp.getWriter().write(objectMapper.writeValueAsString(s));
-
-
}
-
}
4.HttpServletResponse:
- HttpServletRequest的方法大部分都是前缀为get;HttpServletResponse的方法大部分都是前缀为set。
- 在doGet/doPost等方法中,这里面的HttpServletResponse对象都是空的。因此这些方法都是set系列也就好理解了。
- 常用方法:
方法 说明 void setStatus() 设置状态码 void setHeader(String name,String value) 设置一个header字段,如果已经存在,会覆盖 void addHeader(String name,String value) 设置一个header字段,如果存在,会再创建一个 void setContentType() 设置发送给客户端的响应的内容类型+字符编码 void setCharacterEncoding() 设置发送给客户端的响应的字符编码 void sendRedirect(String location) 重定向 PrintWriter getWriter() 用于往body中写入文本格式数据 OutputStream getOutputStream() 用于往body中写入二进制数据 - 状态码和header的设置要放到getWriter和getOutputStream前面。
5.HttpServletResponse代码示例:
5.1.设置不同的状态码
-
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 {
-
//约定一下浏览器的query string传一个参数过来
-
//127.0.0.1:8080/servlet/status?type=1
-
//如果type=1返回200,如果为2返回404
-
String
type
= req.getParameter(
"type");
-
-
if(type.equals(
"1")){
-
resp.setStatus(
200);
-
}
else
if(type.equals(
"2")){
-
resp.setStatus(
404);
-
}
else
if(type.equals(
"3")){{
-
resp.setStatus(
500);
-
}}
else{
-
resp.setStatus(
504);
-
}
-
}
-
}
5.2.设置响应的header,实现页面的自动刷新
- 在header中设置refresh属性,值是一个秒数,浏览器会在时间到了之后自动刷新
- 尽管我设置了3秒刷新一次,但是并不是精确的3000ms,会比3000略多一点
-
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("/autoRefresh")
-
public
class
AutoRefreshServlet
extends
HttpServlet {
-
@Override
-
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//直接返回响应就行
-
resp.setHeader(
"refresh",
"3");
-
resp.getWriter().write(System.currentTimeMillis()+
"");
-
}
-
}
5.3.构造一个重定向响应
- 可以设置header中的Location属性,实现跳转;也可以使用sendRedirect方法。
-
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.bilibili.com");
-
-
//第二种写法
-
resp.sendRedirect(
"http://www.bilibili.com");
-
}
-
}
6.代码案例:
- 实现表白墙:在页面上点击提交,希望在服务器这里保存数据,把数据发送给服务器;当关闭页面再启动,需要从服务器上读取之前保存过的数据,在页面上显示出来。
- 先要规划好请求和响应的细节。
- 提供俩种版本:顺序表和数据库。
使用顺序表的版本:
-
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.util.ArrayList;
-
-
@WebServlet("/message")
-
public
class
MessageServlet
extends
HttpServlet {
-
public
ObjectMapper
objectMapper
=
new
ObjectMapper();
-
public ArrayList<Message> arrayList =
new
ArrayList<>();
-
-
@Override
-
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
resp.setContentType(
"text/json; charset=utf8");
-
resp.getWriter().write(objectMapper.writeValueAsString(arrayList));
-
}
-
-
//浏览器提交数据
-
@Override
-
protected
void
doPost
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
//获取到body中的数据并且解析
-
Message
message
= objectMapper.readValue(req.getInputStream(),Message.class);
-
//将得到的数据保存
-
arrayList.add(message);
-
resp.setStatus(
200);
-
-
System.out.println(
"提交数据成功,form:" + message.getFrom() +
-
" to: " + message.getTo() +
" Message: " + message.getMessage());
-
}
-
}
-
class
Message {
-
private String From;
-
private String To;
-
private String Message;
-
public String
getFrom
() {
-
return From;
-
}
-
public
void
setFrom
(String from) {
-
From = from;
-
}
-
public String
getTo
() {
-
return To;
-
}
-
public
void
setTo
(String to) {
-
To = to;
-
}
-
public String
getMessage
() {
-
return Message;
-
}
-
public
void
setMessage
(String message) {
-
Message = message;
-
}
-
}
使用数据库的版本:
-
//使用这个类来封装DataSource
-
public
class
DBUtil {
-
private
static
volatile
DataSource
dataSource
=
null;
-
-
public
static DataSource
getDataSource
(){
-
if(dataSource ==
null){
-
synchronized (DBUtil.class){
-
if(dataSource ==
null){
-
dataSource =
new
MysqlDataSource();
-
((MysqlDataSource)dataSource).setUrl(
"jdbc:mysql://127.0.0.1:3306/java105?characterEncoding=utf8&useSSL=false");
-
((MysqlDataSource)dataSource).setUser(
"root");
-
((MysqlDataSource)dataSource).setPassword(
"111111");
-
}
-
}
-
}
-
return dataSource;
-
}
-
-
private
DBUtil
() {}
-
}
-
-
import com.fasterxml.jackson.databind.ObjectMapper;
-
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
-
-
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 javax.sql.DataSource;
-
import java.io.IOException;
-
import java.sql.Connection;
-
import java.sql.PreparedStatement;
-
import java.sql.ResultSet;
-
import java.sql.SQLException;
-
import java.util.ArrayList;
-
import java.util.List;
-
-
@WebServlet("/message")
-
public
class
MessageServlet
extends
HttpServlet {
-
// 这个对象在多个方法中都需要使用
-
private
ObjectMapper
objectMapper
=
new
ObjectMapper();
-
-
// 负责让页面获取到数据
-
@Override
-
protected
void
doGet
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
// 显式声明当前的响应数据格式 不要让客户端去猜!!!
-
resp.setContentType(
"application/json; charset=utf8");
-
// 把 messageList 转成 json 字符串, 并且返回给页面就行了.
-
List<Message> messageList =
null;
-
try {
-
messageList = load();
-
}
catch (SQLException e) {
-
e.printStackTrace();
-
}
-
resp.getWriter().write(objectMapper.writeValueAsString(messageList));
-
}
-
-
// 提交数据
-
@Override
-
protected
void
doPost
(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
-
// 获取到 body 中的数据并解析
-
Message
message
= objectMapper.readValue(req.getInputStream(), Message.class);
-
// 把这个 message 保存一下. 简单的办法就是保存在内存中.
-
// messageList.add(message);
-
try {
-
save(message);
-
}
catch (SQLException e) {
-
e.printStackTrace();
-
}
-
resp.setStatus(
200);
-
-
System.out.println(
"提交数据成功: from=" + message.getFrom()
-
+
", to=" + message.getTo() +
", message=" + message.getMessage());
-
}
-
-
private List<Message>
load
()
throws SQLException {
-
// 从数据库查询数据
-
-
// 1. 先有一个数据源
-
DataSource
dataSource
= DBUtil.getDataSource();
-
-
// 2. 建立连接
-
Connection
connection
= dataSource.getConnection();
-
-
// 3. 构造 SQL
-
String
sql
=
"select * from message";
-
PreparedStatement
statement
= connection.prepareStatement(sql);
-
-
// 4. 执行 SQL
-
ResultSet
resultSet
= statement.executeQuery();
-
-
// 5. 遍历结果集合
-
List<Message> messageList =
new
ArrayList<>();
-
while (resultSet.next()) {
-
Message
message
=
new
Message();
-
message.setFrom(resultSet.getString(
"from"));
-
message.setTo(resultSet.getString(
"to"));
-
message.setMessage(resultSet.getString(
"message"));
-
messageList.add(message);
-
}
-
-
// 6. 关闭连接
-
statement.close();
-
connection.close();
-
return messageList;
-
}
-
-
private
void
save
(Message message)
throws SQLException {
-
// 把数据保存到数据库中
-
-
// 1. 先有一个数据源
-
DataSource
dataSource
= DBUtil.getDataSource();
-
-
// 2. 建立连接
-
Connection
connection
= dataSource.getConnection();
-
-
// 3. 构造 SQL
-
String
sql
=
"insert into message values(?, ?, ?)";
-
PreparedStatement
statement
= connection.prepareStatement(sql);
-
statement.setString(
1, message.getFrom());
-
statement.setString(
2, message.getTo());
-
statement.setString(
3, message.getMessage());
-
-
// 4. 执行 SQL
-
int
ret
= statement.executeUpdate();
-
System.out.println(
"ret = " + ret);
-
-
// 5. 关闭连接
-
statement.close();
-
connection.close();
-
}
-
}
如果对您有帮助的话,
不要忘记点赞+关注哦,蟹蟹
如果对您有帮助的话,
不要忘记点赞+关注哦,蟹蟹
如果对您有帮助的话,
不要忘记点赞+关注哦,蟹蟹
转载:https://blog.csdn.net/qq_68993495/article/details/127934027
查看评论