一:Cookie和Session
(1)Cookie
Cookie:是一种用于在Web浏览器和Web服务器之间传递数据的技术。当用户访问一个网站时,该网站可以通过在用户的浏览器中存储一个小文件来创建和使用Cookie。这个小文件包含有关用户在网站上的活动和偏好的信息。Cookie通常用于跟踪用户在网站上的行为、记录登录状态、存储购物车内容以及个性化用户体验等。当用户再次访问同一网站时,浏览器会将Cookie发送回服务器,从而使网站能够识别用户并提供相应的个性化服务。Cookie包含了键值对的信息,每个键值对表示一条数据。其中,键表示数据的名称,值表示数据的内容。除了键值对外,Cookie还可以包含一些其他属性,如过期时间、域名、路径等,用于控制其在浏览器中的行为。尽管Cookie在互联网上广泛使用,但也存在一些安全和隐私方面的考虑。因此,现代浏览器提供了控制Cookie的选项,用户可以选择是否接受、删除或限制Cookie的使用\
Cookie是通过在请求和响应报文中写入Cookie信息来控制客户端的状态,可以这样理解:客户端第一次请求后,服务器会下发一个装有客户信息的“身份铭牌”(也就是set-cookie),后续该客户端再次请求服务器的时候,只需要戴上“身份铭牌”,服务器就能认得然后自动完成认证
可以发现这样做是有很大的风险的,这也意味着在传输过程所有信息等于在“裸奔”,如果让一些不怀好意的人截获Cookie,就会造成很大的麻烦。为了解决Cookie的弊端,Session应运而生
(2)Session
Session:是一种服务器端的存储机制,用于在多个HTTP请求之间维持和跟踪用户会话状态。与Cookie不同,Session数据是存储在服务器上的,而不是在客户端浏览器中
客户端在第一次发送请求时,服务器会创建一个Session,同时会创建一个特殊的Cookie(它其实是一个name
为JSEESIONID
的固定值,value
为session
对象的ID),然后将Cookie发送至客户端;当客户端第二次及以后发送请求时,会携带该name
为JSESSION
的对象,接着服务器会根据name
为JSESSIONID
的cookie的value
(sessionid
)去查询session
对象,进行身份确认
所以在你登录一个网站的时候,如果服务器端使用的是Session,那么所有的数据都会保存在服务器上,客户端每次请求服务器的时候会发送当前会话sessionid
,服务器则根据当前sessionid
标识用户,以确定该用户的身份以及是否具有某种权限。由于数据存在服务器上面,所以相对安全
(3)关系
Cookie和Session共同协作,使得服务器能够跟踪和管理用户的会话状态。Cookie负责在客户端浏览器和服务器之间传递sessionid
,而Session则负责存储和管理与用户相关的会话数据。这种组合使得网站能够提供个性化的服务、记录登录状态、存储购物车内容等功能
- Cookie数据存放在客户端,Seesion数据存放在服务器
- Session相较于Cookie安全
- 由于Session考虑了安全,因此会影响服务器的性能
- 单个Cookie在客户端的限制为3k
- Cookie和Session经常会配合使用,但也不是说非得配合
- 完全可以用Cookie来保存一些数据在客户端,这些数据不一定是用户身份信息,也不一定是
token
或sessioid
- Session中的
token
或sessioid
也不是非得要通过Cookie来传递
二:相关API
HttpServletRequest类中相关方法:
Http Session getSession()
:- 如果参数为
true
:判断当前会话是否存在,如果不存在,就创建一个新的键值对并保存到哈希表中,然后把生成的sessionId
返回给浏览器;如果存在,则直接返回对应的HttpSession对象 - 如果参数为
false
:判断当前会话是否存在,如果不存在,直接返回null
;如果存在则返回对应的HttpSession对象
- 如果参数为
Cookie[] getCookies()
:返回一个Cookie对象数组(因为可能有多个Cookie)
HttpServletResponse类中相关方法:
void addCookie(Cookie cookie)
:将指定的cookie添加到响应中
HttpSession类中相关方法:一个HttpSession对象里面包含多个键值对,我们可以向HttpSession中添加任何我们需要的信息
Object getArrtibute(String name)
:返回在该Session会话中具有指定名称的对象,如果没有则返回null
void setAttribute(String name, Object value)
: 使用指定的名称绑定一个对象到该Session会话boolean isNew()
: 判断当前是否是新创建出来的会话
Cookie类中的相关方法:每个Cookie对象就是一个键值对
String getName()
:返回Cookie的名称(名称在创建之后不能改变)String getValue()
:获取与Cookie关联的值void setValue(String newValue)
:设置与Cookie关联的值
三:案例
(1)案例1:用户登录
- 代码Github:点击跳转
如下图,当用户登录成功时创建Session,然后重定向的index
,并显示欢迎信息。而如果用户没有登录或登录失败直接访问index
,则由于没有Seesion,就会出现拒绝访问的信息
当然,如果将Cookie删除后,自然也就是拒绝访问了
IndexServlet.java
:用于处理登录后跳转的主页
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 {
// 获取Session,这里的Session就是刚才在登录页时登录成功后创建出来的
HttpSession session = req.getSession(false);
// 表示登录失败或者就没有登录,没有这样的Session就不让访问
if(session == null) {
resp.setStatus(403);
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write("未登录,拒绝访问主页");
}
// 如果有Session,则去取出对应的用户名,并显示欢迎访问
String username = (String) session.getAttribute("username");
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write(username + "! 欢迎来到主页");
}
}
LoginServlet.java
:Servlet服务器
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 {
// form表单数据将会提交到服务器
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 从请求中获取用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
// 验证
if ("zhangsan".equals(username) && "123321".equals(password)) {
// 成功
// 创建Session
HttpSession session = req.getSession(true);
// 使用session存储信息
session.setAttribute("username", "zhangsan");
// 让响应重定向到主页
resp.sendRedirect("index");
} else {
// 失败
resp.setStatus(403);
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write("登录失败,用户名或密码错误");
}
}
}
login.html
:登录页面(可自己设计)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录页面</title>
<style>
* {
margin: 0;
padding: 0;
}
a {
text-decoration: none;
}
input,
button {
background: transparent;
border: 0;
outline: none;
}
body {
height: 100vh;
background: linear-gradient(#141e30, #243b55);
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
color: #03e9f4;
}
.loginBox {
width: 400px;
height: 364px;
background-color: #0c1622;
margin: 100px auto;
border-radius: 10px;
box-shadow: 0 15px 25px 0 rgba(0, 0, 0, .6);
padding: 40px;
box-sizing: border-box;
}
h2 {
text-align: center;
color: aliceblue;
margin-bottom: 30px;
font-family: 'Courier New', Courier, monospace;
}
.item {
height: 45px;
border-bottom: 1px solid #fff;
margin-bottom: 40px;
position: relative;
}
.item input {
width: 100%;
height: 100%;
color: #fff;
padding-top: 20px;
box-sizing: border-box;
}
.item input:focus+label,
.item input:valid+label {
top: 0px;
font-size: 2px;
}
.item label {
position: absolute;
left: 0;
top: 12px;
transition: all 0.5s linear;
}
.btn {
padding: 10px 20px;
margin-top: 30px;
color: #03e9f4;
position: relative;
overflow: hidden;
text-transform: uppercase;
letter-spacing: 2px;
left: 35%;
}
.btn:hover {
border-radius: 5px;
color: #fff;
background: #03e9f4;
box-shadow: 0 0 5px 0 #03e9f4,
0 0 25px 0 #03e9f4,
0 0 50px 0 #03e9f4,
0 0 100px 0 #03e9f4;
transition: all 1s linear;
}
.btn>span {
position: absolute;
}
.btn>span:nth-child(1) {
width: 100%;
height: 2px;
background: -webkit-linear-gradient(left, transparent, #03e9f4);
left: -100%;
top: 0px;
animation: line1 1s linear infinite;
}
@keyframes line1 {
50%,
100% {
left: 100%;
}
}
.btn>span:nth-child(2) {
width: 2px;
height: 100%;
background: -webkit-linear-gradient(top, transparent, #03e9f4);
right: 0px;
top: -100%;
animation: line2 1s 0.25s linear infinite;
}
@keyframes line2 {
50%,
100% {
top: 100%;
}
}
.btn>span:nth-child(3) {
width: 100%;
height: 2px;
background: -webkit-linear-gradient(left, #03e9f4, transparent);
left: 100%;
bottom: 0px;
animation: line3 1s 0.75s linear infinite;
}
@keyframes line3 {
50%,
100% {
left: -100%;
}
}
.btn>span:nth-child(4) {
width: 2px;
height: 100%;
background: -webkit-linear-gradient(top, transparent, #03e9f4);
left: 0px;
top: 100%;
animation: line4 1s 1s linear infinite;
}
@keyframes line4 {
50%,
100% {
top: -100%;
}
}
</style>
</head>
<body>
<div class="loginBox">
<h2>login</h2>
<form action="login" method="post">
<div class="item">
<input type="text" required name="username">
<label for="">userName</label>
</div>
<div class="item">
<input type="password" required name="password">
<label for="">password</label>
</div>
<button class="btn" id="submitBtn">submit
<span></span>
<span></span>
<span></span>
<span></span>
</button>
</form>
</div>
</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("#submitBtn").click(function(event) {
event.preventDefault(); // 阻止表单默认提交行为
var username = $('input[name="username"]').val();
var password = $('input[name="password"]').val();
$.ajax({
url: "login",
type: "post",
data: {
username: username,
password: password
},
success: function(response) {
// 请求成功的处理逻辑
alert("登录成功!");
},
error: function(jqXHR, textStatus, errorThrown) {
// 请求失败的处理逻辑
if (jqXHR.status == 403) {
alert("用户名或密码错误,请重新输入!")
}
}
});
});
});
</script>
</html>
(2)案例2:上传文件
如下图,在浏览器中点击提交按钮后将选择的文件提交给服务器,然后让服务器保存该文件(用由于这里的服务器在本地,所以带来的效果可能不那么明显)
A:相关API
HttpServletRequest类中相关方法:
Part getPart(String name)
:获取请求中给定name
的文件Collection<Part> getParts()
:获取所有的文件
Part类中相关方法:
String getSubmittedFileNamed()
:获取提交的文件名String getContentType()
:获取提交的文件类型long getSize()
:获取文件的大小void write(String path)
:将提交的文件数据写入磁盘文件
B:代码
upload.html
:上传文件页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传文件</title>
</head>
<body>
<!--注意:使用form表单提交文件时必须加上 enctype="multipart/form-data--><form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="myfile">
<input type="submit" name="提交">
</form>
</body>
</html>
uploadServlet.java
:Servlet服务器
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;
@WebServlet("/upload")
// 专门针对上传文件的注解
@MultipartConfig
public class UploadServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 这里参数中的 name 和input标签中的name一致
Part part = req.getPart("myfile");
// 获取文件名
System.out.println(part.getSubmittedFileName());
// 获取文件大小
System.out.println(part.getSize());
// 获取文件类型
System.out.println(part.getContentType());
// 保存文件
part.write("D:/programData/temp/test.jpg");
}
}
评论区