目录
先看效果
涉及知识
- Spring Web
- DI
- HuTool
- Lombok
- ajax&css&js(前端)
注意:
开发步骤
一、定义接口文档
1. 获取验证码
- 请求方式:
GET
- 请求URL:
/Captcha/getCode
- 请求参数:无
响应:
- 响应类型:
image/jpeg
(字节流) - 响应内容:返回验证码图片,直接显示在前端页面。
2. 校验验证码
- 请求方式:
POST
- 请求URL:
/Captcha/check
- data:captcha=“xxx”(用户输入的验证码)
- 响应: true或者false(正确/错误)
二、创建spring web项目
导入hutool和lombok的依赖。把两个前端代码拷贝到resources->static
路径下:
然后此路径创建两个包,用于区分代码功能:
接着,controller路径下创建一个类CaptchaController
:
三、CaptchaController的实现
基本框架如下:
package com.hyy.testcaptcha.controller;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/Captcha")//根据接口文档建立映射
@RestController//给到spring管理
public class CaptchaController {
//发送验证码图片给到浏览器
@GetMapping("/getCode")//根据接口文档建立映射
public void getCaptcha(
HttpServletResponse response, //通过http响应把图片发送到浏览器
HttpSession session) { //创建会话,确定单个用户
}
//校验用户输入的验证码是否正确
@RequestMapping("/check")
public boolean check(String captcha, //根据接口文档定义,captcha是前端发送过来的用户输入的验证码
HttpSession session) {//session中存储此用户相关信息,比如验证码的创建时间,用于判断验证码是否过期
}
}
getCaptcha方法的实现
注意要引入hutool依赖:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
方法定义:
//发送验证码图片给到浏览器
@GetMapping("/getCode")//根据接口文档建立映射
public void getCaptcha(
HttpServletResponse response, //通过http响应把图片发送到浏览器
HttpSession session) { //创建会话,确定单个用户
//创建图形验证码,定义长和宽
ICaptcha icaptcha = CaptchaUtil.createCircleCaptcha(90, 30);
//定义键值对,Code代表正确的验证码
session.setAttribute("Code", icaptcha.getCode());
//设定创建时间 Date()是Java自带的工具类,可以获取创建该对象时的时间戳
session.setAttribute("Time",new Date());
//要加异常
try {
//规定数据类型
response.setContentType("image/jpeg");
//禁止缓存,防止无法向服务器读取图片
response.setHeader("Pragma", "No-cache");
//规定编码格式
response.setCharacterEncoding("utf-8");
//图片写入浏览器
icaptcha.write(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
接口测试:
图片显示成功!
check方法的实现
//校验用户输入的验证码是否正确
@RequestMapping("/check")
public boolean check(String captcha, //根据接口文档定义,captcha是前端发送过来的用户输入的验证码
HttpSession session) {//session中存储此用户相关信息,比如验证码的创建时间,用于判断验证码是否过期
//打印日志
System.out.println("用户输入的验证码:"+captcha);
if(captcha==null||captcha=="")return false;//前端返回无效字符串直接返回假
//校验时间是否过期
Date before=(Date)session.getAttribute("Time");
//超时返回假
if(System.currentTimeMillis()-before.getTime()>OUT_TIME)return false;
//获取正确的验证码
String code=(String)session.getAttribute("Code");
//比对验证码是否正确(不区分大小写)
return captcha.equalsIgnoreCase(code);
}
接口测试:
成功!
至此,后端代码已经全部完成。
优化(解耦合)
一、概述
在这些地方我们的代码是写死的,耦合太强了:
- 超时时间的定义:
- 长宽的定义:
- 验证码和时间戳名字的定义:
一旦我们要求改这些参数,会非常麻烦,东改一下,西改以下。所以我们的优化思路是把这些参数放到properties
文件中
二、操作步骤
1、修改properties文件
按照这个配置就可以:
captcha.width=90
captcha.height=30
#超时时间两分钟
captcha.outtime=120000
#session是一个对象,属性分别是time code
captcha.session.date="Time"
captcha.session.code="Code"
2、将properties属性映射到代码
首先,再 mode包中创建一个类CaptchaProperties,作为映射对象:
代码:
/**
* 也可以使用@Value一个个映射,但是比较麻烦,所以
* 我使用ConfigurationProperties
* */
@Data
@Configuration
@ConfigurationProperties(prefix="captcha")
public class CaptchaProperties {
private Long outtime;
private Integer width;
private Integer height;
private Session session;
static class Session{
String date;
String code;
}
}
注意:
- 类中属性的名字要和properties配置中的名字要匹配否则会报错!
- 内部类必须是static 修饰。因为spring是通过反射创建对象的。但在反射机制中,实例内部类需要创建外部类才能创建。因此,Session是实例内部类,那么Spring无法创建其对象。
然后我们回到CaptchaController,把属性全部替换成CaptchapProperties的对应字段即可:
package com.hyy.testcaptcha.controller;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ICaptcha;
import cn.hutool.captcha.LineCaptcha;
import com.hyy.testcaptcha.mode.CaptchaProperties;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.Date;
@RequestMapping("/Captcha")//根据接口文档建立映射
@RestController//给到spring管理
public class CaptchaController {
//创建属性对象
@Autowired//依赖注入
private CaptchaProperties captchaProperties;
//发送验证码图片给到浏览器
@GetMapping("/getCode")//根据接口文档建立映射
public void getCaptcha(
HttpServletResponse response, //通过http响应把图片发送到浏览器
HttpSession session) { //创建会话,确定单个用户
//创建图形验证码,定义长和宽
ICaptcha icaptcha = CaptchaUtil.createCircleCaptcha(captchaProperties.getWidth(), captchaProperties.getHeight());
//打印日志
System.out.println("生成的验证码:"+icaptcha.getCode());
//定义键值对,Code代表正确的验证码
session.setAttribute(captchaProperties.getSession().getCode(), icaptcha.getCode());
//设定创建时间 Date()是Java自带的工具类,可以获取创建该对象时的时间戳
session.setAttribute(captchaProperties.getSession().getDate(),new Date());
//要加异常
try {
//规定数据类型
response.setContentType("image/jpeg");
//禁止缓存,防止无法向服务器读取图片
response.setHeader("Pragma", "No-cache");
//规定编码格式
response.setCharacterEncoding("utf-8");
//图片写入浏览器
icaptcha.write(response.getOutputStream());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//超时时间定义成两分钟
public static Long OUT_TIME=2*60*1000L;
//校验用户输入的验证码是否正确
@RequestMapping("/check")
public boolean check(String captcha, //根据接口文档定义,captcha是前端发送过来的用户输入的验证码
HttpSession session) {//session中存储此用户相关信息,比如验证码的创建时间,用于判断验证码是否过期
//打印日志
System.out.println("用户输入的验证码:"+captcha);
if(captcha==null||captcha=="")return false;//前端返回无效字符串直接返回假
//校验时间是否过期
Date before=(Date)session.getAttribute(captchaProperties.getSession().getDate());
//超时返回假
if(System.currentTimeMillis()-before.getTime()>captchaProperties.getOuttime())return false;
//获取正确的验证码
String code=(String)session.getAttribute(captchaProperties.getSession().getCode());
//比对验证码是否正确(不区分大小写)
return captcha.equalsIgnoreCase(code);
}
}
3、测试
URL:
http://127.0.0.1:8080/index.html
输入正确验证码,提交显示成功即可: