目录
1、核心方法:
这些方法的调用时机,就构成了“Servlet”的生命周期
注:
- 在写Servlet代码时,第一步就是先创建类,继承自HttpServlet,并且重写其中的某些方法
- 在实际的开发中,主要重写doXXX方法,很少会重写init/destory/service
- HttpServlet的实例只是在程序启动时创建一次,而不是每次收到HTTP请求都重新创建实例
- tomcat收到请求,实际上是先调用service,在service里面再去根据方法,调用不同的doXXX
HttpServletRequest关键方法:
HttpServletResponse关键方法:
2、获取GET请求信息:
请求对象提供的都是getXXX方法,用来获取的,修改是setXXX方法
对于请求的信息,我们运用HttpServletRequest类的方法来进行请求信息的获取:
比如我们访问的url为http://127.0.0.1:8080/Test/requestServlet?key=10&a=100&b=200,很明显这是使用查询字符串构造的一个GET请求,通过HttpServletRequest类一系列对应的方法,我们可以获取到这个请求的方法类型,协议版本,URL,查询字符串,头部的一些信息等。其中查询字符串与头部信息的获取先要使用getParameterNames方法或者getHeaderNames方法获取所有的查询字符串或头部信息的所有key值,这个一个枚举对象,然后在根据getParameter或者getHeader方法通过key值遍历枚举对象获取value。
代码测试看结果:
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("/requestServlet")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//访问链接:http://127.0.0.1:8080/hello_servlet/showreq?key=10&a=100&b=200
StringBuilder stringBuilder = new StringBuilder();
resp.setContentType("text/html; charset=utf-8");
//1协议名称与版本
stringBuilder.append("协议版本:");
stringBuilder.append(req.getProtocol());
stringBuilder.append("<br>");
//2方法类型
stringBuilder.append("方法:");
stringBuilder.append(req.getMethod());
stringBuilder.append("<br>");
//3获取查URL路径
stringBuilder.append("URL路径:");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("<br>");
//4URL(不包括查询字符串后面的部分)
stringBuilder.append("URL(不包括查询字符串后面的部分):");
stringBuilder.append(req.getRequestURL());
stringBuilder.append("<br>");
//5一级路径
stringBuilder.append("一级路径:");
stringBuilder.append(req.getContextPath());
stringBuilder.append("<br>");
//6查询字符串
stringBuilder.append("查询字符串:");
stringBuilder.append(req.getQueryString());
stringBuilder.append("<br>");
//7正文编码格式
stringBuilder.append("正文编码格式:");
stringBuilder.append(req.getCharacterEncoding());
stringBuilder.append("<br>");
//8mine
stringBuilder.append("mine:");
stringBuilder.append(req.getContentType());
stringBuilder.append("<br>");
//9正文长度
stringBuilder.append("正文长度:");
stringBuilder.append(req.getContentLength());
stringBuilder.append("<br>");
//10获得每一个查询字符串的键值:
stringBuilder.append("<h3>获得每一个查询字符串的键值:</h3>");
Enumeration query = req.getParameterNames();
while(query.hasMoreElements()) {
String key = (String)query.nextElement();
stringBuilder.append(key);
stringBuilder.append(":");
stringBuilder.append(req.getParameter(key));
stringBuilder.append("<br>");
}
//11获得头部的键值
stringBuilder.append("<h3>获得头部的键值:</h3>");
Enumeration header = req.getHeaderNames();
while(header.hasMoreElements()) {
String key = (String)header.nextElement();
stringBuilder.append(key);
stringBuilder.append(":");
stringBuilder.append(req.getHeader(key));
stringBuilder.append("<br>");
}
resp.getWriter().write(stringBuilder.toString());
}
}
其中查询字符串与头部信息的获取先要使用getParameterNames方法或者getHeaderNames方法获取所有的查询字符串或头部信息的所有key
值,这个一个枚举对象,然后在根据getParameter或者getHeader方法通过key
值遍历枚举对象获取value
。
成功启动后(如何部署程序,前面说过了,感兴趣的小伙伴可以自行去查看一下0,去浏览器查看结果:
这里如果你出现乱码了,中文的编码有很多种,其中最常见就是utf8,如果没有显式的指定编码方式,则浏览器不能正确的识别编码,就会出现乱码,可以在代码中,通过resp.setContentType("text/html;charset=utf8");显式指定编码方法,一般情况就不会再有乱码了,但是,如果你还是乱码,可以去检查一下IDEA:
这样设置后,应该就不会有问题啦!
3、Post请求的构造
在同一webapp里面,关联路径不能够相同,不然Tomcat跑不起来,对于GET请求,可以使用URL的查询字符串进行构造,但是POST请求不行,需要使用form或者ajax。
构造Post请求(使用ajax构造):
在webapp目录下创建一个HTML文件,用来构造POST请求,首先我们先的引入jquery依赖(https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js导入依赖),然后调用ajax构造请求。
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$.ajax({
type: "post",
url: "method",
success: function (body){
console.log(body);
}
})
</script>
注意上面的URL属性不能加/
,加上表示的就是绝对路径了,当然你也可以使用./
来表示相对路径,但是在Servlet注解关联路径必须得加上/
。
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 doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("POST请求");
}
}
打包部署,刷新页面:
4、Post请求信息的获取
我们知道post请求的请求信息在http格式中的body
部分当中,而body
中的请求内容的格式是有很多种的,比如最常见的有:
- x-www-form-urlencode格式,通过form表单或者postman构造。
- json格式
- form-data格式
x-www-form-urlencode格式:
key=value&key=value&...
form表单创建x-www-form-urlencode格式
请求:
<!DOCTYPE html>
<html lang="ch">
<head>
<meta charset="UTF-8">
<title>post</title>
</head>
<body>
<form action="./postParameter" method="post" accept-charset="utf-8">
<span>userId</span>
<input type="text" name="userId">
<span>classId</span>
<input type="text" name="classId">
<input type="submit" value="提交">
</form>
</body>
</html>
Servlet程序接收和处理请求:
对于x-www-form-urlencode格式
请求可以直接使用HttpServletRequest
中的getParameter
方法依据key
来获取value
,然后再将获取到的数据返回,form表单构造的请求会自动跳转页面。
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 GetPostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取post请求body请求中的参数
//设置请求与响应编码格式
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html; charset=utf8");
//比如useId = classId=
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
//写会数据
resp.getWriter().write("userId=" + userId + ", " + "classId=" + classId);
}
}
结果:
json格式:
{ \{{
k e y : v a l u e , key:value,key:value,
k e y : v a l u e , key:value,key:value,
k e y : v a l u e , key:value,key:value,
. . . ......
} \}}
对于json格式,手动解析不容易,因为json里面的字段是可以嵌套的,但我们可以借助第三方库来解析处理json,比如Jackson,Jackson依赖导入过程如下【中央仓库】:
复制到pom.xml中:
处理json请求步骤:
第一步,在前端js代码中构造出格式为json
格式的请求。
其中ajax
构造post
请求,使用contentType
来说明请求的类型,data
属性来设置body
的内容。
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<title>json</title>
</head>
<body>
<!-- 前端HTML部分 -->
<input type="text" id="userId">
<input type="text" id="classId">
<input type="button" id="submit" value="提交">
<!-- 如果已经准备好本地的jQuery就导入本地的,否则可以找网上的jQuery cdn网络路径 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
let userIdInput = document.querySelector("#userId");
let classIdInput = document.querySelector("#classId");
let button = document.querySelector("#submit");
button.onclick = function() {
$.ajax({
type : "post",
url: "getJsonPost",
contentType: "appliaction/json",
data:JSON.stringify({
userId: userIdInput.value,
classId:classIdInput.value
}),
success: function(body){
console.log(body);
}
})
}
</script>
</body>
</html>
第二步,在java后端代码中使用Jackson处理。
- 创建Jackson核心对象ObjectMapper对象。
- 读取请求中的body信息,该过程通过ObjectMapper对象的readValue方法实现。
- 创建用来接受json数据的类。
- readValue方法的参数有两个,第一个参数用来表示请求的来源,可以是路径字符串,与可以是InputSream对象,也可以是File对象,第二个参数表示接收json数据的类对象。
- 处理并响应请求。
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 User {
public String userId;
public String classId;
}
@WebServlet("/JsonPost")
public class GetJsonPostServlet extends HttpServlet {
//1.创建一个Jackson的核心对象
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//格式
resp.setContentType("text/html; charset=utf8");
//处理
//2.读取body请求的内容,使用ObjectMapper对象的readValue方法来解析
//就是将字符串转换成java的对象,readValue方法的第一个参数可以是路径字符串可以是输入流对象,引入可以是File对象
//第二个参数,表示需要将请求的json格式数据转换成哪一个java对象
User user = objectMapper.readValue(req.getInputStream(), User.class);
System.out.println(user.userId);
System.out.println(user.classId);
resp.getWriter().write("userId=" + user.userId + " ,classId=" + user.classId);
}
}
结果;
readValue方法基本原理:
读取json格式的数据,并解析成键值对。
便利这些键值对,获得key,并与所需传入的对象中的属性(反射)相比,如果key与属性的名字相同,则把key对应的value赋值给这个属性,否则就跳过,所有的键值对便利完后,这个对象差不多就被构造的差不多了。
5、响应的构造
案例1: 设置响应状态码
设置方法很简单,只需要调用httpServletResponse
对象中的setStatus
方法就可以了
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 {
//格式
resp.setContentType("text/html; charset=utf8");
//设置状态码
int status = 200;
resp.setStatus(status);
resp.getWriter().write("hello,这是" + status + "状态码的响应内容!");
}
}
网页显示:
我把状态码修改为404
,网页显示如下:
案例2:自动页面刷新
自动页面刷新只要在响应中设置一个header: Refresh就能实现页面的定时刷新了,对于响应header
的设置,我们可以通过HttpServletResponse
对象中的setHeader
方法来设置Refresh属性和刷新频率。
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.setContentType("text/html; charset = utf8");
//设置Refresh,第二个参数表示刷新频率,单位是秒
resp.setHeader("Refresh", "1");
//响应
resp.getWriter().write("时间戳:" + System.currentTimeMillis());
}
}
页面显示:
案例3:重定向案例
第一步,设置状态码为302
。
第二步,设置header:Location,调用setHeader
方法时,第一个参数填Location
,表示设置header
字段为Location
,第二个参数为重定向的目的地址,你要重定向到哪一个网址就传入哪一个地址的字符串。
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.setContentType("text/html; charset = utf8");
//设置状态码
resp.setStatus(302);
//设置重定向字段与地址,如跳转到力扣官网
resp.setHeader("Location", "https://leetcode.cn/");
}
}
效果:
当然,servlet提供了更为简便的重定向方法,就是使用HttpServletResponse
类中的sendRedirect
方法。
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//格式
resp.setContentType("text/html; charset = utf8");
//设置状态码
// resp.setStatus(302);
// //设置重定向字段与地址,如跳转到力扣官网
// resp.setHeader("Location", "https://leetcode.cn/");
resp.sendRedirect("https://leetcode.cn/");
}
}
效果与上面是一样的。
本期结束啦!下期见~