mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-23 10:33:53 +08:00
旋转图片
This commit is contained in:
@@ -34,6 +34,7 @@
|
|||||||
### 2. 使用 `SliderCaptchaGenerator`生成器生成滑块验证码
|
### 2. 使用 `SliderCaptchaGenerator`生成器生成滑块验证码
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.impl.StandardSliderCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.impl.StandardSliderCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager;
|
||||||
@@ -41,9 +42,9 @@ import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaRe
|
|||||||
public class Test {
|
public class Test {
|
||||||
public static void main(String[] args) throws InterruptedException {
|
public static void main(String[] args) throws InterruptedException {
|
||||||
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
|
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
|
||||||
StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, true);
|
StandardImageCaptchaGenerator sliderCaptchaGenerator = new StandardImageCaptchaGenerator(sliderCaptchaResourceManager, true);
|
||||||
// 生成滑块图片
|
// 生成滑块图片
|
||||||
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo();
|
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateCaptchaImage();
|
||||||
System.out.println(slideImageInfo);
|
System.out.println(slideImageInfo);
|
||||||
|
|
||||||
// 负责计算一些数据存到缓存中,用于校验使用
|
// 负责计算一些数据存到缓存中,用于校验使用
|
||||||
@@ -58,11 +59,12 @@ public class Test {
|
|||||||
### 3. 使用`SliderCaptchaValidator`校验器 验证
|
### 3. 使用`SliderCaptchaValidator`校验器 验证
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.SliderCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.SliderCaptchaGenerator;
|
||||||
|
|
||||||
public class Test2 {
|
public class Test2 {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SliderCaptchaGenerator sliderCaptchaValidator = new BasicCaptchaTrackValidator();
|
ImageCaptchaGenerator sliderCaptchaValidator = new BasicCaptchaTrackValidator();
|
||||||
|
|
||||||
// 用户传来的行为轨迹和进行校验
|
// 用户传来的行为轨迹和进行校验
|
||||||
// - sliderCaptchaTrack为前端传来的滑动轨迹数据
|
// - sliderCaptchaTrack为前端传来的滑动轨迹数据
|
||||||
|
|||||||
@@ -176,4 +176,43 @@ public class CaptchaImageUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 旋转图片
|
||||||
|
// *
|
||||||
|
// * @param bufferedImage 图片
|
||||||
|
// * @param degree 旋转xx度
|
||||||
|
// */
|
||||||
|
// public static void rotateImage(BufferedImage bufferedImage, int degree) {
|
||||||
|
// // 创建Graphics2D对象,用在底图对象上绘图
|
||||||
|
// Graphics2D g2d = bufferedImage.createGraphics();
|
||||||
|
// // 绘制
|
||||||
|
// g2d.rotate(Math.toRadians(degree), bufferedImage.getWidth() / 2, bufferedImage.getHeight()/2);
|
||||||
|
// g2d.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null);
|
||||||
|
// // 释放图形上下文使用的系统资源
|
||||||
|
// g2d.dispose();
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static BufferedImage rotateImage(final BufferedImage bufferedimage,
|
||||||
|
final double degree) {
|
||||||
|
// 得到图片宽度。
|
||||||
|
int w = bufferedimage.getWidth();
|
||||||
|
// 得到图片高度。
|
||||||
|
int h = bufferedimage.getHeight();
|
||||||
|
// 得到图片透明度。
|
||||||
|
int type = bufferedimage.getColorModel().getTransparency();
|
||||||
|
BufferedImage img;// 空的图片。
|
||||||
|
Graphics2D graphics2d;// 空的画笔。
|
||||||
|
(graphics2d = (img = new BufferedImage(w, h, type))
|
||||||
|
.createGraphics()).setRenderingHint(
|
||||||
|
RenderingHints.KEY_INTERPOLATION,
|
||||||
|
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||||
|
// 旋转,degree是整型,度数,比如垂直90度。
|
||||||
|
graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);
|
||||||
|
// 从bufferedimagecopy图片至img,0,0是img的坐标。
|
||||||
|
graphics2d.drawImage(bufferedimage, 0, 0, null);
|
||||||
|
graphics2d.dispose();
|
||||||
|
// 返回复制好的图片,原图片依然没有变,没有旋转,下次还可以使用。
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/4/22 16:30
|
||||||
|
* @Description 抽象的验证码生成器
|
||||||
|
*/
|
||||||
|
public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||||
|
public static String DEFAULT_BG_IMAGE_TYPE = "jpeg";
|
||||||
|
public static String DEFAULT_SLIDER_IMAGE_TYPE = "png";
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
/** 默认背景图片类型. */
|
||||||
|
public String defaultBgImageType = DEFAULT_BG_IMAGE_TYPE;
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
/** 默认滑块图片类型. */
|
||||||
|
public String defaultSliderImageType = DEFAULT_SLIDER_IMAGE_TYPE;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageCaptchaInfo generateCaptchaImage(String type) {
|
||||||
|
return generateCaptchaImage(type, defaultBgImageType, defaultSliderImageType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public ImageCaptchaInfo generateCaptchaImage(String type, String backgroundFormatName, String sliderFormatName) {
|
||||||
|
return generateCaptchaImage(GenerateParam.builder()
|
||||||
|
.type(type)
|
||||||
|
.backgroundFormatName(backgroundFormatName)
|
||||||
|
.sliderFormatName(sliderFormatName)
|
||||||
|
.obfuscate(false)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将图片转换成字符串格式
|
||||||
|
*
|
||||||
|
* @param bufferedImage 图片
|
||||||
|
* @param formatType 格式化类型
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
|
||||||
|
//转换成字节码
|
||||||
|
byte[] data = byteArrayOutputStream.toByteArray();
|
||||||
|
String base64 = Base64.getEncoder().encodeToString(data);
|
||||||
|
return "data:image/" + formatType + ";base64,".concat(base64);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InputStream getTemplateFile(Map<String, Resource> templateImages, String imageName) {
|
||||||
|
Resource resource = templateImages.get(imageName);
|
||||||
|
if (resource == null) {
|
||||||
|
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
|
||||||
|
}
|
||||||
|
return getSlideImageResourceManager().getResourceInputStream(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+11
-21
@@ -1,33 +1,35 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator;
|
package cloud.tianai.captcha.template.slider.generator;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
|
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
* @date 2020/10/19 18:37
|
* @date 2020/10/19 18:37
|
||||||
* @Description 滑块验证码模板
|
* @Description 图片验证码生成器
|
||||||
*/
|
*/
|
||||||
public interface SliderCaptchaGenerator {
|
public interface ImageCaptchaGenerator {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取滑块验证码
|
* 生成验证码图片
|
||||||
*
|
* @param type 类型 {@link CaptchaTypeConstant}
|
||||||
* @return SliderCaptchaInfo
|
* @return SliderCaptchaInfo
|
||||||
*/
|
*/
|
||||||
SliderCaptchaInfo generateSlideImageInfo();
|
ImageCaptchaInfo generateCaptchaImage(String type);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成滑块验证码
|
* 生成滑块验证码
|
||||||
*
|
* @param type type {@link CaptchaTypeConstant}
|
||||||
* @param targetFormatName jpeg或者webp格式
|
* @param targetFormatName jpeg或者webp格式
|
||||||
* @param matrixFormatName png或者webp格式
|
* @param matrixFormatName png或者webp格式
|
||||||
* @return SliderCaptchaInfo
|
* @return SliderCaptchaInfo
|
||||||
*/
|
*/
|
||||||
SliderCaptchaInfo generateSlideImageInfo(String targetFormatName, String matrixFormatName);
|
ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成滑块验证码
|
* 生成滑块验证码
|
||||||
@@ -35,20 +37,8 @@ public interface SliderCaptchaGenerator {
|
|||||||
* @param param 生成参数
|
* @param param 生成参数
|
||||||
* @return SliderCaptchaInfo
|
* @return SliderCaptchaInfo
|
||||||
*/
|
*/
|
||||||
SliderCaptchaInfo generateSlideImageInfo(GenerateParam param);
|
ImageCaptchaInfo generateCaptchaImage(GenerateParam param);
|
||||||
|
|
||||||
/**
|
|
||||||
* 百分比对比
|
|
||||||
*
|
|
||||||
* @param newPercentage 用户百分比
|
|
||||||
* @param oriPercentage 原百分比
|
|
||||||
* @return true 成功 false 失败
|
|
||||||
* <p>
|
|
||||||
* 废除 , 建议使用
|
|
||||||
* @see SliderCaptchaValidator 进行校验
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
boolean percentageContrast(Float newPercentage, Float oriPercentage);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取滑块验证码资源管理器
|
* 获取滑块验证码资源管理器
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator.common.constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2021/8/7 17:14
|
||||||
|
* @Description 滑块类型
|
||||||
|
*/
|
||||||
|
public interface CaptchaTypeConstant {
|
||||||
|
|
||||||
|
/** 滑块. */
|
||||||
|
String SLIDER = "SLIDER";
|
||||||
|
/** 旋转. */
|
||||||
|
String ROTATE = "ROTATE";
|
||||||
|
}
|
||||||
+2
@@ -21,4 +21,6 @@ public class GenerateParam {
|
|||||||
private String sliderFormatName = "png";
|
private String sliderFormatName = "png";
|
||||||
/** 是否混淆.*/
|
/** 是否混淆.*/
|
||||||
private Boolean obfuscate = false;
|
private Boolean obfuscate = false;
|
||||||
|
/** 类型.*/
|
||||||
|
private String type;
|
||||||
}
|
}
|
||||||
|
|||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @Date 2020/5/29 8:04
|
||||||
|
* @Description 滑块验证码
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class ImageCaptchaInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 背景图
|
||||||
|
*/
|
||||||
|
private String backgroundImage;
|
||||||
|
/**
|
||||||
|
* 移动图
|
||||||
|
*/
|
||||||
|
private String sliderImage;
|
||||||
|
/** 背景图片宽度. */
|
||||||
|
private Integer bgImageWidth;
|
||||||
|
/** 背景图片高度. */
|
||||||
|
private Integer bgImageHeight;
|
||||||
|
/** 滑块图片宽度. */
|
||||||
|
private Integer sliderImageWidth;
|
||||||
|
/** 滑块图片高度. */
|
||||||
|
private Integer sliderImageHeight;
|
||||||
|
/** 随机值.*/
|
||||||
|
private Integer randomX;
|
||||||
|
/**
|
||||||
|
* 扩展字段
|
||||||
|
*/
|
||||||
|
public Object expand;
|
||||||
|
|
||||||
|
public ImageCaptchaInfo(String backgroundImage,
|
||||||
|
String sliderImage,
|
||||||
|
Integer bgImageWidth,
|
||||||
|
Integer bgImageHeight,
|
||||||
|
Integer sliderImageWidth,
|
||||||
|
Integer sliderImageHeight,
|
||||||
|
Integer randomX) {
|
||||||
|
this.backgroundImage = backgroundImage;
|
||||||
|
this.sliderImage = sliderImage;
|
||||||
|
this.bgImageWidth = bgImageWidth;
|
||||||
|
this.bgImageHeight = bgImageHeight;
|
||||||
|
this.sliderImageWidth = sliderImageWidth;
|
||||||
|
this.sliderImageHeight = sliderImageHeight;
|
||||||
|
this.randomX = randomX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ImageCaptchaInfo of(String backgroundImage,
|
||||||
|
String sliderImage,
|
||||||
|
Integer bgImageWidth,
|
||||||
|
Integer bgImageHeight,
|
||||||
|
Integer sliderImageWidth,
|
||||||
|
Integer sliderImageHeight,
|
||||||
|
Integer randomKey) {
|
||||||
|
return new ImageCaptchaInfo( backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/4/22 15:49
|
||||||
|
* @Description 旋转图片
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
||||||
|
/**
|
||||||
|
* 旋转多少度
|
||||||
|
*/
|
||||||
|
private Double degree;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static RotateImageCaptchaInfo of(Double degree,
|
||||||
|
Integer randomX,
|
||||||
|
String backgroundImage,
|
||||||
|
String sliderImage,
|
||||||
|
Integer bgImageWidth,
|
||||||
|
Integer bgImageHeight,
|
||||||
|
Integer sliderImageWidth,
|
||||||
|
Integer sliderImageHeight) {
|
||||||
|
RotateImageCaptchaInfo rotateImageCaptchaInfo = new RotateImageCaptchaInfo();
|
||||||
|
rotateImageCaptchaInfo.setDegree(degree);
|
||||||
|
rotateImageCaptchaInfo.setRandomX(randomX);
|
||||||
|
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||||
|
rotateImageCaptchaInfo.setSliderImage(sliderImage);
|
||||||
|
rotateImageCaptchaInfo.setBgImageWidth(bgImageWidth);
|
||||||
|
rotateImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||||
|
rotateImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||||
|
rotateImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||||
|
return rotateImageCaptchaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
-66
@@ -1,66 +0,0 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Author: 天爱有情
|
|
||||||
* @Date 2020/5/29 8:04
|
|
||||||
* @Description 滑块验证码
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class SliderCaptchaInfo {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* x轴
|
|
||||||
*/
|
|
||||||
private Integer x;
|
|
||||||
/**
|
|
||||||
* y轴
|
|
||||||
*/
|
|
||||||
private Integer y;
|
|
||||||
/**
|
|
||||||
* 背景图
|
|
||||||
*/
|
|
||||||
private String backgroundImage;
|
|
||||||
/**
|
|
||||||
* 移动图
|
|
||||||
*/
|
|
||||||
private String sliderImage;
|
|
||||||
/** 背景图片宽度. */
|
|
||||||
private Integer bgImageWidth;
|
|
||||||
/** 背景图片高度. */
|
|
||||||
private Integer bgImageHeight;
|
|
||||||
/** 滑块图片宽度. */
|
|
||||||
private Integer sliderImageWidth;
|
|
||||||
/** 滑块图片高度. */
|
|
||||||
private Integer sliderImageHeight;
|
|
||||||
/**
|
|
||||||
* 扩展字段
|
|
||||||
*/
|
|
||||||
public Object expand;
|
|
||||||
|
|
||||||
public SliderCaptchaInfo(Integer x, Integer y, String backgroundImage, String sliderImage, Integer bgImageWidth, Integer bgImageHeight, Integer sliderImageWidth, Integer sliderImageHeight) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.backgroundImage = backgroundImage;
|
|
||||||
this.sliderImage = sliderImage;
|
|
||||||
this.bgImageWidth = bgImageWidth;
|
|
||||||
this.bgImageHeight = bgImageHeight;
|
|
||||||
this.sliderImageWidth = sliderImageWidth;
|
|
||||||
this.sliderImageHeight = sliderImageHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SliderCaptchaInfo of(Integer x,
|
|
||||||
Integer y,
|
|
||||||
String backgroundImage,
|
|
||||||
String sliderImage,
|
|
||||||
Integer bgImageWidth,
|
|
||||||
Integer bgImageHeight,
|
|
||||||
Integer sliderImageWidth,
|
|
||||||
Integer sliderImageHeight) {
|
|
||||||
return new SliderCaptchaInfo(x, y, backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class SliderImageCaptchaInfo extends ImageCaptchaInfo {
|
||||||
|
/**
|
||||||
|
* x轴
|
||||||
|
*/
|
||||||
|
private Integer x;
|
||||||
|
/**
|
||||||
|
* y轴
|
||||||
|
*/
|
||||||
|
private Integer y;
|
||||||
|
|
||||||
|
|
||||||
|
public static SliderImageCaptchaInfo of(Integer x,
|
||||||
|
Integer y,
|
||||||
|
String backgroundImage,
|
||||||
|
String sliderImage,
|
||||||
|
Integer bgImageWidth,
|
||||||
|
Integer bgImageHeight,
|
||||||
|
Integer sliderImageWidth,
|
||||||
|
Integer sliderImageHeight) {
|
||||||
|
SliderImageCaptchaInfo sliderImageCaptchaInfo = new SliderImageCaptchaInfo();
|
||||||
|
sliderImageCaptchaInfo.setX(x);
|
||||||
|
sliderImageCaptchaInfo.setY(y);
|
||||||
|
sliderImageCaptchaInfo.setRandomX(x);
|
||||||
|
sliderImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||||
|
sliderImageCaptchaInfo.setSliderImage(sliderImage);
|
||||||
|
sliderImageCaptchaInfo.setBgImageWidth(bgImageWidth);
|
||||||
|
sliderImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||||
|
sliderImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||||
|
sliderImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||||
|
|
||||||
|
return sliderImageCaptchaInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+17
-22
@@ -1,8 +1,8 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.SliderCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.util.NamedThreadFactory;
|
import cloud.tianai.captcha.template.slider.common.util.NamedThreadFactory;
|
||||||
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -22,12 +22,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
* @Description 滑块验证码缓冲器
|
* @Description 滑块验证码缓冲器
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||||
|
|
||||||
protected final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("slider-captcha-queue"));
|
protected final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("slider-captcha-queue"));
|
||||||
protected ConcurrentLinkedQueue<SliderCaptchaInfo> queue;
|
protected ConcurrentLinkedQueue<ImageCaptchaInfo> queue;
|
||||||
protected AtomicInteger pos = new AtomicInteger(0);
|
protected AtomicInteger pos = new AtomicInteger(0);
|
||||||
protected SliderCaptchaGenerator target;
|
protected ImageCaptchaGenerator target;
|
||||||
protected int size;
|
protected int size;
|
||||||
/** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */
|
/** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */
|
||||||
protected int waitTime = 1000;
|
protected int waitTime = 1000;
|
||||||
@@ -39,13 +39,13 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
@Setter
|
@Setter
|
||||||
protected boolean requiredGetCaptcha = true;
|
protected boolean requiredGetCaptcha = true;
|
||||||
|
|
||||||
public CacheSliderCaptchaGenerator(SliderCaptchaGenerator target, GenerateParam generateParam, int size) {
|
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.generateParam = generateParam;
|
this.generateParam = generateParam;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CacheSliderCaptchaGenerator(SliderCaptchaGenerator target, GenerateParam generateParam, int size, int waitTime, int period) {
|
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size, int waitTime, int period) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.generateParam = generateParam;
|
this.generateParam = generateParam;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
@@ -71,7 +71,7 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
if (pos.get() >= size) {
|
if (pos.get() >= size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SliderCaptchaInfo slideImageInfo = target.generateSlideImageInfo(generateParam);
|
ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(generateParam);
|
||||||
if (slideImageInfo != null) {
|
if (slideImageInfo != null) {
|
||||||
boolean addStatus = queue.offer(slideImageInfo);
|
boolean addStatus = queue.offer(slideImageInfo);
|
||||||
if (addStatus) {
|
if (addStatus) {
|
||||||
@@ -101,17 +101,17 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public SliderCaptchaInfo generateSlideImageInfo() {
|
public ImageCaptchaInfo generateCaptchaImage(String type) {
|
||||||
return generateSlideImageInfo(this.requiredGetCaptcha);
|
return generateCaptchaImage(this.requiredGetCaptcha);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public SliderCaptchaInfo generateSlideImageInfo(boolean requiredGetCaptcha) {
|
public ImageCaptchaInfo generateCaptchaImage(boolean requiredGetCaptcha) {
|
||||||
SliderCaptchaInfo poll = queue.poll();
|
ImageCaptchaInfo poll = queue.poll();
|
||||||
if (poll == null && requiredGetCaptcha) {
|
if (poll == null && requiredGetCaptcha) {
|
||||||
log.warn("滑块验证码缓存不足, genParam:{}", generateParam);
|
log.warn("滑块验证码缓存不足, genParam:{}", generateParam);
|
||||||
// 如果池内没数据, 则直接生成
|
// 如果池内没数据, 则直接生成
|
||||||
return target.generateSlideImageInfo(generateParam);
|
return target.generateCaptchaImage(generateParam);
|
||||||
}
|
}
|
||||||
// 减1
|
// 减1
|
||||||
pos.decrementAndGet();
|
pos.decrementAndGet();
|
||||||
@@ -119,18 +119,13 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SliderCaptchaInfo generateSlideImageInfo(String targetFormatName, String matrixFormatName) {
|
public ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName) {
|
||||||
return target.generateSlideImageInfo(targetFormatName, matrixFormatName);
|
return target.generateCaptchaImage(type,targetFormatName, matrixFormatName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SliderCaptchaInfo generateSlideImageInfo(GenerateParam param) {
|
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||||
return target.generateSlideImageInfo(param);
|
return target.generateCaptchaImage(param);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean percentageContrast(Float newPercentage, Float oriPercentage) {
|
|
||||||
return target.percentageContrast(newPercentage, oriPercentage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
+26
-99
@@ -1,24 +1,25 @@
|
|||||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||||
import cloud.tianai.captcha.template.slider.generator.SliderCaptchaGenerator;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
|
||||||
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
import lombok.Getter;
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
import lombok.Setter;
|
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||||
@@ -29,7 +30,7 @@ import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils
|
|||||||
* @Description 滑块验证码模板
|
* @Description 滑块验证码模板
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认的resource资源文件路径.
|
* 默认的resource资源文件路径.
|
||||||
@@ -40,59 +41,28 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
*/
|
*/
|
||||||
public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template";
|
public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template";
|
||||||
|
|
||||||
public static String DEFAULT_BG_IMAGE_TYPE = "jpeg";
|
|
||||||
public static String DEFAULT_SLIDER_IMAGE_TYPE = "png";
|
|
||||||
public static float DEFAULT_TOLERANT = 0.02f;
|
|
||||||
|
|
||||||
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
/** 容错值. */
|
|
||||||
public float tolerant = DEFAULT_TOLERANT;
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
/** 默认背景图片类型. */
|
|
||||||
public String defaultBgImageType = DEFAULT_BG_IMAGE_TYPE;
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
/** 默认滑块图片类型. */
|
|
||||||
public String defaultSliderImageType = DEFAULT_SLIDER_IMAGE_TYPE;
|
|
||||||
|
|
||||||
public StandardSliderCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager,
|
public StandardImageCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager,
|
||||||
boolean initDefaultResource) {
|
boolean initDefaultResource) {
|
||||||
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
||||||
if (initDefaultResource) {
|
if (initDefaultResource) {
|
||||||
initDefaultResource();
|
initDefaultResource();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public SliderCaptchaInfo generateSlideImageInfo() {
|
|
||||||
return generateSlideImageInfo(defaultBgImageType, defaultSliderImageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
public SliderCaptchaInfo generateSlideImageInfo(String backgroundFormatName, String sliderFormatName) {
|
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||||
return generateSlideImageInfo(GenerateParam.builder()
|
|
||||||
.backgroundFormatName(backgroundFormatName)
|
|
||||||
.sliderFormatName(sliderFormatName)
|
|
||||||
.obfuscate(false)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
|
||||||
public SliderCaptchaInfo generateSlideImageInfo(GenerateParam param) {
|
|
||||||
Boolean obfuscate = param.getObfuscate();
|
Boolean obfuscate = param.getObfuscate();
|
||||||
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate();
|
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType());
|
||||||
if (templateImages == null || templateImages.isEmpty()) {
|
if (templateImages == null || templateImages.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collection<InputStream> inputStreams = new LinkedList<>();
|
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||||
try {
|
try {
|
||||||
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource();
|
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType());
|
||||||
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage);
|
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||||
inputStreams.add(resourceInputStream);
|
inputStreams.add(resourceInputStream);
|
||||||
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
|
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
|
||||||
@@ -151,16 +121,16 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
* @return SliderCaptchaInfo
|
* @return SliderCaptchaInfo
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public SliderCaptchaInfo wrapSliderCaptchaInfo(int randomX,
|
public SliderImageCaptchaInfo wrapSliderCaptchaInfo(int randomX,
|
||||||
int randomY,
|
int randomY,
|
||||||
BufferedImage backgroundImage,
|
BufferedImage backgroundImage,
|
||||||
BufferedImage sliderImage,
|
BufferedImage sliderImage,
|
||||||
GenerateParam param) {
|
GenerateParam param) {
|
||||||
String backgroundFormatName = param.getBackgroundFormatName();
|
String backgroundFormatName = param.getBackgroundFormatName();
|
||||||
String sliderFormatName = param.getSliderFormatName();
|
String sliderFormatName = param.getSliderFormatName();
|
||||||
String backGroundImageBase64 = transform(backgroundImage, backgroundFormatName);
|
String backGroundImageBase64 = transform(backgroundImage, backgroundFormatName);
|
||||||
String sliderImageBase64 = transform(sliderImage, sliderFormatName);
|
String sliderImageBase64 = transform(sliderImage, sliderFormatName);
|
||||||
return SliderCaptchaInfo.of(randomX, randomY,
|
return SliderImageCaptchaInfo.of(randomX, randomY,
|
||||||
backGroundImageBase64,
|
backGroundImageBase64,
|
||||||
sliderImageBase64,
|
sliderImageBase64,
|
||||||
backgroundImage.getWidth(), backgroundImage.getHeight(),
|
backgroundImage.getWidth(), backgroundImage.getHeight(),
|
||||||
@@ -168,41 +138,6 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将图片转换成字符串格式
|
|
||||||
*
|
|
||||||
* @param bufferedImage 图片
|
|
||||||
* @param formatType 格式化类型
|
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
|
||||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
|
||||||
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
|
|
||||||
//转换成字节码
|
|
||||||
byte[] data = byteArrayOutputStream.toByteArray();
|
|
||||||
String base64 = Base64.getEncoder().encodeToString(data);
|
|
||||||
return "data:image/" + formatType + ";base64,".concat(base64);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 百分比对比
|
|
||||||
*
|
|
||||||
* @param newPercentage 用户百分比
|
|
||||||
* @param oriPercentage 原百分比
|
|
||||||
* @return true 成功 false 失败
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean percentageContrast(Float newPercentage, Float oriPercentage) {
|
|
||||||
if (newPercentage == null || Float.isNaN(newPercentage) || Float.isInfinite(newPercentage)
|
|
||||||
|| oriPercentage == null || Float.isNaN(oriPercentage) || Float.isInfinite(oriPercentage)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 容错值
|
|
||||||
float maxTolerant = oriPercentage + tolerant;
|
|
||||||
float minTolerant = oriPercentage - tolerant;
|
|
||||||
return newPercentage >= minTolerant && newPercentage <= maxTolerant;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||||
return sliderCaptchaResourceManager;
|
return sliderCaptchaResourceManager;
|
||||||
@@ -217,34 +152,26 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
|||||||
return ThreadLocalRandom.current().nextInt(slWidth, sliderX - slWidth);
|
return ThreadLocalRandom.current().nextInt(slWidth, sliderX - slWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InputStream getTemplateFile(Map<String, Resource> templateImages, String imageName) {
|
|
||||||
Resource resource = templateImages.get(imageName);
|
|
||||||
if (resource == null) {
|
|
||||||
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
|
|
||||||
}
|
|
||||||
return sliderCaptchaResourceManager.getResourceInputStream(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化默认资源
|
* 初始化默认资源
|
||||||
*/
|
*/
|
||||||
public void initDefaultResource() {
|
public void initDefaultResource() {
|
||||||
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
||||||
// 添加一些系统的资源文件
|
// 添加一些系统的资源文件
|
||||||
resourceStore.addResource(new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||||
|
|
||||||
// 添加一些系统的 模板文件
|
// 添加一些系统的 模板文件
|
||||||
Map<String, Resource> template1 = new HashMap<>(4);
|
Map<String, Resource> template1 = new HashMap<>(4);
|
||||||
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));
|
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));
|
||||||
template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));
|
template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));
|
||||||
template1.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/matrix.png")));
|
template1.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/matrix.png")));
|
||||||
resourceStore.addTemplate(template1);
|
resourceStore.addTemplate(CaptchaTypeConstant.SLIDER, template1);
|
||||||
|
|
||||||
|
|
||||||
Map<String, Resource> template2 = new HashMap<>(4);
|
Map<String, Resource> template2 = new HashMap<>(4);
|
||||||
template2.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));
|
template2.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));
|
||||||
template2.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));
|
template2.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));
|
||||||
template2.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/matrix.png")));
|
template2.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/matrix.png")));
|
||||||
resourceStore.addTemplate(template2);
|
resourceStore.addTemplate(CaptchaTypeConstant.SLIDER, template2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+147
@@ -0,0 +1,147 @@
|
|||||||
|
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||||
|
import static cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
|
||||||
|
import static cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: 天爱有情
|
||||||
|
* @date 2022/4/22 16:43
|
||||||
|
* @Description 旋转图片验证码生成器
|
||||||
|
*/
|
||||||
|
public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||||
|
|
||||||
|
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
||||||
|
|
||||||
|
public StandardRotateCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager, boolean initDefaultResource) {
|
||||||
|
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
||||||
|
if (initDefaultResource) {
|
||||||
|
initDefaultResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initDefaultResource() {
|
||||||
|
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
||||||
|
// 添加一些系统的资源文件
|
||||||
|
resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||||
|
|
||||||
|
// 添加一些系统的 模板文件
|
||||||
|
Map<String, Resource> template1 = new HashMap<>(4);
|
||||||
|
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/active.png")));
|
||||||
|
template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/fixed.png")));
|
||||||
|
resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||||
|
// 旋转验证码没有混淆
|
||||||
|
Boolean obfuscate = param.getObfuscate();
|
||||||
|
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType());
|
||||||
|
if (templateImages == null || templateImages.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||||
|
try {
|
||||||
|
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType());
|
||||||
|
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||||
|
inputStreams.add(resourceInputStream);
|
||||||
|
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
|
||||||
|
// 拷贝一份图片
|
||||||
|
BufferedImage targetBackground = deepCopyBufferedImage(cutBackground);
|
||||||
|
|
||||||
|
InputStream fixedTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME);
|
||||||
|
inputStreams.add(fixedTemplateInput);
|
||||||
|
BufferedImage fixedTemplate = wrapFile2BufferedImage(fixedTemplateInput);
|
||||||
|
|
||||||
|
InputStream activeTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME);
|
||||||
|
inputStreams.add(activeTemplateInput);
|
||||||
|
BufferedImage activeTemplate = wrapFile2BufferedImage(activeTemplateInput);
|
||||||
|
// 算出居中的x和y
|
||||||
|
int x = targetBackground.getWidth() / 2 - fixedTemplate.getWidth() / 2;
|
||||||
|
int y = targetBackground.getHeight() / 2 - fixedTemplate.getHeight() / 2;
|
||||||
|
overlayImage(targetBackground, fixedTemplate, x, y);
|
||||||
|
// 抠图部分
|
||||||
|
BufferedImage cutImage = cutImage(cutBackground, fixedTemplate, x, y);
|
||||||
|
overlayImage(cutImage, activeTemplate, 0, 0);
|
||||||
|
// 随机旋转抠图部分
|
||||||
|
// 随机x, 转换为角度
|
||||||
|
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
|
||||||
|
double degree = randomX / ((targetBackground.getWidth()) / 360d);
|
||||||
|
// int degree = ThreadLocalRandom.current().nextInt(10, 350);
|
||||||
|
cutImage = rotateImage(cutImage, degree);
|
||||||
|
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, cutImage, param);
|
||||||
|
} finally {
|
||||||
|
// 使用完后关闭流
|
||||||
|
for (InputStream inputStream : inputStreams) {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
private ImageCaptchaInfo wrapRotateCaptchaInfo(double degree, int randomX, BufferedImage backgroundImage, BufferedImage sliderImage, GenerateParam param) {
|
||||||
|
String backgroundFormatName = param.getBackgroundFormatName();
|
||||||
|
String sliderFormatName = param.getSliderFormatName();
|
||||||
|
String backGroundImageBase64 = transform(backgroundImage, backgroundFormatName);
|
||||||
|
String sliderImageBase64 = transform(sliderImage, sliderFormatName);
|
||||||
|
return RotateImageCaptchaInfo.of(degree,
|
||||||
|
randomX,
|
||||||
|
backGroundImageBase64,
|
||||||
|
sliderImageBase64,
|
||||||
|
backgroundImage.getWidth(), backgroundImage.getHeight(),
|
||||||
|
sliderImage.getWidth(), sliderImage.getHeight()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||||
|
return sliderCaptchaResourceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
BufferedImage bgImage = CaptchaImageUtils.wrapFile2BufferedImage(
|
||||||
|
new FileInputStream("E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
|
||||||
|
BufferedImage image1 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
||||||
|
BufferedImage image2 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
||||||
|
|
||||||
|
BufferedImage cutImage = CaptchaImageUtils.cutImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
||||||
|
CaptchaImageUtils.overlayImage(cutImage, image2, 0, 0);
|
||||||
|
cutImage = CaptchaImageUtils.rotateImage(cutImage, 180);
|
||||||
|
CaptchaImageUtils.overlayImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
||||||
|
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a1.jpg");
|
||||||
|
FileOutputStream file2OutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a2.png");
|
||||||
|
ImageIO.write(bgImage, "jpeg", fileOutputStream);
|
||||||
|
ImageIO.write(cutImage, "png", file2OutputStream);
|
||||||
|
fileOutputStream.close();
|
||||||
|
file2OutputStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,97 +12,97 @@ public interface ResourceStore {
|
|||||||
*
|
*
|
||||||
* @param resource 资源
|
* @param resource 资源
|
||||||
*/
|
*/
|
||||||
void addResource(Resource resource);
|
void addResource(String type, Resource resource);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置资源
|
* 清除某个类型下的所有资源
|
||||||
*
|
*
|
||||||
* @param resources resources
|
* @param type type
|
||||||
*/
|
*/
|
||||||
void setResource(List<Resource> resources);
|
void clearResources(String type);
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除资源
|
|
||||||
*
|
|
||||||
* @param resource resource
|
|
||||||
*/
|
|
||||||
boolean deleteResource(Resource resource);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除所有资源
|
* 清除所有资源
|
||||||
*/
|
*/
|
||||||
void clearResources();
|
void clearAllResources();
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加模板
|
|
||||||
*
|
|
||||||
* @param template template
|
|
||||||
*/
|
|
||||||
void addTemplate(Map<String, Resource> template);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置模板
|
|
||||||
*
|
|
||||||
* @param templateResource templateResource
|
|
||||||
*/
|
|
||||||
void setTemplates(List<Map<String, Resource>> templateResource);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除模板
|
|
||||||
*
|
|
||||||
* @param template template
|
|
||||||
*/
|
|
||||||
void deleteTemplate(Map<String, Resource> template);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除所有模板
|
|
||||||
*/
|
|
||||||
void clearTemplates();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有资源对象
|
* 获取所有资源对象
|
||||||
*
|
*
|
||||||
* @return List<Resource>
|
* @return List<Resource>
|
||||||
*/
|
*/
|
||||||
List<Resource> listResources();
|
Map<String,List<Resource>> listAllResources();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有模板
|
* 获取某个type下的所有资源对象
|
||||||
*
|
*
|
||||||
* @return List<Map < String, Resource>>
|
* @param type type
|
||||||
|
* @return List<Resource>
|
||||||
*/
|
*/
|
||||||
List<Map<String, Resource>> listTemplates();
|
List<Resource> listResourcesByType(String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机获取某个资源
|
||||||
|
*
|
||||||
|
* @param type type
|
||||||
|
* @return Resource
|
||||||
|
*/
|
||||||
|
Resource randomGetResource(String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取资源总数
|
* 获取资源总数
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int getResourceCount();
|
int getAllResourceCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取模板count
|
* 获取某个type下的资源总数
|
||||||
*
|
*
|
||||||
|
* @param type type
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int getTemplateCount();
|
int getResourceCount(String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取资源通过index
|
* 添加模板
|
||||||
*
|
*
|
||||||
* @param index index
|
* @param template template
|
||||||
* @return Resource
|
|
||||||
*/
|
*/
|
||||||
Resource getResourceByIndex(int index);
|
void addTemplate(String type, Map<String, Resource> template);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取模板通过indx
|
* 清除所有模板
|
||||||
|
*/
|
||||||
|
void clearAllTemplates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除某个type下的所有模板
|
||||||
*
|
*
|
||||||
* @param index index
|
* @param type type
|
||||||
|
*/
|
||||||
|
void clearTemplates(String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有模板通过type
|
||||||
|
*
|
||||||
|
* @return List<Map < String, Resource>>
|
||||||
|
*/
|
||||||
|
List<Map<String, Resource>> listTemplatesByType(String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有模板
|
||||||
|
*
|
||||||
|
* @return Map<String, List < Map < String, Resource>>>
|
||||||
|
*/
|
||||||
|
Map<String, List<Map<String, Resource>>> listAllTemplates();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机获取某个模板通过type
|
||||||
|
*
|
||||||
|
* @param type type
|
||||||
* @return Map<String, Resource>
|
* @return Map<String, Resource>
|
||||||
*/
|
*/
|
||||||
Map<String, Resource> getTemplateByIndex(int index);
|
Map<String, Resource> randomGetTemplateByType(String type);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -18,14 +18,14 @@ public interface SliderCaptchaResourceManager {
|
|||||||
*
|
*
|
||||||
* @return Map<String, Resource>
|
* @return Map<String, Resource>
|
||||||
*/
|
*/
|
||||||
Map<String, Resource> randomGetTemplate();
|
Map<String, Resource> randomGetTemplate(String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 随机获取某个资源对象
|
* 随机获取某个资源对象
|
||||||
*
|
*
|
||||||
* @return Resource
|
* @return Resource
|
||||||
*/
|
*/
|
||||||
Resource randomGetResource();
|
Resource randomGetResource(String type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取真正的资源流通过资源对象
|
* 获取真正的资源流通过资源对象
|
||||||
|
|||||||
+75
-59
@@ -1,12 +1,11 @@
|
|||||||
package cloud.tianai.captcha.template.slider.resource.impl;
|
package cloud.tianai.captcha.template.slider.resource.impl;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||||
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -17,86 +16,103 @@ public class DefaultResourceStore implements ResourceStore {
|
|||||||
/**
|
/**
|
||||||
* 模板资源.
|
* 模板资源.
|
||||||
*/
|
*/
|
||||||
private List<Map<String, Resource>> templateResourceList = new ArrayList<>(2);
|
private Map<String, List<Map<String, Resource>>> templateResourceMap = new HashMap<>(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* resource.
|
* resource.
|
||||||
*/
|
*/
|
||||||
private List<Resource> resourceList = new ArrayList<>(20);
|
private Map<String, List<Resource>> resourceMap = new HashMap<>(2);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResource(Resource resource) {
|
public void addResource(String type, Resource resource) {
|
||||||
resourceList.add(resource);
|
resourceMap.computeIfAbsent(type, k -> new ArrayList<>(20)).add(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setResource(List<Resource> resources) {
|
public void clearResources(String type) {
|
||||||
resourceList = new ArrayList<>(resources);
|
resourceMap.remove(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteResource(Resource resource) {
|
public void clearAllResources() {
|
||||||
return resourceList.remove(resource);
|
resourceMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearResources() {
|
public Map<String, List<Resource>> listAllResources() {
|
||||||
resourceList.clear();
|
return resourceMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTemplate(Map<String, Resource> template) {
|
public List<Resource> listResourcesByType(String type) {
|
||||||
templateResourceList.add(template);
|
return resourceMap.getOrDefault(type, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTemplates(List<Map<String, Resource>> templateResource) {
|
public Resource randomGetResource(String type) {
|
||||||
templateResourceList = new ArrayList<>(templateResource);
|
List<Resource> resources = resourceMap.get(type);
|
||||||
}
|
if (CollectionUtils.isEmpty(resources)) {
|
||||||
|
throw new IllegalStateException("随机获取资源错误,store中资源为空, type:" + type);
|
||||||
@Override
|
|
||||||
public void deleteTemplate(Map<String, Resource> template) {
|
|
||||||
templateResourceList.remove(template);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearTemplates() {
|
|
||||||
templateResourceList.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Resource> listResources() {
|
|
||||||
return Collections.unmodifiableList(resourceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Map<String, Resource>> listTemplates() {
|
|
||||||
return Collections.unmodifiableList(templateResourceList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getResourceCount() {
|
|
||||||
return resourceList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTemplateCount() {
|
|
||||||
return templateResourceList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Resource getResourceByIndex(int index) {
|
|
||||||
if (index < 0 || index > resourceList.size() - 1) {
|
|
||||||
throw new IllegalArgumentException("错误的index");
|
|
||||||
}
|
}
|
||||||
return resourceList.get(index);
|
if (resources.size() == 1) {
|
||||||
|
return resources.get(0);
|
||||||
|
}
|
||||||
|
int randomIndex = ThreadLocalRandom.current().nextInt(resources.size());
|
||||||
|
return resources.get(randomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Resource> getTemplateByIndex(int index) {
|
public int getAllResourceCount() {
|
||||||
if (index < 0 || index > templateResourceList.size() - 1) {
|
int count = 0;
|
||||||
throw new IllegalArgumentException("错误的index");
|
for (List<Resource> value : resourceMap.values()) {
|
||||||
|
count += value.size();
|
||||||
}
|
}
|
||||||
return templateResourceList.get(index);
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getResourceCount(String type) {
|
||||||
|
return resourceMap.getOrDefault(type, Collections.emptyList()).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTemplate(String type, Map<String, Resource> template) {
|
||||||
|
templateResourceMap.computeIfAbsent(type, k -> new ArrayList<>(2)).add(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAllTemplates() {
|
||||||
|
templateResourceMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearTemplates(String type) {
|
||||||
|
templateResourceMap.remove(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Resource>> listTemplatesByType(String type) {
|
||||||
|
return templateResourceMap.getOrDefault(type, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<Map<String, Resource>>> listAllTemplates() {
|
||||||
|
return templateResourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Resource> randomGetTemplateByType(String type) {
|
||||||
|
List<Map<String, Resource>> templateList = templateResourceMap.get(type);
|
||||||
|
if (CollectionUtils.isEmpty(templateList)) {
|
||||||
|
throw new IllegalStateException("随机获取模板错误,store中模板为空, type:" + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templateList.size() == 1) {
|
||||||
|
return templateList.get(0);
|
||||||
|
}
|
||||||
|
int randomIndex = ThreadLocalRandom.current().nextInt(templateList.size());
|
||||||
|
return templateList.get(randomIndex);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-19
@@ -13,7 +13,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Author: 天爱有情
|
* @Author: 天爱有情
|
||||||
@@ -47,29 +46,21 @@ public class DefaultSliderCaptchaResourceManager implements SliderCaptchaResourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Resource> randomGetTemplate() {
|
public Map<String, Resource> randomGetTemplate(String type) {
|
||||||
int count = resourceStore.getTemplateCount();
|
Map<String, Resource> resourceMap = resourceStore.randomGetTemplateByType(type);
|
||||||
if (count < 1) {
|
if (resourceMap == null) {
|
||||||
throw new IllegalStateException("随机获取模板错误,store中模板为空");
|
throw new IllegalStateException("随机获取模板错误,store中模板为空, type:" + type);
|
||||||
}
|
}
|
||||||
if (count == 1) {
|
return resourceMap;
|
||||||
return resourceStore.getTemplateByIndex(0);
|
|
||||||
}
|
|
||||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
|
||||||
return resourceStore.getTemplateByIndex(randomIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource randomGetResource() {
|
public Resource randomGetResource(String type) {
|
||||||
int count = resourceStore.getResourceCount();
|
Resource resource = resourceStore.randomGetResource(type);
|
||||||
if (count < 1) {
|
if (resource == null) {
|
||||||
throw new IllegalStateException("随机获取资源错误,store中资源为空");
|
throw new IllegalStateException("随机获取资源错误,store中资源为空, type:" + type);
|
||||||
}
|
}
|
||||||
if (count == 1) {
|
return resource;
|
||||||
return resourceStore.getResourceByIndex(0);
|
|
||||||
}
|
|
||||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
|
||||||
return resourceStore.getResourceByIndex(randomIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
package cloud.tianai.captcha.template.slider.validator;
|
package cloud.tianai.captcha.template.slider.validator;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -43,10 +43,10 @@ public interface SliderCaptchaValidator {
|
|||||||
/**
|
/**
|
||||||
* 用于生成验证码校验时需要的回传参数
|
* 用于生成验证码校验时需要的回传参数
|
||||||
*
|
*
|
||||||
* @param sliderCaptchaInfo 生成的验证码数据
|
* @param imageCaptchaInfo 生成的验证码数据
|
||||||
* @return Map<String, Object>
|
* @return Map<String, Object>
|
||||||
*/
|
*/
|
||||||
Map<String, Object> generateSliderCaptchaValidData(SliderCaptchaInfo sliderCaptchaInfo);
|
Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验用户滑动滑块是否正确
|
* 校验用户滑动滑块是否正确
|
||||||
|
|||||||
+5
-5
@@ -1,7 +1,7 @@
|
|||||||
package cloud.tianai.captcha.template.slider.validator.impl;
|
package cloud.tianai.captcha.template.slider.validator.impl;
|
||||||
|
|
||||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
|
||||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
|
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
|
||||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -56,9 +56,9 @@ public class SimpleSliderCaptchaValidator implements SliderCaptchaValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> generateSliderCaptchaValidData(SliderCaptchaInfo sliderCaptchaInfo) {
|
public Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||||
Map<String, Object> map = new HashMap<>(8);
|
Map<String, Object> map = new HashMap<>(8);
|
||||||
addPercentage(sliderCaptchaInfo, map);
|
addPercentage(imageCaptchaInfo, map);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +106,8 @@ public class SimpleSliderCaptchaValidator implements SliderCaptchaValidator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addPercentage(SliderCaptchaInfo sliderCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
|
protected void addPercentage(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
|
||||||
float percentage = calcPercentage(sliderCaptchaInfo.getX(), sliderCaptchaInfo.getBgImageWidth());
|
float percentage = calcPercentage(imageCaptchaInfo.getRandomX(), imageCaptchaInfo.getBgImageWidth());
|
||||||
sliderCaptchaValidData.put("percentage", percentage);
|
sliderCaptchaValidData.put("percentage", percentage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,37 @@
|
|||||||
|
package example;
|
||||||
|
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
|
||||||
|
import cloud.tianai.captcha.template.slider.generator.impl.StandardRotateCaptchaGenerator;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.impl.DefaultResourceStore;
|
||||||
|
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class StandardRotateCaptchaGeneratorTest {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
ResourceStore resourceStore = new DefaultResourceStore();
|
||||||
|
// Map<String, Resource> template = new HashMap<>();
|
||||||
|
// template.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
||||||
|
// template.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
||||||
|
|
||||||
|
// resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template);
|
||||||
|
// resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("file", "E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
|
||||||
|
|
||||||
|
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(resourceStore);
|
||||||
|
|
||||||
|
StandardRotateCaptchaGenerator standardRotateCaptchaGenerator = new StandardRotateCaptchaGenerator(sliderCaptchaResourceManager, true);
|
||||||
|
ImageCaptchaInfo imageCaptchaInfo = standardRotateCaptchaGenerator.generateCaptchaImage(CaptchaTypeConstant.ROTATE);
|
||||||
|
System.out.println("backgroundImage:" + imageCaptchaInfo.getBackgroundImage());
|
||||||
|
System.out.println("sliderImage:" + imageCaptchaInfo.getSliderImage());
|
||||||
|
System.out.println(((RotateImageCaptchaInfo)imageCaptchaInfo).getDegree());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user