Session技术
Session 将数据存放在服务器端 , 获得session对象的同时 ,会为每一个客户端创建一块存放客户数据的区域,同时也会相应给客户端一个JsssionId的标识(Cookie ),当客户端在本次会话中再次访问时 ,都会携带 JsssionId 找到对应的session数据区域。 session是基于Cookie实现 。响应给客户端的Jsessionid不用自己管理 (自动完成)
Session
一:获取Session对象
HttpSession session = request.getSession();
获得session 服务器自动设置表示当前session唯一标识的jsessoinid (通过Cookie)发送给客户端
二: 存取数据 Session是一个域对象
Session.setAttribute(String name,Object o)
Session.getAttribute(String name)
Session.removeAttribute(String name)
三:Seesion 的生命周期
-
创建:第一次获得session的时候 req.getSession()(jsp 页面 翻译成Servlet里面 也有获得session的方法 )
-
销毁:1. 服务器关闭时 (客户端 丢失sessionid) 2.Session过期 /失效 (默认30分钟) 默认30可以改变,时间的起点是最后一次发送当前站点请求资源的时候,
<!-- session 的过期时间 单位分钟 --> <session-config> <session-timeout>1</session-timeout> </session-config>
-
手动销毁:session.invalidate();
session作用范围: 默认在一次会话中 ,(一次会话中包含了多次请求和响应)
四:Session的持久化
JsessionId 保存Cookie中并设置过期时间
//session持久化
Cookie cookie = new Cookie("JSSIONID", session.getId());
//设置过期时间
cookie.setMaxAge(60 * 60);
cookie.setPath("/web_session/getSessionlongtime");
response.addCookie(cookie);
response.sendRedirect("/web_session/welcome.jsp");
五:验证码的校验
1.首先生成一个验证码
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获得word.txt的路径,在WEB-INF/word.txt中自己写验证码
String realPath = getServletContext().getRealPath("WEB-INF/word.txt");
//创建一个集合
List arrayList = new ArrayList();
//使用字符缓冲流,readLine()读一行的方法
BufferedReader bufferedReader = new BufferedReader(new FileReader(realPath));
String readLine = bufferedReader.readLine();
while (readLine != null) {
arrayList.add(readLine);
readLine = bufferedReader.readLine();
}
// 画一个验证码 随机验证码
int height = 30;
int width = 110;
// 内存中 画一个图片
BufferedImage bufferedImage = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
// 画笔
Graphics graphics = bufferedImage.getGraphics();
// 给图片添加背景颜色
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
// 边框
graphics.setColor(Color.BLUE);
graphics.drawRect(0, 0, width - 2, height - 2);
// 写入验证码
// 设置字体
graphics.setFont(new Font("楷体", Font.BOLD, 20));
Random random = new Random();
Graphics2D graphics2D = (Graphics2D) graphics;
//从arrayList集合中随机取出一行数据
String mess = (String) arrayList.get(random.nextInt(arrayList.size()));
graphics2D.setColor(new Color(random.nextInt(255), random.nextInt(255),
random.nextInt(255)));
// 弧度
int jiaodu = random.nextInt(15) - 7;
double theta = jiaodu * Math.PI / 180;
graphics2D.rotate(theta, (width / 6), 20);
graphics2D.drawString(mess, (width / 7), 22);
graphics2D.rotate(-theta, (width / 6), 20);
// 画干扰线
for (int i = 0; i < 5; i++) {
graphics2D.setColor(new Color(random.nextInt(255), random
.nextInt(255), random.nextInt(255)));
graphics2D.drawLine(random.nextInt(width), random.nextInt(height),
random.nextInt(width), random.nextInt(height));
graphics2D.drawOval(random.nextInt(width), random.nextInt(height),
2, 3);
}
// 给客户端响应图片
ImageIO.write(bufferedImage, "jpg", response.getOutputStream());
}
2.jsp页面访问
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<script type="text/javascript">
function code(jpg) {
jpg.src = "/web06_session/responseCode?zz=" + new Date().getTime();
}
</script>
</head>
<body>
<form action="/web06_session/resposeCodeCheck" method="post">
用户名<input type="text" name="username" /><br /> 密 码<input
type="password" name="password" /><br /> 验证码 <input
name="checkcode" /><img onclick="code(this)"
src="/web06_session/responseCode" /> <input type="submit" />
</form>
<%
if (request.getAttribute("error") != null) {
%>
<%=request.getAttribute("error")%>
<%
}
%>
</body>
</html>
3.验证码验证
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
// 获得前端的验证码
request.setCharacterEncoding("utf-8");
String checkcode = request.getParameter("checkcode");
System.out.println(checkcode);
if (session.getAttribute("checkcode") != null) {
// 获得后台生成的
String checkcodesession = (String) session.getAttribute("checkcode");
// 比较验证码
if (!checkcode.equals(checkcodesession)) {
request.setAttribute("error", "验证码错误");
session.removeAttribute("checkcode");
request.getRequestDispatcher("/login.jsp").forward(request,
response);
} else {
// 登陆成功
session.setAttribute("username", "张三");
session.removeAttribute("checkcode");
response.sendRedirect("/web06_session/welcome.jsp");
}
} else {
request.setAttribute("error", "验证码失效");
request.getRequestDispatcher("/login.jsp").forward(request,
response);
}
}
六:使用Session解决表单重复提交
网路延时场景
- 场景1 : 网络延时 ,用户可能会点击多次提交按钮服务器会多次处理多次请求
- 场景2 :提交之后 用户点击了刷新按钮
- 场景3 : 点击 [后退] 回到了上个表单页面再次点击提交
解决方案:场景1 : 网络延时,用户可能会点击多次提交按钮。前端js解决;
<script type="text/javascript">
var isCommit = ture;//表示表单可以提交
function doSubmit() {
if (isCommit) {
isCommit = false;
return false;
}
return false;
}
</script>
并不能解决场景2和场景3
只能依靠服务器端解决,使用Session解决
流程: 在服务器生成一个随机唯一标识(Token 令牌) ,同时把它存入session域 , 需要服务器将其发送给客户端 ,客户端发送请求是携带Token 服务器端在验证过程中 先要验证Token是否和session中的Token一致 (如果一致就可以提交 ,不一致 ,表示就是重复提交 服务器就不处理 )并且提交后需要清除session中的Token :
不一致的情况:
- session中的Token和客户端提交的Token 不一致
- 客户端没有携带Token
- 服务端没有Token
1.创建一个Token
public class TokenUtil {
private TokenUtil() {
}
private static final TokenUtil tokenutil = new TokenUtil();
private static final BASE64Encoder bASE64Encoder = new BASE64Encoder();
public static TokenUtil getTokenUtil() {
return tokenutil;
}
public String makeToken() {
String Token = System.currentTimeMillis() + new Random().nextInt(999999999) + "";
return bASE64Encoder.encode(Token.getBytes());
}
}
创建一个令牌,将token存放在session
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// 创建一个令牌
String token = TokenUtil.getTokenUtil().makeToken();
// 将token存放在session
request.getSession().setAttribute("token", token);
request.getRequestDispatcher("/form.jsp").forward(request, response);
}
2.前端jsp页面演示表单提交
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<script type="text/javascript">
var isCommit = ture;//表示表单可以提交
function doSubmit() {
if (isCommit) {
isCommit = false;
return false;
}
return false;
}
</script>
</head>
<body>
<form action="/web06_session/formTokenServlet" method="post"
onsubmit="return doSubmit">
用户名<input type="text" name="username" /><br /> 密 码<input
type="password" name="password" /><br /> <input name="token"
value="<%=session.getAttribute("token")%>" type="hidden" /> <input
type="submit" />
</form>
</body>
</html>
3.创建一个Servlet判断表单是否重复提交
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
// 解决表单是否重复提交
// 是否重复提交
boolean isrepeatSubmit = isrepeatSubmit(request);
if (!isrepeatSubmit) {
System.out.println("表单重复提交");
} else {
request.getSession().removeAttribute("token");
System.out.println("用户每一次提交需要处理");
}
}
private boolean isrepeatSubmit(HttpServletRequest request) {
String clientToken = request.getParameter("token");
if (clientToken == null) {
return false;
}
// 获取服务器
String sessionToken = (String) request.getSession().getAttribute(
"token");
if (sessionToken == null) {
return false;
}
if (!sessionToken.equals(clientToken)) {
return false;
}
return true;
}