getParameter
获取body或url中指定的key/value值
String classId=req.getParameter("classId");
getQueryString
获取请求的所有查询参数key,values1
String queryString=req.getQueryString();
from表单提交
前端通过from表单提交用户名和密码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="Demo4" method="post"><input type="text" name="username"><input type="password" name="password"><input type="submit" name="提交"></form>
</body>
</html>
后端通过req.getParameter获取用户名和密码
package Demo;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("/Demo4")
public class Demo4 extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf8");String username=req.getParameter("username");String password=req.getParameter("password");if(username.equals("user")&&password.equals("123")){resp.getWriter().write("登录成功!");}else{resp.getWriter().write("用户名或者密码错误!");}}
}
构造json格式
body中的json格式
使用jackson库解析json格式
版本随便一个都可以
拷贝复制
记得刷新
读取从客户端传来的json数据
class Student{public int classId;public int studentId;
}
// 使用jackSon库处理JSON格式ObjectMapper objectMapper=new ObjectMapper();
// 从请求获取body并且解析
// 使用readValue来把json字符串转成java对象
// 第一个对象是String或者InputStream
// 第二个参数是转换的结果对应的java类对象//把JSON字符串转成java对象Student s=objectMapper.readValue(req.getInputStream(),Student.class);resp.getWriter().write("classId="+s.classId+" studentId="+s.studentId);
服务器把json写入到客户端
//传json时,要用这个类型resp.setContentType("application/json;charset=utf8");//要拿到写数据库操作的类BlogDao blogDao=new BlogDao();String jsonString=objectMapper.writeValueAsString(blogs);//响应resp.getWriter().write(jsonString);
客户端如何解析json格式?
后端设置了application/json格式,并且返回json格式,那么ajax会自动把body中的json格式转换成js对象
function getBlogs(){//构造ajax$.ajax({type:'get',url:'blog',success: function(body){let container=document.querySelector('.container-right');//后端返回的是json数据//如果Content-Type是application/json,jquery ajax会把body转成js对象for(let blog of body){//构造最外层的divlet blogDiv=document.createElement('div');blogDiv.className='blog';//创建博客标题let titleDiv=document.createElement('div');titleDiv.className='title';//把后端传来的json,被jackson解析成blog对象,对象内的标题属性赋值titleDiv.innerHTML=blog.title;//把titleDiv添加在blogDiv内blogDiv.appendChild(titleDiv);
页面自动刷新
设置头部信息Refresh属性 values为秒
package Demo;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("/Demo5")
public class Demo5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf8");resp.setHeader("Refresh","1");resp.getWriter().write("设置页面1秒后自动刷新");}
}
跳转页面
//跳转页面resp.setStatus(302);//设置状态码 302resp.setHeader("Location","Demo1.html");
N秒后自动跳转页面
//2秒后,跳转页面resp.getWriter().write("2秒后我将跳转页面");resp.setHeader("refresh", "2;Demo1.html");
自动下载
response.setHeader("content-disposition", "attachment;filename=3.jpg");
对话墙
基本逻辑
前端构造post方法,把数据构造成json格式,发送给后端,后端解析json格式,存储到数据库。
当页面刷新时,前端构造get方法,把数据构造成json格式,发送给后端,后端从数据库读取数据,再构造成json格式,发送给前端。
ajax会自动把body中的json格式解析成js对象,之后前端把数据显示到页面上。
前端页面
<!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><style>* {padding: 0;margin: 0;box-sizing: border-box;}.container {width: 800px;margin: 10px auto;}.container h2 {text-align: center;margin: 30px 0px;}.row {height: 50px;display: flex;justify-content: center;margin-top: 5px;line-height: 50px;}.row span {height: 50px;width: 100px;line-height: 50px;}.row input {height: 50px;width: 300px;line-height: 50px;}.row button {width: 400px;height: 50px;color: white;background-color: orange;border: none;border-radius: 10px;}.row button:active {background-color: grey;}</style>
</head>
<body><!-- 这是一个顶层容器, 放其他元素 --><div class="container"><h2>表白墙</h2><div class="row"><span>谁</span><input type="text" id="from"></div><div class="row"><span>对谁</span><input type="text" id="to"></div><div class="row"><span>说什么</span><input type="text" id="message"></div><div class="row"><button>提交</button></div></div><script src="https://code.jquery.com/jquery-3.7.1.min.js"></script><script>let container = document.querySelector('.container');let fromInput = document.querySelector('#from');let toInput = document.querySelector('#to');let messageInput = document.querySelector('#message');let button = document.querySelector('button');button.onclick = function() {// 1. 把用户输入的内容获取到. let from = fromInput.value;let to = toInput.value;let message = messageInput.value;if (from == '' || to == '' || message == '') {return;}// 2. 构造一个 div, 把这个 div 插入到 .container 的末尾let newDiv = document.createElement('div');newDiv.className = 'row';newDiv.innerHTML = from + " 对 " + to + " 说: " + message;// 3. 把 div 挂在 container 里面container.appendChild(newDiv);// 4. 把之前的输入框内容进行清空fromInput.value = '';toInput.value = '';messageInput.value = '';// 5. [新的步骤] 需要把刚才输入框里取到的数据, 构造成 POST 请求, 交给后端服务器!// JSON格式let messageJson={//kv值 k是我们现在定义的,v是在上面我们自己定义的from:from,to:to,message:message}$.ajax({type:"post",url:"message",contentType:'application/json;charset=utf8',// ajax构造请求发送JSONdata:JSON.stringify(messageJson),//当服务器返回数据时,执行success:function (){alert("提交成功!");},error:function (){alert("提交失败");}})}//这个函数再页面加载时候调用,通过这个函数从服务器获取当前的消息列表//摈弃显示到页面上function load(){$.ajax({type: 'get',url: 'message',contentType:'application/json;charset=utf8',//当服务器返回数据时,才会执行success: function(body){//服务器传来的时JSON格式,但ajax根据Content-Type为//application/json,ajax会帮我们自动类型转换成js数组let container=document.querySelector('.container');//服务器传来的数据都在body里//遍历bodyfor(let message of body){let newDiv=document.createElement('div');newDiv.className='row';newDiv.innerHTML=message.from +" 对 "+message.to+ " 说 "+message.message;//把newDiv加在container的里面container.appendChild(newDiv);}}})}//函数页面写在这代表页面加载/刷新时执行load函数load();</script>
</body>
</html>
后端页面
package org.example;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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;//对应前端的格式
//名字和全都key时一致的
class Message{public String from;public String to;public String message;@Overridepublic String toString() {return "org.example.Message{" +"from='" + from + '\'' +", to='" + to + '\'' +", message='" + message + '\'' +'}';}
}@WebServlet("/message")
public class MessageServlet extends HttpServlet {//因为get、post都会用到这个对象,所以共享出来private ObjectMapper objectMapper=new ObjectMapper();//private List<org.example.Message> messageList=new ArrayList<>();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//报文格式resp.setContentType("application/json;charset=utf8");List<Message> messageList=load();//把messageList对象转成JSON格式String respString=objectMapper.writeValueAsString(messageList);resp.getWriter().write(respString);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("application/json;charset=utf8");//第一个参数从拿哪读,转成什么类型Message message=objectMapper.readValue(req.getInputStream(),Message.class);save(message);System.out.println("message"+message);//把这些数据存储起来//messageList.add(message);//System.out.println("messaage="+message);//返回保存成功响应resp.getWriter().write("{\"ok\":1}");}// 把当前的消息存到数据库中private void save(Message message) {Connection connection = null;PreparedStatement statement = null;try {// 1. 和数据库建立连接connection = DBUtil.getConnection();// 2. 构造 SQL 语句String sql = "insert into message values(?, ?, ?)";//写入sqlstatement = connection.prepareStatement(sql);//填入问号statement.setString(1, message.from);statement.setString(2, message.to);statement.setString(3, message.message);// 3. 执行 SQL 语句int ret = statement.executeUpdate();if (ret != 1) {System.out.println("插入失败!");} else {System.out.println("插入成功!");}} catch (SQLException e) {e.printStackTrace();} finally {// 4. 关闭连接.DBUtil.close(connection, statement, null);}}// 从数据库查询到记录private List<Message> load() {Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;List<Message> messageList = new ArrayList<>();try {// 1. 建立连接connection = DBUtil.getConnection();// 2. 构造 SQLString sql = "select * from message";//写入sqlstatement = connection.prepareStatement(sql);// 3. 执行 SQLresultSet = statement.executeQuery();// 4. 遍历结果集while (resultSet.next()) {Message message = new Message();message.from = resultSet.getString("from");message.to = resultSet.getString("to");message.message = resultSet.getString("message");messageList.add(message);}} catch (SQLException throwables) {throwables.printStackTrace();} finally {// 5. 释放资源DBUtil.close(connection, statement, resultSet);}return messageList;}
}
建立连接
完成与数据库建立连接
package org.example;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;// 期望通过这个类来完成数据库建立连接的过程.
// 建立连接需要使用 DataSource . 并且一个程序有一个 DataSource 实例即可. 此处就使用单例模式来实现.
public class DBUtil {private static DataSource dataSource = null;private static DataSource getDataSource() {if (dataSource == null) {dataSource = new MysqlDataSource();((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/MessageWall?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("monan1946");}return dataSource;}public static Connection getConnection() throws SQLException {return getDataSource().getConnection();}public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {// 此处还是推荐大家写成分开的 try catch.// 保证及时一个地方 close 异常了, 不会影响到其他的 close 的执行.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();}}}
}
抓包过程
当页面提交数据时,触发post请求,会把数据提交到服务器,服务器会把数据存储起来。
当刷新页面时,会触发get请求,服务器会把数据回传给页面,页面会把数据继续显示到页面上,所以数据会依据存在
为什么刷新页面时会自动触发get请求呢?
在HTTP协议中,GET请求是用来获取服务器上的资源的。当你在浏览器中输入一个URL并按下回车键或者点击刷新按钮时,浏览器会向服务器发送一个GET请求,请求服务器返回该URL对应的资源。
客户端发起的请求,会自动触发服务器的对应的do方法
服务器返回响应,就会触发客户端的代码,也就是success的回调函数
模拟用户登录
基本逻辑
前端传递用户名和密码
当用户名与密码正确时,后端创建session(cookie),把用户名写进去,并且创建计数器。之后在另一个页面,获取session中的用户名,再把计数器也取出,计数器++,并且两个打印,计数器更新后,再把更新后的计数器写入session
前端
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>登录页</title>
</head>
<body><!-- action是路径 method是方法 --><form action="login" method="post"><input type="text" name="username"><input type="password" name="password"><input type="submit" name="提交"></form>
</body>
</html>
后端
loginServlet
package login;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.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/login")
//处理登录请求
public class loginServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf8");String username=req.getParameter("username");String password=req.getParameter("password");//数据为空时if(username==null || username.equals("")|| password==null || password.equals("")){//返回到登录页面//resp.sendRedirect("login.html");resp.getWriter().write("用户名或密码错误,请重新登录!");return;}if(username.equals("user")&&password.equals("123")){//创建一个session会话 把用户信息填写到session中//如果会话存在直接获取,根据cookie中的sessionid来查//如果不存在就创建新的//第一次登录时,cookie没有sessionid,就会创建新的会话对象//同时这个getsession还会生成一个sessionid,把这个sessionid作为Set-Cookie中的字段返回//给浏览器保存//一个sessionid对应一个sessionHttpSession sessio=req.getSession(true);sessio.setAttribute("username","user");//设置计数器 用来表示用户访问页面次数Integer visitCount= (Integer) sessio.getAttribute("visitCount");//如果visitCount为空时,就设置0if(visitCount==null){//第二个参数是Object 所以会自动装箱成Integersessio.setAttribute("visitCount",0);}else{//如果已经存在,就不设置为0}resp.sendRedirect("index");}else{resp.getWriter().write("用户名或密码错误,请重新登录!");return;}}
}
indexServlet
package login;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.servlet.http.HttpSession;
import java.io.IOException;@WebServlet("/index")
public class indexServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf8");//false不创建会话,有则有,没有则要求用户重新登录HttpSession session=req.getSession(false);//用户未登录,跳转登录界面,重新登录//当浏览器直接访问这个页面时 并没有先进入login.html页面 就会出现session==null的情况if(session==null){resp.sendRedirect("login.html");return;}//这里就是登录成功//获取会话中的数据//因为getAttribute返回的是Object 所以要强转//获取session中传来的usernameString username= (String) session.getAttribute("username");//session第二个参数是Object,虽然写的是0,但是会自动装箱成Integer,取的时候也是Integer//获取session中传来的计数器Integer visitCount= (Integer) session.getAttribute("visitCount");visitCount=visitCount+1;//加数后,再写回去session.setAttribute("visitCount",visitCount);resp.getWriter().write("当前用户: "+username+"访问次数:"+visitCount);}
}
第一次请求
首次登录,都会触发get方法
第二次请求
输入用户名密码登录
响应
JSESSIONID就是key(servlet自动生成的key名字) 后面是一传很长的十六进制数字,就是value
value就是服务器生成的sessionid
可以看到已经保存在浏览器内了
HttpSession sessio=req.getSession(true);
就是这个代码,实现创建会话,生成sessionid并且把sessionid通过Set-Cookie返回给浏览器
因为上面重定向了,所以浏览器get了index的页面
这是报文里就有了cookie
响应
这时就会读取请求中的cookie中的username,并且显示出来
上传文件
前端
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- enctype="multipart/form-data"指定了表单数据的编码方式,这样文件上传操作才能正确地执行。 --><form action="upload" method="post" enctype="multipart/form-data"><input type="file" name="MyFile"><input type="submit" value="上传"></form>
</body>
</html>
后端
package upload;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//servlet上传文件时默认关闭的,写上这个注解,打开
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf8");
// name要对应前端的name//获取文件Part part=req.getPart("MyFile");// 文件真实名字resp.getWriter().write(part.getSubmittedFileName()+"<br>");//文件大小System.out.println(part.getSize()+"<br>");//文件类型resp.getWriter().write(part.getContentType()+"<br>");//将文件写入磁盘part.write("D:/4k阿狸.jpg");resp.getWriter().write("upload ok");}
}