mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-17 05:14:05 +08:00
feat(captcha):重构点选验证码生成逻辑并优化验证轨迹处理
- 修改 AbstractClickImageCaptchaGenerator 中的图片提示资源结构,支持 ResourceMap 类型 - 引入 CommonConstant 常量用于区分提示图标与点击图标资源 - 新增 Block 类用于管理背景图上的可点击区域分块逻辑 - 更新点击图片的位置计算方式,从随机坐标改为基于分块的确定位置 - 添加 obfuscateImage 方法用于后续图像混淆处理扩展 - 调整时间戳字段类型由 Date 改为 Long,提升性能及一致性 - 在 ParamKeyEnum 中新增 FONT_TAG 参数键,支持按标签读取字体资源 - 标准化字体获取方法,允许通过 GenerateParam 指定字体标签 -修正 DefaultBuiltInResources 中字体路径拼写错误(fontS → fonts) - 补充 ResourceStore 接口的 getTarget 默认方法实现 - 更新测试类 TACBuilderTest2 示例代码中的验证码类型调用参数
This commit is contained in:
+25
-6
@@ -6,6 +6,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -16,17 +17,35 @@ import java.awt.*;
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ClickImageCheckDefinition {
|
||||
/** 提示.*/
|
||||
/** 提示. */
|
||||
private Resource tip;
|
||||
/** x.*/
|
||||
private ImgWrapper tipImage;
|
||||
/** x. */
|
||||
private Integer x;
|
||||
/** y.*/
|
||||
/** y. */
|
||||
private Integer y;
|
||||
/** 宽.*/
|
||||
/** 宽. */
|
||||
private Integer width;
|
||||
/** 高.*/
|
||||
/** 高. */
|
||||
private Integer height;
|
||||
/** 颜色.*/
|
||||
/** 颜色. */
|
||||
private Color imageColor;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/28 14:26
|
||||
* @Description 点击图片包装
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ImgWrapper {
|
||||
/** 图片. */
|
||||
private BufferedImage image;
|
||||
/** 提示. */
|
||||
private Resource tip;
|
||||
/** 图片颜色. */
|
||||
private Color imageColor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ public class ParamKeyEnum<T> implements ParamKey<T> {
|
||||
public static final ParamKey<Integer> CLICK_CHECK_CLICK_COUNT = new ParamKeyEnum<>("checkClickCount");
|
||||
/** 点选验证码干扰数量. 值为Integer */
|
||||
public static final ParamKey<Integer> CLICK_INTERFERENCE_COUNT = new ParamKeyEnum<>("interferenceCount");
|
||||
|
||||
/** 读取字体时,可指定字体TAG,可用于给不同的验证码指定不同的字体包.*/
|
||||
public static final ParamKey<String> FONT_TAG = new ParamKeyEnum<>("fontTag");
|
||||
private String key;
|
||||
|
||||
}
|
||||
|
||||
+58
-30
@@ -1,5 +1,6 @@
|
||||
package cloud.tianai.captcha.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.common.constant.CommonConstant;
|
||||
import cloud.tianai.captcha.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.generator.common.model.dto.CaptchaExchange;
|
||||
import cloud.tianai.captcha.generator.common.model.dto.ClickImageCheckDefinition;
|
||||
@@ -7,6 +8,7 @@ import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
||||
import cloud.tianai.captcha.generator.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
||||
import cloud.tianai.captcha.resource.common.model.dto.Resource;
|
||||
import cloud.tianai.captcha.resource.common.model.dto.ResourceMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -16,6 +18,7 @@ import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -42,40 +45,67 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
||||
|
||||
BufferedImage bgImage = getResourceImage(resourceImage);
|
||||
|
||||
List<Resource> imgTips = randomGetClickImgTips(param);
|
||||
List<ResourceMap> imgTips = randomGetClickImgTips(param);
|
||||
int allImages = imgTips.size();
|
||||
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = new ArrayList<>(allImages);
|
||||
int avg = bgImage.getWidth() / allImages;
|
||||
if (allImages < imgTips.size()) {
|
||||
throw new IllegalStateException("随机生成点击图片小于请求数量, 请求生成数量=" + allImages + ",实际生成数量=" + imgTips.size());
|
||||
}
|
||||
List<Block> blocks = new ArrayList<>();
|
||||
for (int i = 0; i < allImages; i++) {
|
||||
ResourceMap resourceMap = imgTips.get(i);
|
||||
Resource tipResource = resourceMap.get(CommonConstant.IMAGE_TIP_ICON);
|
||||
Resource clickResource = resourceMap.get(CommonConstant.IMAGE_CLICK_ICON);
|
||||
if (clickResource == null) {
|
||||
throw new IllegalStateException("随机生成点击图片失败,资源中必须包含[" + CommonConstant.IMAGE_CLICK_ICON + "]" + resourceMap);
|
||||
}
|
||||
if (tipResource == null) {
|
||||
tipResource = clickResource;
|
||||
}
|
||||
|
||||
// 随机获取点击图片
|
||||
ImgWrapper imgWrapper = getClickImg(imgTips.get(i),null);
|
||||
ClickImageCheckDefinition.ImgWrapper imgWrapper = getClickImg(param, clickResource, null);
|
||||
BufferedImage image = imgWrapper.getImage();
|
||||
// 增加功能,是否需要扭曲图片
|
||||
image = obfuscateImage(image, param);
|
||||
int clickImgWidth = image.getWidth();
|
||||
int clickImgHeight = image.getHeight();
|
||||
// 随机x
|
||||
int randomX;
|
||||
if (i == 0) {
|
||||
randomX = 1;
|
||||
} else {
|
||||
randomX = avg * i;
|
||||
// 假设每个icon的大小都是一样的, 按照宽高进行分块
|
||||
int w = clickImgWidth + clickImgWidth / 2;
|
||||
int h = clickImgHeight + clickImgHeight / 2;
|
||||
int xNum = (int) Math.floor((double) bgImage.getWidth() / w);
|
||||
int yNum = (int) Math.floor((double) bgImage.getHeight() / h);
|
||||
for (int x = 0; x < xNum; x++) {
|
||||
for (int y = 0; y < yNum; y++) {
|
||||
blocks.add(new Block(x * w + clickImgWidth / 2, clickImgWidth, y * h + clickImgHeight / 2, clickImgHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 随机y
|
||||
int randomY = randomInt(10, bgImage.getHeight() - clickImgHeight);
|
||||
// 通过随机x和y 进行覆盖图片
|
||||
CaptchaImageUtils.overlayImage(bgImage, image, randomX, randomY);
|
||||
Block block = blocks.remove(ThreadLocalRandom.current().nextInt(0, blocks.size()));
|
||||
// // 随机x
|
||||
// int randomX;
|
||||
// if (i == 0) {
|
||||
// randomX = 1;
|
||||
// } else {
|
||||
// randomX = avg * i;
|
||||
// }
|
||||
// // 随机y
|
||||
// int randomY = randomInt(10, bgImage.getHeight() - clickImgHeight);
|
||||
// 通过随机x和y 进行覆盖图片7
|
||||
CaptchaImageUtils.overlayImage(bgImage, image, block.startX, block.startY);
|
||||
ClickImageCheckDefinition clickImageCheckDefinition = new ClickImageCheckDefinition();
|
||||
clickImageCheckDefinition.setTip(imgWrapper.getTip());
|
||||
clickImageCheckDefinition.setX(randomX + clickImgWidth / 2);
|
||||
clickImageCheckDefinition.setY(randomY + clickImgHeight / 2);
|
||||
clickImageCheckDefinition.setTip(tipResource);
|
||||
clickImageCheckDefinition.setTipImage(imgWrapper);
|
||||
clickImageCheckDefinition.setX(block.startX + clickImgWidth / 2);
|
||||
clickImageCheckDefinition.setY(block.startY + clickImgHeight / 2);
|
||||
clickImageCheckDefinition.setWidth(clickImgWidth);
|
||||
clickImageCheckDefinition.setHeight(clickImgHeight);
|
||||
clickImageCheckDefinition.setImageColor(imgWrapper.getImageColor());
|
||||
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||
}
|
||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = filterAndSortClickImageCheckDefinition(captchaExchange,clickImageCheckDefinitionList);
|
||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = filterAndSortClickImageCheckDefinition(captchaExchange, clickImageCheckDefinitionList);
|
||||
captchaExchange.setBackgroundImage(bgImage);
|
||||
captchaExchange.setTransferData(checkClickImageCheckDefinitionList);
|
||||
captchaExchange.setResourceImage(resourceImage);
|
||||
@@ -88,20 +118,24 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
||||
|
||||
}
|
||||
|
||||
private BufferedImage obfuscateImage(BufferedImage image, GenerateParam param) {
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤并排序校验的图片点选顺序
|
||||
*
|
||||
* @param allCheckDefinitionList 总的点选图片
|
||||
* @return List<ClickImageCheckDefinition>
|
||||
*/
|
||||
protected abstract List<ClickImageCheckDefinition> filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange,List<ClickImageCheckDefinition> allCheckDefinitionList);
|
||||
protected abstract List<ClickImageCheckDefinition> filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange, List<ClickImageCheckDefinition> allCheckDefinitionList);
|
||||
|
||||
/**
|
||||
* 随机获取一组数据用于生成随机图
|
||||
*
|
||||
* @return List<String>
|
||||
*/
|
||||
protected abstract List<Resource> randomGetClickImgTips(GenerateParam param);
|
||||
protected abstract List<ResourceMap> randomGetClickImgTips(GenerateParam param);
|
||||
|
||||
/**
|
||||
* 随机获取点击的图片
|
||||
@@ -109,22 +143,16 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
||||
* @param tip 提示数据,根据改数据生成图片
|
||||
* @return ImgWrapper
|
||||
*/
|
||||
public abstract ImgWrapper getClickImg(Resource tip, Color randomColor);
|
||||
public abstract ClickImageCheckDefinition.ImgWrapper getClickImg(GenerateParam param, Resource tip, Color randomColor);
|
||||
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/28 14:26
|
||||
* @Description 点击图片包装
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ImgWrapper {
|
||||
/** 图片. */
|
||||
private BufferedImage image;
|
||||
/** 提示. */
|
||||
private Resource tip;
|
||||
/** 图片颜色. */
|
||||
private Color imageColor;
|
||||
private static class Block {
|
||||
private int startX;
|
||||
private int width;
|
||||
private int startY;
|
||||
private int height;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-13
@@ -12,6 +12,7 @@ import cloud.tianai.captcha.interceptor.CaptchaInterceptor;
|
||||
import cloud.tianai.captcha.resource.FontCache;
|
||||
import cloud.tianai.captcha.resource.ImageCaptchaResourceManager;
|
||||
import cloud.tianai.captcha.resource.common.model.dto.Resource;
|
||||
import cloud.tianai.captcha.resource.common.model.dto.ResourceMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -77,15 +78,18 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
|
||||
|
||||
@Override
|
||||
protected List<Resource> randomGetClickImgTips(GenerateParam param) {
|
||||
protected List<ResourceMap> randomGetClickImgTips(GenerateParam param) {
|
||||
Integer checkClickCount = param.getOrDefault(ParamKeyEnum.CLICK_CHECK_CLICK_COUNT, getCheckClickCount());
|
||||
Integer interferenceCount = param.getOrDefault(ParamKeyEnum.CLICK_INTERFERENCE_COUNT, getInterferenceCount());
|
||||
int tipSize = interferenceCount + checkClickCount;
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
List<Resource> tipList = new ArrayList<>(tipSize);
|
||||
List<ResourceMap> tipList = new ArrayList<>(tipSize);
|
||||
for (int i = 0; i < tipSize; i++) {
|
||||
String randomWord = FontUtils.getRandomChar(random);
|
||||
tipList.add(new Resource(null, randomWord));
|
||||
ResourceMap resourceMap = new ResourceMap(param.getTemplateImageTag());
|
||||
resourceMap.put(CommonConstant.IMAGE_TIP_ICON, new Resource(null, randomWord));
|
||||
resourceMap.put(CommonConstant.IMAGE_CLICK_ICON, new Resource(null, randomWord));
|
||||
tipList.add(resourceMap);
|
||||
}
|
||||
// 随机文字
|
||||
return tipList;
|
||||
@@ -101,8 +105,9 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
// resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg"), DEFAULT_TAG));
|
||||
}
|
||||
|
||||
public FontWrapper randomFont() {
|
||||
Resource resource = requiredRandomGetResource(FontCache.FONT_TYPE, CommonConstant.DEFAULT_TAG);
|
||||
public FontWrapper randomFont(GenerateParam param) {
|
||||
String fontTag = param.getOrDefault(ParamKeyEnum.FONT_TAG, CommonConstant.DEFAULT_TAG);
|
||||
Resource resource = requiredRandomGetResource(FontCache.FONT_TYPE, fontTag);
|
||||
Object extra = resource.getExtra();
|
||||
if (extra instanceof FontWrapper) {
|
||||
return (FontWrapper) extra;
|
||||
@@ -110,8 +115,8 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
throw new ImageCaptchaException("随机获取字体失败, resource中没有读到字体包, resource=" + resource);
|
||||
}
|
||||
|
||||
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
|
||||
FontWrapper fontWrapper = randomFont();
|
||||
public ClickImageCheckDefinition.ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions, GenerateParam param) {
|
||||
FontWrapper fontWrapper = randomFont(param);
|
||||
Font font = fontWrapper.getFont();
|
||||
float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef();
|
||||
String tips = imageCheckDefinitions.stream().map(c -> c.getTip().getData()).collect(Collectors.joining());
|
||||
@@ -123,7 +128,7 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
float top = 6 / 2f + font.getSize() - currentFontTopCoef;
|
||||
BufferedImage bufferedImage = CaptchaImageUtils.genSimpleImgCaptcha(tips,
|
||||
font, width, height, left, top, tipImageInterferenceLineNum, tipImageInterferencePointNum);
|
||||
return new ImgWrapper(bufferedImage, new Resource(null, tips), null);
|
||||
return new ClickImageCheckDefinition.ImgWrapper(bufferedImage, new Resource(null, tips), null);
|
||||
}
|
||||
|
||||
// @Override
|
||||
@@ -136,14 +141,14 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
|
||||
|
||||
@Override
|
||||
public ImgWrapper getClickImg(Resource tip, Color randomColor) {
|
||||
public ClickImageCheckDefinition.ImgWrapper getClickImg(GenerateParam param, Resource tip, Color randomColor) {
|
||||
if (randomColor == null) {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
randomColor = CaptchaImageUtils.getRandomColor(random);
|
||||
}
|
||||
// 随机角度
|
||||
int randomDeg = randomInt(0, 85);
|
||||
FontWrapper fontWrapper = randomFont();
|
||||
FontWrapper fontWrapper = randomFont(param);
|
||||
Font font = fontWrapper.getFont();
|
||||
float currentFontTopCoef = fontWrapper.getCurrentFontTopCoef();
|
||||
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
|
||||
@@ -153,11 +158,11 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
clickImgWidth,
|
||||
clickImgHeight,
|
||||
randomDeg);
|
||||
return new ImgWrapper(fontImage, tip, randomColor);
|
||||
return new ClickImageCheckDefinition.ImgWrapper(fontImage, tip, randomColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ClickImageCheckDefinition> filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange,List<ClickImageCheckDefinition> allCheckDefinitionList) {
|
||||
protected List<ClickImageCheckDefinition> filterAndSortClickImageCheckDefinition(CaptchaExchange captchaExchange, List<ClickImageCheckDefinition> allCheckDefinitionList) {
|
||||
GenerateParam param = captchaExchange.getParam();
|
||||
Integer checkClickCount = param.getOrDefault(ParamKeyEnum.CLICK_CHECK_CLICK_COUNT, getCheckClickCount());
|
||||
// 打乱
|
||||
@@ -179,7 +184,7 @@ public class StandardWordClickImageCaptchaGenerator extends AbstractClickImageCa
|
||||
Resource resourceImage = captchaExchange.getResourceImage();
|
||||
CustomData data = captchaExchange.getCustomData();
|
||||
// 提示图片
|
||||
BufferedImage tipImage = genTipImage(checkClickImageCheckDefinitionList).getImage();
|
||||
BufferedImage tipImage = genTipImage(checkClickImageCheckDefinitionList, param).getImage();
|
||||
ImageTransformData transform = getImageTransform().transform(param, bgImage, tipImage, resourceImage, checkClickImageCheckDefinitionList, data);
|
||||
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
||||
clickImageCaptchaInfo.setBackgroundImage(transform.getBackgroundImageUrl());
|
||||
|
||||
+2
-2
@@ -35,8 +35,8 @@ public class BasicTrackCaptchaInterceptor implements CaptchaInterceptor {
|
||||
}
|
||||
ImageCaptchaTrack imageCaptchaTrack = matchData.getTrack();
|
||||
// 进行行为轨迹检测
|
||||
long startSlidingTime = imageCaptchaTrack.getStartTime().getTime();
|
||||
long endSlidingTime = imageCaptchaTrack.getStopTime().getTime();
|
||||
long startSlidingTime = imageCaptchaTrack.getStartTime();
|
||||
long endSlidingTime = imageCaptchaTrack.getStopTime();
|
||||
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
|
||||
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||
// 这里只进行基本检测, 用一些简单算法进行校验,如有需要可扩展
|
||||
|
||||
@@ -69,7 +69,7 @@ public class DefaultBuiltInResources {
|
||||
|
||||
// 字体包
|
||||
defaultTemplateResource.put(FontCache.FONT_TYPE, resourceStore -> {
|
||||
resourceStore.addResource(FontCache.FONT_TYPE,new Resource(type, finalPathPrefix.concat("/fontS/SIMSUN.TTC")));
|
||||
resourceStore.addResource(FontCache.FONT_TYPE,new Resource(type, finalPathPrefix.concat("/fonts/SIMSUN.TTC")));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -77,4 +77,9 @@ public class FontCache implements ResourceStore {
|
||||
public List<ResourceMap> randomGetTemplateByTypeAndTag(String type, String tag, Integer quantity) {
|
||||
return resourceStore.randomGetTemplateByTypeAndTag(type, tag, quantity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceStore getTarget() {
|
||||
return resourceStore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,4 +29,8 @@ public interface ResourceStore {
|
||||
* @return Map<String, Resource>
|
||||
*/
|
||||
List<ResourceMap> randomGetTemplateByTypeAndTag(String type, String tag,Integer quantity);
|
||||
|
||||
default ResourceStore getTarget() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -5,7 +5,6 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -25,9 +24,9 @@ public class ImageCaptchaTrack {
|
||||
/** 模板图片高度. */
|
||||
private Integer templateImageHeight;
|
||||
/** 滑动开始时间. */
|
||||
private Date startTime;
|
||||
private Long startTime;
|
||||
/** 滑动结束时间. */
|
||||
private Date stopTime;
|
||||
private Long stopTime;
|
||||
private Integer left;
|
||||
private Integer top;
|
||||
/** 滑动的轨迹. */
|
||||
|
||||
@@ -42,8 +42,8 @@ public class BasicCaptchaTrackValidator extends SimpleImageCaptchaValidator {
|
||||
return ApiResponse.ofSuccess();
|
||||
}
|
||||
// 进行行为轨迹检测
|
||||
long startSlidingTime = imageCaptchaTrack.getStartTime().getTime();
|
||||
long endSlidingTime = imageCaptchaTrack.getStopTime().getTime();
|
||||
long startSlidingTime = imageCaptchaTrack.getStartTime();
|
||||
long endSlidingTime = imageCaptchaTrack.getStopTime();
|
||||
Integer bgImageWidth = imageCaptchaTrack.getBgImageWidth();
|
||||
List<ImageCaptchaTrack.Track> trackList = imageCaptchaTrack.getTrackList();
|
||||
// 这里只进行基本检测, 用一些简单算法进行校验,如有需要可扩展
|
||||
|
||||
@@ -26,7 +26,7 @@ public class TACBuilderTest2 {
|
||||
.addResource("WORD_IMAGE_CLICK", new Resource("classpath", "META-INF/cut-image/resource/1.jpg"))
|
||||
.addResource("ROTATE", new Resource("classpath", "META-INF/cut-image/resource/1.jpg"))
|
||||
.build();
|
||||
ApiResponse<ImageCaptchaVO> response = application.generateCaptcha("WORD_IMAGE_CLICK");
|
||||
ApiResponse<ImageCaptchaVO> response = application.generateCaptcha("SLIDER");
|
||||
System.out.println(response);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user