关于图片验证码的时候,我们用到地方有很多,我们这次做的图片验证码是我们通过代码生成的图片,然后将其加密为Base64编码。
还是之前的一样,我们要线理一下思路,对于验证码,我们需要怎么做
最开始先导入图片验证码的依赖包
<!-- 图片验证码依赖 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
1、我们需要设置图片验证码的样式,就是显示给我们看的样式,我们需要自己配置
配置文件内存
captchaParameter.properties
#=========================== project Configuration =========================
project.valid-duration=300000
#=========================== captcha Configuration=========================
#\u8FB9\u6846\u989C\u8272
captcha.border.color=blue
#\u8FB9\u6846\u5BBD\u5EA6
captcha.border.thickness=1
#\u56FE\u7247\u5BBD\u5EA6
captcha.image.width=200
#\u56FE\u7247\u9AD8\u5EA6
captcha.image.height=60
#\u56FE\u7247\u5B9E\u73B0\u7C7B
captcha.producer.impl=com.google.code.kaptcha.impl.DefaultKaptcha
#\u9A8C\u8BC1\u7801\u503C
captcha.textproducer.char.string=3456789ABCEFJKMPQRTUVXY
#\u9A8C\u8BC1\u7801\u957F\u5EA6
captcha.textproducer.char.length=4
#\u6587\u5B57\u95F4\u9694
captcha.textproducer.char.space=18
#\u5B57\u4F53
captcha.textproducer.font.name=Arial,Courier
#\u5B57\u4F53\u5927\u5C0F
captcha.textproducer.font.size=30
#\u5B57\u4F53\u989C\u8272
captcha.textproducer.font.color=black
#\u5E72\u6270\u7EBF\u5B9E\u73B0\u7C7B
captcha.nosie.impl=com.google.code.kaptcha.impl.NoNoise
#\u5E72\u6270\u989C\u8272
captcha.nosie.color=lightGray
#\u56FE\u7247\u6837\u5F0F
captcha.obscurificator.impl=com.google.code.kaptcha.impl.ShadowGimpy
#\u80CC\u666F\u5B9E\u73B0\u7C7B
captcha.background.impl=com.google.code.kaptcha.impl.DefaultBackground
#\u80CC\u666F\u6E10\u53D8\u5F00\u59CB
captcha.background.clear.from=lightGray
#\u80CC\u666F\u6E10\u53D8\u7ED3\u675F
captcha.background.clear.to=white
#\u6587\u5B57\u6E32\u67D3\u5668
captcha.word=com.google.code.kaptcha.text.impl.DefaultWordRenderer
#session key
captcha.session.key=KAPTCHA_SESSION_KEY
#session date
captcha.session.date=KAPTCHA_SESSION_DATE
1.1、创建配置实体类,获取到配置文件中的属性
CaptchaParameterConfig
@Data
@Component
@PropertySource(value = {"classpath:captchaParameter.properties"})
public class CaptchaParameterConfig {
/**
* 验证码有效期
*/
@Value("${project.valid-duration}")
private Integer validDuration;
/**
* 边框颜色
*/
@Value("${captcha.border.color}")
private String captchaBorderColor;
/**
* 边框宽度
*/
@Value("${captcha.border.thickness}")
private String captchaBorderThickness;
/**
* 图片宽度
*/
@Value("${captcha.image.width}")
private String captchaImageWidth;
/**
* 图片高度
*/
@Value("${captcha.image.height}")
private String captchaImageHeight;
/**
* 图片实现类
*/
@Value("${captcha.producer.impl}")
private String captchaProducerImpl;
/**
* 验证码值
*/
@Value("${captcha.textproducer.char.string}")
private String captchaTextProducerCharString;
/**
* 验证码长度
*/
@Value("${captcha.textproducer.char.length}")
private String captchaTextProducerCharLength;
/**
* 文字间隔
*/
@Value("${captcha.textproducer.char.space}")
private String captchaTextProducerCharSpace;
/**
* 字体
*/
@Value("${captcha.textproducer.font.name}")
private String captchaTextProducerFontName;
/**
* 字体大小
*/
@Value("${captcha.textproducer.font.size}")
private String captchaTextProducerFontSize;
/**
* 字体颜色
*/
@Value("${captcha.textproducer.font.color}")
private String captchaTextProducerFontColor;
/**
* 干扰线实现类
*/
@Value("${captcha.nosie.impl}")
private String captchaNosieImpl;
/**
* 干扰颜色
*/
@Value("${captcha.nosie.color}")
private String captchaNosieColor;
/**
* 图片样式
*/
@Value("${captcha.obscurificator.impl}")
private String captchaObscurificatorImpl;
/**
* 背景实现类
*/
@Value("${captcha.background.impl}")
private String captchaBackgroundImpl;
/**
* 背景渐变开始
*/
@Value("${captcha.background.clear.from}")
private String captchaBackgroundClearFrom;
/**
* 背景渐变结束
*/
@Value("${captcha.background.clear.to}")
private String captchaBackgroundClearTo;
/**
* 文字渲染器
*/
@Value("${captcha.word}")
private String captchaWord;
/**
* session key
*/
@Value("${captcha.session.key}")
private String captchaSessionKey;
/**
* session date
*/
@Value("${captcha.session.date}")
private String captchaSessionDate;
}
1.2、配置类
@Configuration
public class CaptchaConfig {
@Autowired
private CaptchaParameterConfig parameterConfig;
@Bean
public DefaultKaptcha producer() {
Properties properties = new Properties();
//边框
properties.put("kaptcha.border", "no");
properties.put("kaptcha.border.color", parameterConfig.getCaptchaBorderColor());
properties.put("kaptcha.border.thickness", parameterConfig.getCaptchaBorderThickness());
//图片
properties.put("kaptcha.image.width", parameterConfig.getCaptchaImageWidth());
properties.put("kaptcha.image.height", parameterConfig.getCaptchaImageHeight());
//图片实现类
properties.put("kaptcha.producer.impl", parameterConfig.getCaptchaProducerImpl());
//文本
properties.put("kaptcha.textproducer.char.space", parameterConfig.getCaptchaTextProducerCharSpace());
properties.put("kaptcha.textproducer.char.length", parameterConfig.getCaptchaTextProducerCharLength());
properties.put("kaptcha.textproducer.char.string", parameterConfig.getCaptchaTextProducerCharString());
properties.put("kaptcha.textproducer.font.name", parameterConfig.getCaptchaTextProducerFontName());
properties.put("kaptcha.textproducer.font.size", parameterConfig.getCaptchaTextProducerFontSize());
properties.put("kaptcha.textproducer.font.color", parameterConfig.getCaptchaTextProducerFontColor());
//干扰
properties.put("kaptcha.noise.impl", parameterConfig.getCaptchaNosieImpl());
properties.put("kaptcha.noise.color", parameterConfig.getCaptchaNosieColor());
//图片样式
properties.put("kaptcha.background.impl", parameterConfig.getCaptchaBackgroundImpl());
//渐变
properties.put("kaptcha.background.clear.from", parameterConfig.getCaptchaBackgroundClearFrom());
properties.put("kaptcha.background.clear.to", parameterConfig.getCaptchaBackgroundClearTo());
//文字渲染器
properties.put("kaptcha.word", parameterConfig.getCaptchaWord());
//session
properties.put("kaptcha.session.key", parameterConfig.getCaptchaSessionKey());
properties.put("kaptcha.session.date", parameterConfig.getCaptchaSessionDate());
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
我们的图片验证码的样式就设置好了,但是我这边看不到,这个只是前段能看到
其实主要是有一个方法我们需要用DefaultKaptcha类的方法, 我们根据我们设置的验证码样式,可以使用它的**createText()方法,就可以获取到一个随机的验证码,然后在将我们获取到的验证码放如createImage()**这个方法中,我们就可以得到一个图片验证码
2、实体类
我用的是JPA直接创建的表
@Data
@Entity
@Table(name = "picture")
@EntityListeners(AuditingEntityListener.class)//时间标签,写了它,CreatedDate才能起作用
public class PictureValidationCodeDO {
/**
* 主键
*/
@Id
@GenericGenerator(name = "system-uuid",strategy = "uuid")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "system-uuid")
@Column(length = 50,name = "id")
private String id;
/**
* 创建时间
*/
@CreatedDate
@Column(nullable = false, updatable = false, name = "create_date" ,columnDefinition = "datetime COMMENT '创建时间'")
private Date createDate;
/**
* 验证码
*/
@Column(name = "code", columnDefinition = "varchar(50) comment '验证码' ")
private String code;
}
3、Service接口
public interface PictureValidationCodeService {
/**
* 生成验证码
* @return
*/
PictureValidationVO generate() throws Exception;
/**
* 校验验证码
* @param checkRequest
*/
void validate(PictureValidationCheckRequest checkRequest) throws Exception;
}
PictureValidationVO 只是我自己创建的另一个实体类,它只是用来接收数据的一个实体类,我们可以用DO直接当做返回对象,个人习惯
4、ServiceImpl(最重要的一步)
我们传参也一样,我这边也自己写了一个实体类,专门用来传参数
PictureValidationCheckRequest
@Service
@Slf4j
public class PictureValidationCodeServiceImpl implements PictureValidationCodeService {
@Autowired
private DefaultKaptcha defaultKaptcha;
@Autowired
private PictureValidationCodeRepository pictureValidationCodeRepository;
@Autowired
private CaptchaParameterConfig parameterConfig;
/**
* 生成验证码
* @return
*/
@Override
public PictureValidationVO generate() throws Exception {
log.info("生成图片验证码-service-开始");
//通过DefaultKaptcha获得随机验证码
String text = defaultKaptcha.createText();
//生成图片加密后Base64字符串
String imgBase64String = getImgBase64String(text);
//添加验证码,保存到数据库中
PictureValidationCodeDO pictureValidationCodeDO = savePictureValidationCode(text);
//构造图片验证码(id,code)
PictureValidationVO pictureValidationVO = new PictureValidationVO(pictureValidationCodeDO.getId(), imgBase64String);
log.info("生成图片验证码-service-结束[id:{}]", pictureValidationVO.getId());
return pictureValidationVO;
}
/**
* 校验验证码
* @param checkRequest
*/
@Override
public void validate(PictureValidationCheckRequest checkRequest) throws Exception {
log.debug("校验图片验证码-service-开始[checkRequest:{}]", checkRequest);
//根据id查询验证码
Optional<PictureValidationCodeDO> validationCodeDO = pictureValidationCodeRepository.findById(checkRequest.getId());
//判断验证码是否存在
if (!validationCodeDO.isPresent()){
log.info("校验验证码失败,验证码不存在[checkRequest:{}]", checkRequest);
throw new Exception("验证码不存在");
}
PictureValidationCodeDO pictureValidationCodeDO = validationCodeDO.get();
//校验验证码是否过期
if (System.currentTimeMillis() - pictureValidationCodeDO.getCreateDate().getTime() > parameterConfig.getValidDuration()) {
log.info("校验验证码失败,验证码已过期[checkRequest:{}]", checkRequest);
throw new Exception("验证码已过期");
}
//判断输入的验证码是否正确
if(!pictureValidationCodeDO.getCode().equals(checkRequest.getCode())){
log.info("验证码错误[checkRequest:{}]", checkRequest);
}
log.info("校验图片验证码-service-结束");
}
/**
* 添加验证码(保存到数据库中)
* @param code
* @return
*/
private PictureValidationCodeDO savePictureValidationCode(String code){
PictureValidationCodeDO pictureValidationCodeDO = new PictureValidationCodeDO();
pictureValidationCodeDO.setCode(code);
PictureValidationCodeDO save = pictureValidationCodeRepository.save(pictureValidationCodeDO);
return save;
}
/**
* 生成图片加密后Base64字符串
*
* @param code
* @return Base64字符串
*/
private String getImgBase64String(String code) throws Exception {
//将我们生成的随机验证码转换为图片
//将验证码图片转换成字节流
BufferedImage image = defaultKaptcha.createImage(code);
//获取二进制输出流
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
ImageIO.write(image, "jpg", jpegOutputStream);
} catch (IOException e) {
e.printStackTrace();
throw new Exception("验证码图片转换成字节流失败");
}
//返回Base64字符串
return Base64.encodeBase64String(jpegOutputStream.toByteArray());
}
}
5、然后就是我们的Controller类
@RestController
@Slf4j
@Api(tags = "图片验证码管理", description = "图片验证码管理")
public class PictureValidationCodeController {
@Autowired
private PictureValidationCodeService pictureValidationCodeService;
/**
* 生成图片验证码
* @return
*/
@ApiOperation("生成图片验证码")
@GetMapping("/generate")
public PictureValidationVO generate() throws Exception {
log.info("生成图片验证码开始" );
PictureValidationVO pictureValidationVO = pictureValidationCodeService.generate();
log.info("生成验证码成功");
return pictureValidationVO;
}
/**
* 校验验证码
* @param checkRequest
* @throws Exception
*/
@ApiOperation("校验验证码")
@PostMapping("/validate")
public void validate(PictureValidationCheckRequest checkRequest) throws Exception {
log.info("校验验证码开始");
pictureValidationCodeService.validate(checkRequest);
log.info("校验验证码成功");
}
}
然后我们就可以直接测试一下
这就生成成功了校验也是一样的,因为我是直接存到数据库的,所以我们直接去数据库看
这就考验看到,我们的验证码id,以及他们的值,我们在前端看到的话,就是一个图片,和平时的验证码一样