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 {
@Override
protected 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){
//构造最外层的div
let 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 {
@Override
protected 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);//设置状态码 302
resp.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构造请求发送JSON
data: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里
//遍历body
for(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;
@Override
public 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<>();
@Override
protected 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);
}
@Override
protected 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(?, ?, ?)";
//写入sql
statement = 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. 构造 SQL
String sql = "select * from message";
//写入sql
statement = connection.prepareStatement(sql);
// 3. 执行 SQL
resultSet = 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 {
@Override
protected 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对应一个session
HttpSession sessio=req.getSession(true);
sessio.setAttribute("username","user");
//设置计数器 用来表示用户访问页面次数
Integer visitCount= (Integer) sessio.getAttribute("visitCount");
//如果visitCount为空时,就设置0
if(visitCount==null){
//第二个参数是Object 所以会自动装箱成Integer
sessio.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 {
@Override
protected 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中传来的username
String 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 {
@Override
protected 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");
}
}