会话管理
Cookie简介
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的HTTP协议记录稳定的状态信息成为了可能。
Cookie 主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
1、浏览器第一次向服务器发起请求,服务器接受请求,并且应答头部带上cookie;
2、浏览器接收到服务器的响应,在本地创建cookie;
3、浏览器第二次向服务器发起请求会带上之前的cookie
//指定路径,Test下的方法都在这个路径下访问
@Controller
@RequestMapping("/Test")
public class TestController {
//第一次请求设置cookie
@RequestMapping(path = "/cookie/set",method = RequestMethod.GET)
@ResponseBody
public String setCookie(HttpServletResponse httpServletResponse)
{
//创建一个新cookie,存储一个随机字符串
Cookie cookie=new Cookie("code", CommunityUtil.generateUUID());
//设置cookie的访问路径 只有访问这些路径才会带上cookie
cookie.setPath("/community/Test");
//设置cookie存活时间 秒为单位
cookie.setMaxAge(60*10);
//向response中添加cookie,发送cookie
httpServletResponse.addCookie(cookie);
return "set cookie";
}
//第二次请求获得cookie
//@CookieValue获取对应的cookie值
@RequestMapping(path = "/cookie/get",method = RequestMethod.GET)
@ResponseBody
public String getCookie(@CookieValue("code") String code)
{
System.out.println(code);
return "get cookie";
}
}
Session
Session存放在服务器端,更加安全但是会增加服务器内存压力
// session示例
@RequestMapping(path = "/session/set", method = RequestMethod.GET)
@ResponseBody
public String setSession(HttpSession session) {
session.setAttribute("id", 1);
session.setAttribute("name", "Test");
return "set session";
}
@RequestMapping(path = "/session/get", method = RequestMethod.GET)
@ResponseBody
public String getSession(HttpSession session) {
System.out.println(session.getAttribute("id"));
System.out.println(session.getAttribute("name"));
return "get session";
}
分布式session共享方案:
1、粘性session:在nginx中提供一致性哈希策略,可以保持用户ip进行hash值计算固定分配到某台服务器上,负载也比较均衡,其问题是假如有一台服务器挂了,session也丢失了。
2、同步session:当某一台服务器存了session后,同步到其他服务器中,其问题是同步session到其他服务器会对服务器性能产生影响,服务器之间耦合性较强。
3、共享session:单独搞一台服务器用来存session,其他服务器都向这台服务器获取session,其问题是这台服务器挂了,session就全部丢失。
4、redis集中管理session(主流方法):redis为内存数据库,读写效率高,并可在集群环境下做高可用。
生成验证码
-导入jar包
<!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
-编写Kaptcha配置类
@Configuration
public class KaptchaConfig {
@Bean
public Producer kaptchaProducer() {
Properties properties = new Properties();
//验证码图像的宽度
properties.setProperty("kaptcha.image.width", "100");
//验证码图像的高度
properties.setProperty("kaptcha.image.height", "40");
//验证码生成字体的大小
properties.setProperty("kaptcha.textproducer.font.size", "32");
properties.setProperty("kaptcha.textproducer.font.color", "0,0,0");
//验证码生成的字母的范围
properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYAZ");
//验证码的长度
properties.setProperty("kaptcha.textproducer.char.length", "4");
//采用的干扰类 图片扭曲拉伸
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
DefaultKaptcha kaptcha = new DefaultKaptcha();
//加载配置信息
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
-生成随机字符、生成图片
-写一个请求返回验证码图片
- 需要把验证码生成的文本保存来校验验证码是否输入正确并且需要在多个值之间传递,因此设置session来保存验证码
- 先生成验证码文本,在生成图片
- 将图片输出给浏览器 使用字节流
- 可以不用手动关闭流,response会关闭
//生成验证码
@RequestMapping(value = "/Kaptcha",method = RequestMethod.GET)
public void getKaptcha(HttpServletResponse httpServletResponse, HttpSession session) {
// 生成验证码
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text);
//保存验证码到session
session.setAttribute("KaptchaCode",text);
//将图片输出给浏览器
httpServletResponse.setContentType("image/png");
try {
ServletOutputStream outputStream = httpServletResponse.getOutputStream();
ImageIO.write(image,"png",outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
实现刷新效果
- 修改图片访问路径
- 使用jquery写一个刷新验证码的方法
- js中定义一个全局变量项目工程名 方便修改
- P="+Math.random(); 防止浏览器误以为请求路径没变而不发送请求导致无法刷新
var CONTEXT_PATH="/community";
<div class="col-sm-4">
<img th:src="@{/Kaptcha}" id="kaptcha" style="width:100px;height:40px;" class="mr-2"/>
<a href="javascript:refresh_Kaptcha();" class="font-size-12 align-bottom">刷新验证码</a>
</div>
<script >
function refresh_Kaptcha() {
var path=CONTEXT_PATH+"/Kaptcha?P="+Math.random();
$("#kaptcha").attr("src",path);
}
</script>
DEBUG
一开始写cookie出现了Thymeleaf解析地址错误的问题,发现原来是cookie的路径设置错了,要加上工程路径
cookie.setPath("/community/Test");