概念
服务端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中。HTTPSession
入门
- HTTPSession对象
- Object getAttribute(String name)
- void setAttribute(String name, Object value)
- void removeAttribute(String name)
发送:
//使用Session获取数据
//1 获取session
HttpSession session = request.getSession();
//2 存储数据
session.setAttribute("msg", "hello session");
接收:
//1 获取session
HttpSession session = request.getSession();
//2 获取数据
Object msg = session.getAttribute("msg");
response.getWriter().write(msg + "");
原理
服务器如何确保会话中多次请求的Session是同一个?
- 依赖于Cookie的
问题
- 当客户端关闭后,服务端不关闭,两次获取Session是同一个?
默认情况下:不是,当客户端关闭后,会话结束了,获取时没有对应的cookie头。如果需要相同,可以创建cookie,键为JSESSIONID,设置最大存活时间,让其持久化保存
- 客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
不是同一个,创建session的对象分配的地址值是随机的。但是为了确保数据不丢失,必须 ***session的钝化(序列化),将服务器正常关闭前,将其对象序列化到硬盘 **session的活化:服务器启动后,将session文件转化为内存中的session对象(tomcat自动实现)
- session的失效时间?
** 服务器关闭。***session对象调用invalidate() ** 默认失效的时间为30s【conf/web.xml中可修改配置】
特点
- session用于存储一次会话的多次请求的数据,存在服务器端
- session可以存储任意类型,任意大小的数据
- 与cookie的区别:
- session没有大小限制,cookie有
- session服务器端, cookie在客户端
- session数据安全, cookie相对不安全
代码
需求
- 访问带有验证码的登录页面login.jsp
- 用户输入用户名,密码以及验证码
- 与数据库交互
页面1:登录界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<script>
window.onload = function(){
document.getElementById("img").onclick = function(){
this.src="/checkcode?time=" + new Date().getTime();
}
}
</script>
<style>
div{
color: red;
}
</style>
</head>
<body>
<form action="/loginServletV2" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type=""text name="username"></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>验证码</td>
<td><input type="text" name="checkCode"></td>
</tr>
<tr>
<td colspan="2"><img id="img" src="/checkcode"> </td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"></td>
</tr>
</table>
</form>
<div><%= request.getAttribute("cc_error") == null ? "" : request.getAttribute("cc_error")%></div>
<div><%= request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%></div>
</body>
</html>
页面2:登录成功界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>success</title>
</head>
<body>
<h1> <%= request.getSession().getAttribute("user")%>欢迎你!</h1>
</body>
</html>
web端
import com.pu.dao.UserDao;
import com.pu.domain.User;
import org.apache.commons.beanutils.BeanUtils;
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;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
/**
@WebServlet("/loginServletV2")
public class LoginServletV2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1:设置编码
req.setCharacterEncoding("utf-8");
//2:获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String checkCode = req.getParameter("checkCode");
//获取验证码
HttpSession session = req.getSession();
String checkCodeString = (String)session.getAttribute("checkCodeString");
//获取完验证码立即删除
session.removeAttribute("checkCodeString");
//判断验证码正确性
if(checkCodeString != null && checkCodeString.equalsIgnoreCase(checkCode)){
//判断用户名和密码
User loginUser = new User();
loginUser.setUsername(username);
loginUser.setPassword(password);
UserDao dao = new UserDao();
User user = dao.login(loginUser);
//5:判断User
if(user == null){
req.setAttribute("login_error", "用户名或密码错误");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}else{
//存储
session.setAttribute("user", username);
//跳转其他页面,重定向
resp.sendRedirect(req.getContextPath() + "/success.jsp");
}
}else{
//验证码不正确
//存储提示信息到request
req.setAttribute("cc_error", "验证码错误");
//转发到登录界面
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doGet(req, resp);
}
}
验证码
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/**
@WebServlet("/checkcode")
public class CheckCode extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int width = 100;
int height = 40;
//创建一对象,在内存中图片(验证码图片对象)
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//美化图片
//填充背景色
Graphics g = image.getGraphics();//画笔对象
g.setColor(Color.pink);//设置画笔颜色
g.fillRect(0, 0, width, height);
//画边框
g.setColor(Color.BLUE);
g.drawRect(0, 0, width - 2, height - 2);
//写验证码
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
//生成随机角标
Random ran = new Random();
StringBuffer sb = new StringBuffer();
int index = 0;
for(int i = 1; i <= 4 ; i++){
index = ran.nextInt(str.length());
char ch = str.charAt(index);
sb.append(ch);
String strs = ch + "";
g.drawString(strs, 20 * i , 25 );
}
String checkCodeString = sb.toString();
request.getSession().setAttribute("checkCodeString", checkCodeString);
//画干扰线
g.setColor(Color.GREEN);
for(int i = 0; i < 10; i++) {
int x1 = ran.nextInt(width);
int y1 = ran.nextInt(height);
int x2 = ran.nextInt(width);
int y2 = ran.nextInt(height);
g.drawLine(x1, y1, x2, y2);
}
//输出图片
ImageIO.write(image, "jpg", response.getOutputStream());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
Dao层
import com.pu.domain.User;
import com.pu.util.JDBCUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* description:操作数据库中User表的类
*/
public class UserDao {
//声明JDBCTemplate对象共用
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
/**
* 登录方法
* @param loginUser 只有用户名和密码
* @return user包含用户的数据
*/
public User login(User loginUser){
//1:编写sql语句
try {
String sql = "select * from user where username = ? and password = ?";
//2:调用query方法
User user = template.queryForObject(sql,
new BeanPropertyRowMapper<User>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (DataAccessException e) {
e.printStackTrace();//记录日志
return null;
}
}
}