Session
概念:服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象(HttpSession)中。
快速入门:
- 获取HttpSession对象:
HttpSession session = request.getSession();
- 使用HttpSession对象:
object getAttribute(String name)
void setAttribute(String name, object value)
void removeAttribute(String name)
@WebServlet("/sessionTransmit")
public class SessionTransmit extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用Session共享数据
//1.获取Session
HttpSession session = request.getSession();
//2.存储数据
session.setAttribute("msg","Hello Session!");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
@WebServlet("/sessionReceive")
public class SessionReceive extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取Session
HttpSession session = request.getSession();
//2.获取数据并输出
Object msg = session.getAttribute("msg");
System.out.println(msg);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
原理分析
Session的实现是依赖于cookie的
Session的细节
细节:
-
当客户端关闭后,服务器不关闭,两次获取session是否为同一个?
默认情况下不是。如果需要相同,则可以创建cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存。Cookie sessionCookie = new Cookie("JSESSIONID", session.getId()); sessionCookie.setMaxAge(60*60); response.addCookie(sessionCookie);
@WebServlet("/sessionPersistence") public class SessionPersistence extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取Session HttpSession session = request.getSession(); System.out.println(session); //期望客户端关闭后,Session也能相同 Cookie sessionCookie = new Cookie("JSESSIONID",session.getId()); sessionCookie.setMaxAge(60); response.addCookie(sessionCookie); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }
-
客户端不关闭,服务器关闭后,两次获取的session是同一个吗?
不是同一个,但是要确保数据不丢失。
tomcat自动完成以下工作:
-
session的钝化:在服务器正常关闭之前,将session对象系列化到硬盘上。
-
session的活化:在服务器启动后,将session文件转化为内存中的session对象即可。
具体实现:将Intellij IDEA的项目的 out(或 target)目录下的文件打包为
.war
格式。将打包后的文件放到Tomcat\apache-tomcat-9.0.43\webapps
目录下,Tomcat\apache-tomcat-9.0.43\bin
下 点击startup.bat
启动Tomcat后在浏览器访问用于创建Session并存储的Servlet,然后点击shutdown.bat
正常关闭Tomcat。会在Tomcat\apache-tomcat-9.0.43\work\Catalina\localhost\项目名
目录中产生SESSIONS.serializable
文件用于存放Session对象。重新启动Tomcat后,该文件被自动读取并删除将存储的Session对象还原到内存中。程序运行中动态生成的数据(包括:JSP转换的
.java
文件、Session被序列化后的文件) -
-
session什么时候被销毁?
-
服务器关闭
-
session对象调用
invalidate()
-
session默认失效时间 30分钟
可以在Tomcat\apache-tomcat-9.0.43\conf\web.xml
中选择性配置修改:<!-- ==================== Default Session Configuration ================= --> <!-- You can set the default session timeout (in minutes) for all newly --> <!-- created sessions by modifying the value below. --> <session-config> <session-timeout>30</session-timeout> </session-config>
-
-
session的特点
- session用于存储一次会话的多次请求的数据, 存在服务器端
- session可以存储任意类型,任意大小的数据
session与cookie的区别:
- session存储数据在服务器端,Cookie在客户端
- session没有数据大小限制,Cookie有
- session数据安全,Cookie相对于不安全
案例:验证码
-
案例需求:
- 访问带有验证码的登录页面 login.jsp
- 用户输入用户名,密码以及验证码
- 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
- 如果验证码输入有误,跳转登录页面,提示:验证码错误
- 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
-
分析:
<%--
Created by IntelliJ IDEA.
User: Anonymous
Date: xxxx/xx/xx
Time: xx:xx
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Login Page</title>
<script>
window.onload = function () {
document.querySelector("#toggle").onclick = function () {
document.querySelector("#checkCode").src = "/Login_war_exploded/checkCodeServlet?time=" + new Date().getTime();
}
}
</script>
<style>
#errorInfor {
color: red;
}
</style>
</head>
<body>
<form action="/Login_war_exploded/loginServlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td>
<input type="txt" name="username" placeholder="Enter the username">
</td>
</tr>
<tr>
<td>密码:</td>
<td>
<input type="password" name="password" placeholder="Enter the password">
</td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input type="txt" name="checkCode" placeholder="Enter the check-code">
</td>
</tr>
<tr>
<td>
<img id="checkCode" alt="checkCode" src="/Login_war_exploded/checkCodeServlet">
</td>
<td>
<a href="javascript:;" id="toggle">看不清?换一张</a>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit">
</td>
</tr>
</table>
<div id="errorInfor">
<div>
<%=request.getAttribute("login_error") == null ? "" : request.getAttribute("login_error")%>
</div>
<div>
<%=request.getAttribute("checkCode_error") == null ? "" : request.getAttribute("checkCode_error")%>
</div>
</div>
</form>
</body>
</html>
@WebServlet("/checkCodeServlet")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
int width = 150;
int height = 75;
//1.创建一个存储在内存中的图片对象
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//2.美化图片
//2.1填充背景颜色
Graphics graphics = image.getGraphics();//画笔对象
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
//2.2画边框
graphics.setColor(Color.RED);
graphics.drawRect(0, 0, width - 1, height - 1);
String str = "";
char c = 'A';
for (int i = 0; i < 26; i++) {
str += (char) (c + i);
str += (char) (c + 32 + i);
}
c = '0';
for (int i = 0; i < 10; i++) {
str += (char) (c + i);
}
//生成随机角标和字符串格式验证码
Random random = new Random();
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 4; i++) {
//获取随机字符
int index = random.nextInt(str.length());
char ch = str.charAt(index);
stringBuilder.append(ch);
//2.3写验证码
graphics.drawString(ch + "", width / 4 * i, height / 2);
}
String checkCode_session = stringBuilder.toString();
//将验证码存入Session
request.getSession().setAttribute("checkCode_session", checkCode_session);
//4.画干扰线
graphics.setColor(Color.GREEN);
for (int i = 0; i < 10; i++) {
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
graphics.drawLine(x1, y1, x2, y2);
}
ImageIO.write(image, "jpg", response.getOutputStream());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
<%@ page import="com.example.domain.User" %><%--
Created by IntelliJ IDEA.
User: Anonymous
Date: xxxx/xx/xx
Time: xx:xx
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Welcome Page</title>
</head>
<body>
<h1>Welcome <%=((User) request.getSession().getAttribute("user")).getUsername()%>!</h1>
</body>
</html>
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.设置编码
request.setCharacterEncoding("utf-8");
/* //2.获取请求参数
String username = request.getParameter("username");
String passWord = request.getParameter("password"); */
String checkCode = request.getParameter("checkCode");
HttpSession httpSession = request.getSession();
String checkCode_session = (String) httpSession.getAttribute("checkCode_session");
//删除Session中存储的验证码
httpSession.removeAttribute("checkCode_session");
// System.out.println("checkCode:"+checkCode+"\ncheckCode_session:"+checkCode_session);
//判断验证码是否正确
if (checkCode_session != null && checkCode.equalsIgnoreCase(checkCode_session)) {//验证码输入正确
//2.获取所有请求参数并创建对象使用BeanUtils封装
Map<String, String[]> parameterMap = request.getParameterMap();
User loginUser = new User();
try {
BeanUtils.populate(loginUser, parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//3.封装User对象并调用UserDao的login方法
UserDao userDao = new UserDao();
try {
User user = userDao.login(loginUser);
// User user = userDao.login(new User(username,passWord));
//4.判断user是否为空
if (user != null) {//登陆成功
/*request.setAttribute("user",user);
request.getRequestDispatcher("/welcomePage.jsp").forward(request,response);*/
//存储用户信息
httpSession.setAttribute("user", user);
//重定向到welcomePage.jsp
response.sendRedirect(request.getContextPath() + "/welcomePage.jsp");
} else {//用户名或密码错误,登录失败
//存储提示信息到request
request.setAttribute("login_error", "Username or password error!");
//转发到登录页面
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
} catch (SQLException throwable) {
throwable.printStackTrace();
}
} else {//验证码不一致
//存储提示信息到request
request.setAttribute("checkCode_error", "Check code error!");
//转发到登录页面
request.getRequestDispatcher("/Login.jsp").forward(request, response);
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
public class User {
private String username;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{}";
}
}
public class UserDao {
//声明JdbcTemplate对象公用
private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtil.getDataSource());
public UserDao() {
}
/**
* @param loginUser 只存储了待登录用户的用户名和密码的用户对象
* @return 包含所有用户信息的用户对象
* @throws SQLException
*/
public User login(User loginUser) throws SQLException {
/*
Connection conn = null;
conn = JDBCUtil.getConnection();
String sql = "select * from sign_up_check where username=? and password=?";
PreparedStatement prepStat = conn.prepareStatement(sql);
prepStat.setString(1,username);
prepStat.setString(2,password);
ResultSet resultSet = prepStat.executeQuery();
if (resultSet!=null){
//这里可以从数据库提取用户的其他数据,此处省略这些操作
return new User(username,password);
}
return null;
*/
try {
String sql = "select * from sign_up_check where username=? and password=?";
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class),
loginUser.getUsername(), loginUser.getPassword());
return user;
} catch (Exception throwable) {
throwable.printStackTrace();//记录日志
return null;
}
}
}
public class JDBCUtil {
private JDBCUtil() {
}
// private static final ResourceBundle bundle = ResourceBundle.getBundle("db");
private static DataSource dataSource;
static {
//注册驱动
/*try {//方法一
Driver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);
} catch (SQLException throwables) {
throwables.printStackTrace();
}*/
/*try {//方法二
Class.forName(bundle.getString("driver"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}*/
try {
//1.加载配置文件
Properties properties = new Properties();
properties.load(JDBCUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
// return DriverManager.getConnection(bundle.getString("url"),bundle.getString("user"),bundle.getString("password"));
return dataSource.getConnection();
}
//关闭资源
public static void close(ResultSet resultSet, Statement statement, Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwable) {
throwable.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwable) {
throwable.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwable) {
throwable.printStackTrace();
}
}
}
public static void close(Statement statement, Connection connection) {
close(null, statement, connection);
}
//获取数据库连接池对象
public static DataSource getDataSource() {
return dataSource;
}
}