携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
生成验证码
1. 导入 jar 包
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
2. 编写 Kaptcha 配置类
因为SpringBoot没有整合Kaptcha ,所以我们要自己写配置类将Kaptcha注入Spring容器
// 配置 Kaptcha 的工具类
// Kaptcha可以生成验证码图片
@Configuration
public class KaptchaConfig {
@Bean
public Producer kaptchaProducer(){
// 这个类其实可以从properties配置文件里读数据,但是我们不这样做,我们直接往里面塞数据
Properties properties = new Properties();
properties.setProperty("kaptcha.image.width", "100"); // 设置图片宽度,单位:像素
properties.setProperty("kaptcha.image.height", "40"); // 设置图片高度
properties.setProperty("kaptcha.textproducer.font.size", "32"); // 设置字号为 32 号字
properties.setProperty("kaptcha.textproducer.font.color", "black"); // 设置字的颜色
// 设置验证码从这些字符串中挑字符拼接用
properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
// 设置验证码长度
properties.setProperty("kaptcha.textproducer.char.length", "4");
// 设置使用哪个干扰类(对图片造成干扰)
properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise");
// Producer是个接口,DefaultKaptcha是它的实现类
// Producer有两个方法,一个是创建图片,一个是生成验证码,但是要通过Config对象做一些配置
DefaultKaptcha kaptcha = new DefaultKaptcha();
// 所有的配置都是通过config配的,config又依赖于Properties
Config config = new Config(properties);
kaptcha.setConfig(config);
return kaptcha;
}
}
3. 测试生成验证码的方法
- Kaptcha生成验证码的方法写在哪里?
不是在LoginController中的getLoginPage访问登录方法之中写的,getLoginPage这个方法是给浏览器返回一个html,而这个html里面会包含一个图片的路径,浏览器会依据路径再次访问服务器获得这个图片,所以我们需要再单独写一个请求(LoginController中的方法)向浏览器返回图片,当然登录页面的html会引用这个方法的路径。
@Controller
public class LoginController implements CommunityConstant {
private static Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private UserService userService;
@Autowired
private Producer kaptchaProducer;
@RequestMapping(path = "/register", method = RequestMethod.GET)
public String getRegisterPage(){
return "/site/register";
}
// 处理请求,因为是浏览器向我们提交数据,所以请求是POST方式
@RequestMapping(path = "/register", method = RequestMethod.POST)
public String register(Model model, User user){
// 注意:因为User声明在了方法的参数里,SpringMVC会自动把user存到model里
Map<String, Object> map = userService.register(user);
// map为空说明注册成功,我们应该提示浏览器注册成功,然后跳转到首页页面,之后激活之后才跳转到登录页面
if(map == null || map.isEmpty()){
model.addAttribute("msg", "注册成功,我们已经向您的邮箱发送了一封激活邮件,请尽快激活!");
model.addAttribute("target", "/index");
return "/site/operate-result";
} else {
// 有错误,传给页面信息并返回登录页面
model.addAttribute("usernameMsg", map.get("usernameMsg"));
model.addAttribute("passwordMsg", map.get("passwordMsg"));
model.addAttribute("emailMsg", map.get("emailMsg"));
return "/site/register";
}
}
// http://localhost:8080/community/activation/101/code
@RequestMapping(path = "activation/{userId}/{code}", method = RequestMethod.GET)
public String activation(Model model,
@PathVariable("userId") int userId,
@PathVariable("code") String code){
// 这个结果的含义可以从结果中识别,所以也需让LoginController实现CommunityConstant接口
int result = userService.activation(userId, code);
// 无论成功还是失败,都跳转到中转页面只是返回给中转页面的提示信息不同,然后从中转页面跳转到哪里根据激活是否成功决定
if(result == ACTIVATION_SUCCESS){
// 激活成功跳转到登录页面
model.addAttribute("msg", "激活成功,您的账号已经可以正常使用了!");
model.addAttribute("target", "/login"); // 返回给服务器,服务器跳转到登录的controller
} else if(result == ACTIVATION_REPEAT){
// 邮箱之前已经激活过了,重复了
model.addAttribute("msg", "无效操作,该账号已经激活过了!");
model.addAttribute("target", "/index"); // 跳转到展示首页的controller
} else {
// 激活失败
model.addAttribute("msg", "激活失败,您提供的激活码不正确!");
model.addAttribute("target", "/index"); // 跳转到展示首页的controller
}
return "/site/operate-result";
}
@RequestMapping(path = "/login", method = RequestMethod.GET)
public String getLoginPage(){
return "/site/login";
}
@RequestMapping(path = "/kaptcha", method = RequestMethod.GET)
public void getLKaptcha(HttpServletResponse response, HttpSession session){
// 生成验证码
String text = kaptchaProducer.createText();
BufferedImage image = kaptchaProducer.createImage(text); // 将验证码传入生成图片
// 将验证码存入session
session.setAttribute("kaptcha", text);
// 将图片输出给浏览器
response.setContentType("image/png"); // 声明返回给浏览器的是什么可视的数据
// response向浏览器做响应我们需要获取它的输出流
try {
ServletOutputStream os = response.getOutputStream();
// 这个流不用关,因为是SpringMVC维护,会自动关
ImageIO.write(image, "png", os); // 输出哪个图片; 格式; 哪个流输出
} catch (IOException e) {
logger.error("响应验证码失败:" + e.getMessage());
}
}
}
扫描二维码关注公众号,回复:
14418459 查看本文章
# 为什么方法的返回值是 void 呢?
因为我们向浏览器输出的是特殊的东西,是一个图片,不是一个字符串,也不是一个网页,所以这个方法比较特别,我们需要自己用 response 对象手动的向浏览器输出,所以方法的返回值为 void 。
# 将验证码存入session
生成验证码之后,服务端要把它记住,浏览器登陆的时候好验证验证码对不对,又因为它是敏感数据,所以我们将它存
到 session里。
4. 将生成验证码的方法应用到登录页面上
<script>
function refresh_kaptcha() {
var path = CONTEXT_PATH + "/kaptcha?p=" + Math.random();
$("#kaptcha").attr("src", path);
}
</script>
测试:
点击 “刷新验证码”