Fighting
一、HttpServlet
方法 | |
---|---|
doGet | 处理 GET 请求 |
doPost | 处理POST请求 |
doPut/Delete… | 处理其他方法的请求 |
init | HttpServlet实例化后调用一次 |
service | 收到HTTP请求时调用 |
destory | HttpServlet对象不再使用后调用一次) |
Servlet的生命周期: |
- Servlet对象是由Tomcat实例化的,并在实例化完成后调用init()方法
- Tomcat 收到的每一个请求,都通过对应的 Servlet 的service()方法处理
- Tomcat 在结束之前,会调用 Servlet 的 destroy 方法(直接杀死进程时(直接关闭进程),不调用;通过Tomcat的管理端口(8005)关闭时,调用
二、HttpServletRequest
Tomcat通过Socket API读取HTTP请求(字符串),按照HTTP协议的格式把字符串解析成HttpServletRequest对象
- IDEA使用utf-8编码;浏览器默认跟随操作系统的编码方式,不一定是按照utf-8编码的;所以解析数据时会出现问题,需要声明编码方式
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
1. 获取参数
(1). 获取 queryString 中的参数(value)
// 获取程序猿传递的参数 GET方法通过queryString传递,用getParameter获取
@WebServlet("/showGetParameter")
public class showGetParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
resp.getWriter().write("username = " + username + "</br>" + "password = " + password);
}
}
(2). body 中的参数(value)
- x-www-form-urlencode格式( 与queryString中的格式相同)
//获取程序员传递的参数 请求通过body传递参数,x-www-form-urlencoded格式,用getParameter
@WebServlet("/PostParameter")
public class PostParameter extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
resp.getWriter().write("username = " + username + "</br>" + "password = " + password);
}
}
- json 格式
需要使用 Jackson 第三方库了,在pom.xml中引入 Jackson 库
关键类 ObjectMapper
关键方法 readValue
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
// 此处Message的成员变量名,要和body中的key对应
class Message {
public String username;
public String password;
}
@WebServlet("/Json")
public class JsonParaServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf8");
// Jackson 中的类,用于解析json
ObjectMapper mapper = new ObjectMapper();
// 一个message就是一个json对象,mapper遍历Message中成员属性,再去找到相应的body中的key,将value赋值给成员属性
// Message.class是类对象,告诉mapper把json转成哪个类的对象
Message message = mapper.readValue(req.getInputStream(),Message.class);
resp.getWriter().write("username = " + message.username + "</br>" + "password = " + message.password);
}
}
- readValue() 参数可以是 String(body内容组成的字符串)、InputStream(body的字节流对象)、byte[ ](body内容组成的字节数组)、
class Message {
public String username;
public String password;
}
@WebServlet("/Json")
public class JsonParaServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf8");
ObjectMapper mapper = new ObjectMapper();
Message message = mapper.readValue(readBody(req),Message.class);
resp.getWriter().write("username = " + message.username + "</br>" + "password = " + message.password);
}
public String readBody(HttpServletRequest req) throws IOException {
// 得到body的字节流对象
InputStream inputStream = req.getInputStream();
// 获取body的长度,单位是字节
int len = req.getContentLength();
// 字节数组 存放body内容
byte[] bytes = new byte[len];
inputStream.read(bytes);
// 需要说明的是,此处字节数组(二进制数据)以字节为单位,字符串(文本数据)以字符为单位,要指定字符集,说明字节数组当前的编码方式,用这种编码方式来解析字节数组,转变成字符串
// java 使用Unicode字符集编码,一个字符是两个字节;但是此处的从body中读入的字节数组可不一定是使用Unicode编码的
String body = new String(bytes, "utf8");
return body;
}
}
2、获取请求中的其他内容
@WebServlet("/showRequest")
public class showRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charser=utf-8");
StringBuilder html = new StringBuilder();
//获取方法
html.append(req.getMethod());
html.append("</br>");
//获取URL
html.append(req.getRequestURI());
html.append("</br>");
//获取协议名
html.append(req.getProtocol());
html.append("</br>");
//获取ContextPath
html.append(req.getContextPath());
html.append("</br>");
//获取queryString
html.append(req.getQueryString());
html.append("</br>");
html.append("</br>");
html.append("</br>");
html.append("</br>");
//将请求头的key放到一个枚举数组
Enumeration<String> headers = req.getHeaderNames();
while(headers.hasMoreElements()){
String headerName = headers.nextElement();
html.append(headerName);
html.append(": ");
//获取相对应的value
String value = req.getHeader(headerName);
html.append(value);
html.append("</br>");
}
resp.getWriter().write(html.toString());
}
三、HttpServletResponse
- doXXX方法根据请求,计算得到响应,把响应的数据涉及到HttpServletResponse中
- Tomcat 把这个对象按照HTTP协议的格式,转成一个字符串,通过Socket写给服务器
@WebServlet("/status")
public class statusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 设计一个header,key相同会覆盖旧值
resp.setHeader("qust","rubbish");
// 设计一个header,key相同不会覆盖旧值
resp.addHeader("qust","strong");
// 重定向,页面自动跳转到 百度界面
resp.sendRedirect("http://www.baidu.com");
//设置状态码
resp.setStatus(404);
resp.getWriter().write("状态码不影响body的内容d");
}
}
1、自动刷新
页面每隔1s刷新一次,设置响应头
@WebServlet("/autoRefresh")
public class autoRefresh extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.setHeader("Refresh","1");
resp.getWriter().write("时间是: " + System.currentTimeMillis());
}
}
- 设置响应的body 为json格式,此时前端的响应对象data就是一个数组,里面的每一个对象就是一个json信息
注意设置ContentType,即设置 body内容的类型,为 application/json
class Message {
public String from;
public String to;
public String mes;
}
@WebServlet("/MessageWail")
public class MessageWail extends HttpServlet {
private List<Message> messages = new ArrayList<Message>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("application/json;charset=utf-8");
ObjectMapper objectMapper = new ObjectMapper();
// 将messages数组中的消息对象都转变成 json形式的内容
String jsonString = objectMapper.writeValueAsString(messages);
resp.getWriter().write(jsonString);
}
四、在Servlet程序中同时部署静态页面
将HTML文件放到webapps目录下面,可通过静态页面向服务器发送请求
<!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>Document</title>
</head>
<body>
//此处是相对路径,HTML和PosTParameter同在一个ContextPath下
<form action="PostParameter" method="POST">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
六、Session 和 Cookie
第一次登录CSDN后,后面在登录的时候直接跳转到博客主页面,而不是登录页面;此处就是应用了 Session和Cookie 共同存储用户信息
- Session(会话)是服务器存储数据的一种机制,键值对结构,主要用于存储用户的各种信息
- Cookie 是浏览器(客户端)存储数据的一种机制,键值对结构,主要用于存储用户的各种信息
- HttpSession是存储在服务器内存中的,当服务器重启之后,内存中的数据就没有了,原来的HttpSession也就没有了
使用Session和Cookie共同存储用户信息
- 可以使客户端轻量;客户端和服务器传输的资源减少,节约网络带宽;数据都在服务器,客户端出现问题,数据不会有损害
- 用户第一次登录webapp(网站)时,服务器生成一个会话(键值对),key是sessionId,value是HttpSession对象,HttpSession对象也是一个键值对结构,存储用户信息;将sessionId通过Set-Cookie返回给浏览器存储;再次登录时,客户端通过Cookie传送sessionId(Cookie中所有的东西都传),服务器找到相应的用户信息
- sessionId是唯一的,每一个用户都有一个唯一的sessionId
- Httpsession中的信息是程序员自定义的
方法
- HttpServletRequest类的方法
- HttpSession getSession()
- 参数是true
根据请求传来的sessionId,如果找到对应的HttpSession对象,返回此对象
如果没有找到,新建一个键值对(sessionId + HttpSession) - 参数是false
根据请求传来的sessionId,如果找到对应的HttpSession对象,返回此对象
如果没有找到,直接返回 - Cookie [ ] getCookie()
每一个Cookie对象就是一个键值对 - HttpSession类的方法
- Object getAttribute(String key)
根据key获取value - void setAttribute(String key, Object value)
设置一个键值对
七、登录程序的实现
- 读取用户名和密码
- 校验用户名和密码
- 判断是否登录成功
- 创建会话,保存自定义信息
- 重定向界面
<!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>登入页面</title>
</head>
<body>
<form action="login" method="post">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
//登入流程 固定套路
@WebServlet("/login")
public class SessionServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 1.读取用户的用户名和密码
// form标签body中的参数是 queryString的形式,通过getParameter()获取参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 2.校验用户名和密码
if(username == null || username.equals("") || password == null || password.equals("")){
resp.getWriter().write("<h3>用户名或密码为空</h3>");
return;
}
// 3. 判断是否登入成功
// 此处规定用户名为 Guo, 密码是 123456, 正常情况下,用户名和密码是存储在数据库中的
if(!username.equals("Guo") || !password.equals("123456")){
resp.getWriter().write("<h3>用户名或密码错误<h3>");
return;
}
// 4.创建会话,保存自定义信息
HttpSession httpSession = req.getSession(true);
// 添加一个登入次数
httpSession.setAttribute("visited",0);
// 5.重定向页面,页面名称就是index,重定向的请求是GET方法
resp.sendRedirect("index");
}
}
@WebServlet("/index")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 获取 HttpSession 对象,参数是false,如果没有 对应的sessionID 不会创建 HttpSession对象
HttpSession session = req.getSession(false);
if(session == null){
resp.getWriter().write("<h3>当前未登录,兄弟</h3>");
return;
}
// 获取访问次数
Integer count = (Integer) session.getAttribute("visited");
count++;
// 将新的访问次数返回到 HttpSession 对象中
session.setAttribute("visited",count);
// 显示访问次数
resp.getWriter().write("visited = " + count);
}
}
八、下载文件
- webapp目录下的 upload.html
ebctype就是设置body的格式,默认是 x-www-from-urlencode
<!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>Document</title>
</head>
<body>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="MyFile">
<input type="submit" value="提交">
</form>
</body>
</html>
- Java文件必须添加注解 @MultipartConfig
- 通过getPart()方法获得文件
//只有添加这个注解,才能使用getPart方法
@MultipartConfig
@WebServlet("/upload")
public class FileServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.通过 getPart() 获取前端传来的文件
Part part = req.getPart("MyFile");
System.out.println(part.getSubmittedFileName());
System.out.println(part.getSize());
System.out.println(part.getContentType());
// 2.把传来的文件放到指定位置
part.write("C://user");
resp.getWriter().write("upload ok");
}
}