文章目录
HttpServlet
我们写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自 HttpServlet, 并重写其中的某些方法.
咱们自己写的代码就是继承这个类,然后重写其中的方法,来被Tomcat执行到 (多态)
核心方法
方法名称 | 调用时机 |
---|---|
init | 在 HttpServlet 实例化之后被调用一次 |
destroy | 在 HttpServlet 实例不再使用的时候调用一次 |
service | 收到 HTTP 请求的时候调用 |
doGet | 收到 GET 请求的时候调用(由 service 方法调用) |
doPost | 收到 POST 请求的时候调用(由 service 方法调用) |
doPut/doDelete/doOptions/… | 收到其他请求的时候调用(由 service 方法调用) |
我们实际开发的时候主要重写 doXXX 方法, 很少会重写 init / destory / service .
这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程).
处理POST请求
HttpServletRequest
当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成HttpServletRequest 对象.
核心方法
方法 | 描述 |
---|---|
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 对象. |
在初步了解了这个方法之后,接下来通过实例加深理解
代码示例: 打印请求信息
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//调用HttpServletRequest涉及到的几个关键API
StringBuilder stringBuild = new StringBuilder();
stringBuild.append(req.getProtocol());
stringBuild.append("<br>");
stringBuild.append(req.getMethod());
stringBuild.append("<br>");
stringBuild.append(req.getRequestURI());
stringBuild.append("<br>");
stringBuild.append(req.getContextPath());
stringBuild.append("<br>");
stringBuild.append(req.getQueryString());
stringBuild.append("<br>");
stringBuild.append("<h3>headers:</h3>");
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
String headerValue = req.getHeader(headerName);
stringBuild.append(headerName+":"+headerValue+"<br>");
}
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write(stringBuild.toString());
}
}
代码示例: 获取 GET 请求中的参数
GET 请求中的参数一般都是通过 query string 传递给服务器的.
此时浏览器通过 query string 给服务器传递了两个参数, userId 和 classId, 值分别是 1111 和 100在服务器端就可以通过 getParameter 来获取到参数的值.
创建GetParameter类
重新部署程序, 在浏览器中通过http://127.0.0.1:8080/hello02/getParameter
访问, 可以看到
当没有 query string的时候, getParameter 获取的值为 null
如果通过http://127.0.0.1:8080/hello02/getParameter?userId=123&classId=456
访问, 可以看到
此时说明服务器已经获取到客户端传递过来的参数.
getParameter 的返回值类型为 String. 必要的时候需要手动把 String 转成 int.
POST请求body格式
- x-www-from-urlencoded
- from-data
- json
1 x-www-from-urlencoded
如果请求是这个方式,获取方式和get一样,也是使用getParameter
如何在前端创建这种格式?
- form表单
- postman
通过form表单:
创建类 PostParameterServlet
@WebServlet("/postGetParameter")
public class PostGetParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId="+userId+" classId="+classId);
}
}
创建 test.html, 放到 webapp 目录中
<form action="postGetParameter" method="post">
<input type="text" name="userId">
<input type="text" name="classId">
<input type="submit" value="提交">
</form>
在页面中的样式:
点击提交按钮之后:
通过fiddler抓包之后的结果如下
3 json
上面的数据结构为userId=123&classId=456
json的数据结构为
{
userId:123,
classId:456
}
此时这种body为json的格式来说,如果手动解析,其实不是很容易 (JSON里面的字段可以嵌套) 可以使用第三方库,直接处理json处理数据
这里使用的是jackson
前端代码:
<body>
<input type="text" id="userId">
<input type="text" id="classId">
<input type="button" value="提交" id="submit">
<script src="http://libs.baidu.com/jquery/2.0.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: 'postJson',
contentType: 'application/json',
data: JSON.stringify({
userId: userIdInput.value,
classId: classIdInput.value
}),
success: function(body) {
console.log(body);
}
});
}
</script>
后端代码
class User{
public int userId;
public int classId;
}
@WebServlet("/postJson")
public class PostJsonServlet extends HelloServlet{
ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
User user = objectMapper.readValue(req.getInputStream(), User.class);
resp.getWriter().write("userId="+user.userId+" classId="+user.classId);
}
}
HttpServletResponse
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到HttpServletResponse 对象中.
然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过Socket 写回给浏览器.
核心方法
方法 | 描述 |
---|---|
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 中写入二进制格式数据. |
代码示例: 设置状态码
@WebServlet("/status")
public class StatusServlet extends HelloServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);
resp.getWriter().write("hello");
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LUfDoNkz-1654141414193)(C:/Users/78581/AppData/Roaming/Typora/typora-user-images/image-20220601151411755.png)]
此时通过fiddler抓包就看状态码为404,但是页面仍然显示了输出结果,原因是:服务器返回状态码,只是告诉服务器,当前的响应是什么状态,并不会影响浏览器照常的去显示body部分的内容
代码示例: 自动刷新
实现一个程序, 让浏览器每秒钟自动刷新一次. 并显示当前的时间戳.
创建AutoRefreshServlet类
@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Refresh","1");
resp.getWriter().write("timeStamp"+System.currentTimeMillis());
}
}
浏览器显示结果为
通过fiddler抓包可以看到,
通过setHeader方法,设置响应报头中的Refreash属性
代码示例: 重定向
实现一个程序, 返回一个重定向 HTTP 响应, 自动跳转到另外一个页面
创建 RedirectServlet 类
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendRedirect("https://www.baidu.com");
}
}