会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应
会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
HTTP协议是无状态的,每次浏览器向服务器请求时,服务器都会将该请求视为新的请求,因此我们需要会话跟踪技术来实现会话内数据共享
实现方式:
1.客户端会话跟踪技术:Cookie
2.服务端会话跟踪技术:Session
1,Cookie
1.1 Cookie基本使用
Cookie:客户端会话技术,将数据保存到客户端,以后每次请求都携带Cookie数据进行访问
1.1.1 发送Cookie
1. 创建Cookie对象,设置数据
Cookie cookie = new Cookie("key","value");
2. 发送Cookie到客户端:使用response对象
response.addCookie(cookie);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 创建Cookie
Cookie cookie = new Cookie("username", "zs");
//2. 发送Cookie
resp.addCookie(cookie);
}
1.1.2 获取Cookie
1. 获取客户端携带的所有Cookie,使用request对象
Cookie[] cookies = request.getCookies();
2. 遍历数组,获取每一个Cookie对象:for
3. 使用Cookie对象方法获取数据
cookie.getName();
cookie.getValue();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 获取Cookie数组
Cookie[] cookies = req.getCookies();
//2. 遍历数组
for(Cookie cookie: cookies){
// 3.获取Cookie
String name = cookie.getName();
if ("username".equals(name)){
String value = cookie.getValue();
System.out.println(name+":"+value);
break;
}
}
}
1.2 Cookie原理
Cookie的实现是基于HTTP协议的
响应头: set-cookie
请求头: cookie
1.3 Cookie的使用细节
1.3.1 Cookie存活时间
默认情况下,Cookie存储在浏览器内存中,当浏览器关闭,内存释放,则Cookie被销毁
setMaxAge(int seconds):设置Cookie存活时间
1.正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除
2.负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
3.零:删除对应Cookie
1.3.2 Cookie存储中文
Cookie不能直接存储中文
如需要存储,则需要进行转码:URL编码
//1. 创建Cookie
String value="张三";
//URL编码
value = URLEncoder.encode(value, "UTF-8");
System.out.println("存储数据:"+value);
Cookie cookie = new Cookie("username", value);
// 3.获取Cookie
String name = cookie.getName();
if ("username".equals(name)){
String value = cookie.getValue();
//URL解码
value = URLDecoder.decode(value,"UTF-8");
System.out.println(name+":"+value);
break;
}
2,Session
2.1 Session基本使用
服务端会话跟踪技术:将数据保存到服务端
JavaEE 提供HttpSession接口,来实现一次会话的多次请求间数据共享功能
2.1.1 获取Session对象
HttpSession session = request.getSession();
2.1.2 Session对象功能
void setAttribute(String name, Object):存储数据到session域中
Object getAttribute(String name):根据key,获取值
void removeAttribute(String name):根据key,删除该键值对
2.2 Session原理
Session是基于Cookie实现的
原理:Session是建立在Cookie上的,响应时会附带一个set-cookie中的JSESSIONID,再次访问时会根据JSESSIONID访问,从而拿到数据,
而请求3没有JSESSIONID,所以无法访问
2.3 Session使用细节
2.3.1 Session的钝化,活化
服务器重启后,Session中的数据是否还在?
钝化:在服务器正常关闭后,Tomcat会自动将Session数据写入硬盘的文件中
活化:再次启动服务器后,从文件中加载数据到Session中
2.3.2 Session销毁
1. 默认情况下,无操作,30分钟自动销毁
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2. 调用Session对象的invalidate()方法
3,小结
Cookie和Session都是来完成一次会话内多次请求间数据共享的
区别:
1. 存储位置:Cookie是将数据存储在客户端,Session将数据存储在服务端
2. 安全性:Cookie 不安全,Session安全
3. 数据大小: Cookie最大3KB,Session无大小限制
4. 存储时间:Cookie可以长期存储,Session 默认30分钟
5. 服务器性能:Cookie不占服务器资源,Session占用服务器资源
4,案例
4.1 用户登录
public class UserService {
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();
//登录方法
public User login(String username,String password){
//2.获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//4.调用方法
User user = mapper.select(username, password);
//释放资源
sqlSession.close();
return user;
}
}
loginServlet:
private UserService service = new UserService();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
//查看复选框是否被勾选
String remember = req.getParameter("remember");
//2.调用service方法
User user = service.login(username, password);
//3.判断
if (user != null){
//登录成功,跳转到查询所有的界面
if("1".equals(remember)){
//勾选
Cookie c_username = new Cookie("username",username);
Cookie c_password = new Cookie("password",password);
//设置Cookie的存活时间
c_username.setMaxAge(60*60*24*7);
c_password.setMaxAge(60*60*24*7);
//发送
resp.addCookie(c_username);
resp.addCookie(c_password);
}
//登录成功后user对象存储到Session中
HttpSession session = req.getSession();
session.setAttribute("user",user);
String contextPath = req.getContextPath();
resp.sendRedirect(contextPath+"/selectAllServlet");
}else {
//登陆失败
//存储错误信息到request
req.setAttribute("login_msg","用户名或密码错误");
//跳转到login.jsp
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}
}
记住账号密码:
<p>Remember:<input id="remember" name="remember" value="1" type="checkbox"></p>
if("1".equals(remember)){
//勾选
Cookie c_username = new Cookie("username",username);
Cookie c_password = new Cookie("password",password);
//设置Cookie的存活时间
c_username.setMaxAge(60*60*24*7);
c_password.setMaxAge(60*60*24*7);
//发送
resp.addCookie(c_username);
resp.addCookie(c_password);
}
若为1,则会选择记住账号密码
4.2 用户注册
//注册方法
public Boolean register(User user){
//2.获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.获取UserMapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//4.判断用户名是否存在
User u = mapper.selectByUsername(user.getUsername());
if (u == null) {
//用户名不存在,注册
mapper.add(user);
sqlSession.commit();
}
//释放资源
sqlSession.close();
return u == null;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
User user = new User();
user.setUsername(username);
user.setPassword(password);
//2.调用Service注册
boolean flag=service.register(user);
//3.判断成功与否
if (flag){
//注册成功
req.setAttribute("register_msg","注册成功,请登录");
req.getRequestDispatcher("/login.jsp").forward(req,resp);
}else {
//注册失败
req.setAttribute("register_msg","注册失败,用户名已存在");
req.getRequestDispatcher("/register.jsp").forward(req,resp);
}
}
4.3 验证码
4.3.1 展示
验证码功能:
展示验证码:展示验证码图片,并可以点击切换
校验验证码:验证码填写不正确,则注册失败
/**
* 输出随机验证码图片流,并返回验证码值(一般传入输出流,响应response页面端,Web项目用的较多)
*
* @param width 图片宽度
* @param height 图片高度
* @param os 输出流
* @param verifySize 数据长度
* @return 验证码数据
* @throws IOException
*/
public static String outputVerifyImage(int width, int height, OutputStream os, int verifySize) throws IOException {
String verifyCode = generateVerifyCode(verifySize);
outputImage(width, height, os, verifyCode);
return verifyCode;
}
//生成随机验证码图片
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletOutputStream os = resp.getOutputStream();
String checkCode = CheckCodeUtil.outputVerifyImage(100, 50, os, 4);
}
//点击看不清时,更新验证码图片
<tr>
<td>验证码</td>
<td class="inputs">
<input name="checkCode" type="text" id="checkCode">
<img id="checkCodeImg" src="/brand-demo/checkCodeServlet">
<a href="#" id="changeImg">看不清?</a>
</td>
</tr>
//上述不能改变图片多次
<script>
document.getElementById("changeImg").onclick=function (){
document.getElementById("checkCodeImg").src="/brand-demo/checkCodeServlet?"+new Date().getMilliseconds();
}
</script>
其中new Date().getMilliseconds()获取时间,使当前的src属性一致不同,从而生成多个不同的验证码
4.3.2 校验
//获取用户输入的验证码
String checkCode = req.getParameter("checkCode");
//获取程序生成的验证码
HttpSession session = req.getSession();
String checkCodeGen = (String) session.getAttribute("checkCodeGen");
//比对
if (!checkCodeGen.equalsIgnoreCase(checkCode)){
//不允许注册
req.setAttribute("register_msg","验证码错误");
req.getRequestDispatcher("/register.jsp").forward(req,resp);
return;
}
首先拿两个验证码进行比较(不分大小写),如果不一样,则直接退出,不会执行下面的代码
//存入Session
HttpSession session = req.getSession();
session.setAttribute("checkCodeGen",checkCode);