2.4 生成验证码

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情

生成验证码

image-20220710141644264

code.google.com/archive/p/k…

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;
    }
}

image-20220710142837625

image-20220710143208160

image-20220710143939656

image-20220710155830214

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());
        }

    }
}

image-20220710160242255

image-20220710160427170

扫描二维码关注公众号,回复: 14418459 查看本文章
# 为什么方法的返回值是 void 呢?

因为我们向浏览器输出的是特殊的东西,是一个图片,不是一个字符串,也不是一个网页,所以这个方法比较特别,我们需要自己用 response 对象手动的向浏览器输出,所以方法的返回值为 void 。


# 将验证码存入session
生成验证码之后,服务端要把它记住,浏览器登陆的时候好验证验证码对不对,又因为它是敏感数据,所以我们将它存
到 session里。

4. 将生成验证码的方法应用到登录页面上

image-20220710165409753

image-20220710165436251

<script>
   function refresh_kaptcha() {
      var path = CONTEXT_PATH + "/kaptcha?p=" + Math.random();
      $("#kaptcha").attr("src", path);
   }
</script>

image-20220710165526970

测试:

image-20220710165552707

点击 “刷新验证码”

image-20220710165623819

猜你喜欢

转载自juejin.im/post/7125942980677992455