mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
U 修改资源读取和存储模块
升级版本为1.2
This commit is contained in:
+29
-56
@@ -3,9 +3,6 @@ package cloud.tianai.captcha.template.slider;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
@@ -25,12 +22,23 @@ public class CacheSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
private AtomicInteger pos = new AtomicInteger(0);
|
||||
private SliderCaptchaTemplate target;
|
||||
private int size;
|
||||
/** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */
|
||||
private int waitTime = 1000;
|
||||
/** 调度器检查缓存的间隔时间. */
|
||||
private int period = 100;
|
||||
|
||||
public CacheSliderCaptchaTemplate(SliderCaptchaTemplate target, int size) {
|
||||
this.target = target;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public CacheSliderCaptchaTemplate(SliderCaptchaTemplate target, int size, int waitTime, int period) {
|
||||
this.target = target;
|
||||
this.size = size;
|
||||
this.waitTime = waitTime;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记的初始化调度器
|
||||
*/
|
||||
@@ -57,22 +65,26 @@ public class CacheSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
pos.incrementAndGet();
|
||||
}
|
||||
} else {
|
||||
// 休眠500毫秒
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(500);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
sleep();
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// cache所有
|
||||
log.error("缓存队列扫描时出错, ex", e);
|
||||
// 休眠
|
||||
sleep();
|
||||
}
|
||||
}, 0, 100, TimeUnit.MILLISECONDS);
|
||||
}, 0, period, TimeUnit.MILLISECONDS);
|
||||
log.info("缓存滑块验证码调度器初始化完成: size:{}", size);
|
||||
}
|
||||
|
||||
private void sleep() {
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(waitTime);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public SliderCaptchaInfo getSlideImageInfo() {
|
||||
@@ -88,60 +100,21 @@ public class CacheSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResource(URL url) {
|
||||
target.addResource(url);
|
||||
public SliderCaptchaInfo getSlideImageInfo(String targetFormatName, String matrixFormatName) {
|
||||
return target.getSlideImageInfo(targetFormatName, matrixFormatName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTemplate(Map<String, URL> template) {
|
||||
target.addTemplate(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(List<URL> resources) {
|
||||
target.setResource(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemplates(List<Map<String, URL>> imageTemplates) {
|
||||
target.setTemplates(imageTemplates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteResource(URL resource) {
|
||||
target.deleteResource(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> listResources() {
|
||||
return target.listResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearResources() {
|
||||
target.clearResources();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTemplate(Map<String, URL> template) {
|
||||
target.deleteTemplate(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, URL>> listTemplates() {
|
||||
return target.listTemplates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTemplates() {
|
||||
target.clearTemplates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean percentageContrast(Float newPercentage, Float oriPercentage) {
|
||||
return target.percentageContrast(newPercentage, oriPercentage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||
return target.getSlideImageResourceManager();
|
||||
}
|
||||
|
||||
|
||||
// public static void main(String[] args) throws InterruptedException {
|
||||
// SliderCaptchaTemplate captchaTemplate = new DefaultSliderCaptchaTemplate("jpeg", "png", true);
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 15:43
|
||||
* @Description 默认的资源存储
|
||||
*/
|
||||
public class DefaultResourceStore implements ResourceStore {
|
||||
/**
|
||||
* 模板资源.
|
||||
*/
|
||||
private List<Map<String, Resource>> templateResourceList = new ArrayList<>(2);
|
||||
|
||||
/**
|
||||
* resource.
|
||||
*/
|
||||
private List<Resource> resourceList = new ArrayList<>(20);
|
||||
|
||||
@Override
|
||||
public void addResource(Resource resource) {
|
||||
resourceList.add(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(List<Resource> resources) {
|
||||
resourceList = new ArrayList<>(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteResource(Resource resource) {
|
||||
return resourceList.remove(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearResources() {
|
||||
resourceList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTemplate(Map<String, Resource> template) {
|
||||
templateResourceList.add(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemplates(List<Map<String, Resource>> templateResource) {
|
||||
templateResourceList = new ArrayList<>(templateResource);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Resource> getTemplateByIndex(int index) {
|
||||
if (index < 0 || index > templateResourceList.size() - 1) {
|
||||
throw new IllegalArgumentException("错误的index");
|
||||
}
|
||||
return templateResourceList.get(index);
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.provider.ClassPathResourceProvider;
|
||||
import cloud.tianai.captcha.template.slider.provider.URLResourceProvider;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 15:35
|
||||
* @Description 默认的滑块验证码资源管理
|
||||
*/
|
||||
public class DefaultSliderCaptchaResourceManager implements SliderCaptchaResourceManager {
|
||||
|
||||
private ResourceStore resourceStore;
|
||||
|
||||
private List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
|
||||
|
||||
|
||||
public DefaultSliderCaptchaResourceManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
public DefaultSliderCaptchaResourceManager(ResourceStore resourceStore) {
|
||||
this.resourceStore = resourceStore;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (this.resourceStore == null) {
|
||||
this.resourceStore = new DefaultResourceStore();
|
||||
}
|
||||
// 注入一些默认的提供者
|
||||
registerResourceProvider(new URLResourceProvider());
|
||||
registerResourceProvider(new ClassPathResourceProvider());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Resource> randomGetTemplate() {
|
||||
int count = resourceStore.getTemplateCount();
|
||||
if (count < 1) {
|
||||
throw new IllegalStateException("随机获取模板错误,store中模板为空");
|
||||
}
|
||||
if (count == 1) {
|
||||
return resourceStore.getTemplateByIndex(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
||||
return resourceStore.getTemplateByIndex(randomIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource randomGetResource() {
|
||||
int count = resourceStore.getResourceCount();
|
||||
if (count < 1) {
|
||||
throw new IllegalStateException("随机获取资源错误,store中资源为空");
|
||||
}
|
||||
if (count == 1) {
|
||||
return resourceStore.getResourceByIndex(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
||||
return resourceStore.getResourceByIndex(randomIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceInputStream(Resource resource) {
|
||||
for (ResourceProvider resourceProvider : resourceProviderList) {
|
||||
if (resourceProvider.supported(resource.getType())) {
|
||||
return resourceProvider.getResourceInputStream(resource);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("没有找到Resource [" + resource.getType() + "]对应的资源提供者");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResourceProvider> listResourceProviders() {
|
||||
return Collections.unmodifiableList(resourceProviderList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerResourceProvider(ResourceProvider resourceProvider) {
|
||||
deleteResourceProviderByName(resourceProvider.getName());
|
||||
resourceProviderList.add(resourceProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteResourceProviderByName(String name) {
|
||||
return resourceProviderList.removeIf(r -> r.getName().equals(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceStore(ResourceStore resourceStore) {
|
||||
this.resourceStore = resourceStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceStore getResourceStore() {
|
||||
return resourceStore;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+61
-150
@@ -1,5 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.provider.ClassPathResourceProvider;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@@ -11,9 +12,12 @@ import java.awt.image.ColorModel;
|
||||
import java.awt.image.PixelGrabber;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
@@ -33,132 +37,38 @@ public class DefaultSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
*/
|
||||
public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template";
|
||||
|
||||
public static final String ACTIVE_IMAGE_NAME = "active.png";
|
||||
public static final String FIXED_IMAGE_NAME = "fixed.png";
|
||||
public static final String MATRIX_IMAGE_NAME = "matrix.png";
|
||||
|
||||
/**
|
||||
* resource图片.
|
||||
*/
|
||||
private List<URL> resourceImageFiles = new ArrayList<>(20);
|
||||
/**
|
||||
* 模板图片.
|
||||
*/
|
||||
private List<Map<String, URL>> templateImageFiles = new ArrayList<>(2);
|
||||
private final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
||||
|
||||
protected String targetFormatName = "jpeg";
|
||||
protected String matrixFormatName = "png";
|
||||
|
||||
public void initDefaultResource() {
|
||||
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
||||
// 添加一些系统的资源文件
|
||||
addResource(getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
resourceStore.addResource(new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
|
||||
// 添加一些系统的 模板文件
|
||||
Map<String, URL> template1 = new HashMap<>(4);
|
||||
template1.put(ACTIVE_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));
|
||||
template1.put(FIXED_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));
|
||||
template1.put(MATRIX_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/matrix.png")));
|
||||
addTemplate(template1);
|
||||
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_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")));
|
||||
resourceStore.addTemplate(template1);
|
||||
|
||||
|
||||
Map<String, URL> template2 = new HashMap<>(4);
|
||||
template2.put(ACTIVE_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));
|
||||
template2.put(FIXED_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));
|
||||
template2.put(MATRIX_IMAGE_NAME, getClassLoader().getResource(DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/matrix.png")));
|
||||
addTemplate(template2);
|
||||
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_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")));
|
||||
resourceStore.addTemplate(template2);
|
||||
|
||||
}
|
||||
|
||||
public DefaultSliderCaptchaTemplate(boolean initDefaultResource) {
|
||||
// 加载系统资源文件
|
||||
public DefaultSliderCaptchaTemplate(SliderCaptchaResourceManager sliderCaptchaResourceManager, boolean initDefaultResource) {
|
||||
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultSliderCaptchaTemplate(String targetFormatName, String matrixFormatName, boolean initDefaultResource) {
|
||||
this.targetFormatName = targetFormatName;
|
||||
this.matrixFormatName = matrixFormatName;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultSliderCaptchaTemplate(String targetFormatName,
|
||||
String matrixFormatName,
|
||||
List<URL> r,
|
||||
List<Map<String, URL>> t,
|
||||
boolean initDefaultResource) {
|
||||
this.targetFormatName = targetFormatName;
|
||||
this.matrixFormatName = matrixFormatName;
|
||||
resourceImageFiles = r;
|
||||
templateImageFiles = t;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public DefaultSliderCaptchaTemplate(List<URL> r, List<Map<String, URL>> t, boolean initDefaultResource) {
|
||||
resourceImageFiles = r;
|
||||
templateImageFiles = t;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addResource(URL url) {
|
||||
resourceImageFiles.remove(url);
|
||||
resourceImageFiles.add(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(List<URL> resources) {
|
||||
resourceImageFiles = resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemplates(List<Map<String, URL>> imageTemplates) {
|
||||
templateImageFiles = imageTemplates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteResource(URL resource) {
|
||||
resourceImageFiles.remove(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> listResources() {
|
||||
return Collections.unmodifiableList(resourceImageFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearResources() {
|
||||
resourceImageFiles.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTemplate(Map<String, URL> template) {
|
||||
templateImageFiles.remove(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, URL>> listTemplates() {
|
||||
return Collections.unmodifiableList(templateImageFiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTemplates() {
|
||||
templateImageFiles.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTemplate(Map<String, URL> template) {
|
||||
templateImageFiles.remove(template);
|
||||
templateImageFiles.add(template);
|
||||
}
|
||||
|
||||
private static ClassLoader getClassLoader() {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
@@ -173,27 +83,26 @@ public class DefaultSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
|
||||
@Override
|
||||
public SliderCaptchaInfo getSlideImageInfo() {
|
||||
return getSlideImageInfo(this.targetFormatName, this.matrixFormatName);
|
||||
return getSlideImageInfo("jpeg", "png");
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public SliderCaptchaInfo getSlideImageInfo(String targetFormatName, String matrixFormatName) {
|
||||
if (resourceImageFiles.isEmpty() || templateImageFiles.isEmpty()) {
|
||||
log.warn("滑块验证码生成失败, 资源或模板为空,不能进行生成, 资源文件列表长度: {}, 模板文件列表长度: {}",
|
||||
resourceImageFiles.size(), templateImageFiles.size());
|
||||
return null;
|
||||
}
|
||||
URL resourceImage = getRandomResourceImage();
|
||||
Map<String, URL> templateImages = getRandomTemplateImages();
|
||||
|
||||
BufferedImage cutBackground = warpFile2BufferedImage(resourceImage);
|
||||
|
||||
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate();
|
||||
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource();
|
||||
|
||||
|
||||
BufferedImage cutBackground = warpFile2BufferedImage(sliderCaptchaResourceManager.getResourceInputStream(resourceImage));
|
||||
// 拷贝一份图片
|
||||
BufferedImage targetBackground = deepCopyBufferedImage(cutBackground);
|
||||
|
||||
BufferedImage fixedTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, FIXED_IMAGE_NAME));
|
||||
BufferedImage activeTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, ACTIVE_IMAGE_NAME));
|
||||
BufferedImage matrixTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, MATRIX_IMAGE_NAME));
|
||||
BufferedImage fixedTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME));
|
||||
BufferedImage activeTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME));
|
||||
BufferedImage matrixTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME));
|
||||
// BufferedImage cutTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, CUT_IMAGE_NAME));
|
||||
|
||||
// 获取随机的 x 和 y 轴
|
||||
@@ -233,6 +142,11 @@ public class DefaultSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
return newPercentage >= minTolerant && newPercentage <= maxTolerant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||
return sliderCaptchaResourceManager;
|
||||
}
|
||||
|
||||
|
||||
private String transformBase64(BufferedImage bufferedImage, String formatName) {
|
||||
byte[] data = null;
|
||||
@@ -383,21 +297,14 @@ public class DefaultSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
private URL getTemplateFile(Map<String, URL> templateImages, String imageName) {
|
||||
URL url = templateImages.get(imageName);
|
||||
if (url == null) {
|
||||
private InputStream getTemplateFile(Map<String, Resource> templateImages, String imageName) {
|
||||
Resource resource = templateImages.get(imageName);
|
||||
if (resource == null) {
|
||||
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
|
||||
}
|
||||
return url;
|
||||
return sliderCaptchaResourceManager.getResourceInputStream(resource);
|
||||
}
|
||||
|
||||
private Map<String, URL> getRandomTemplateImages() {
|
||||
if (templateImageFiles.size() == 1) {
|
||||
return templateImageFiles.get(0);
|
||||
}
|
||||
int templateNo = ThreadLocalRandom.current().nextInt(templateImageFiles.size());
|
||||
return templateImageFiles.get(templateNo);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static BufferedImage warpFile2BufferedImage(URL resourceImage) {
|
||||
@@ -407,23 +314,27 @@ public class DefaultSliderCaptchaTemplate implements SliderCaptchaTemplate {
|
||||
return ImageIO.read(resourceImage);
|
||||
}
|
||||
|
||||
private URL getRandomResourceImage() {
|
||||
if (resourceImageFiles.size() == 1) {
|
||||
return resourceImageFiles.get(0);
|
||||
@SneakyThrows
|
||||
private static BufferedImage warpFile2BufferedImage(InputStream resource) {
|
||||
if (resource == null) {
|
||||
throw new IllegalArgumentException("包装文件到 BufferedImage 失败, file不能为空");
|
||||
}
|
||||
int targetNo = ThreadLocalRandom.current().nextInt(resourceImageFiles.size());
|
||||
return resourceImageFiles.get(targetNo);
|
||||
return ImageIO.read(resource);
|
||||
}
|
||||
|
||||
// public static void main(String[] args) throws InterruptedException {
|
||||
// DefaultSliderCaptchaTemplate sliderCaptchaTemplate = new DefaultSliderCaptchaTemplate();
|
||||
// // 生成滑块图片
|
||||
// SliderCaptchaInfo slideImageInfo = sliderCaptchaTemplate.getSlideImageInfo();
|
||||
// // 获取背景图片的base64
|
||||
// String backgroundImage = slideImageInfo.getBackgroundImage();
|
||||
// // 获取滑块图片
|
||||
// slideImageInfo.getSliderImage();
|
||||
// // 获取滑块被背景图片的百分比, (校验图片使用)
|
||||
// Float xPercent = slideImageInfo.getXPercent();
|
||||
// }
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
|
||||
DefaultSliderCaptchaTemplate sliderCaptchaTemplate = new DefaultSliderCaptchaTemplate(sliderCaptchaResourceManager, true);
|
||||
// 生成滑块图片
|
||||
SliderCaptchaInfo slideImageInfo = sliderCaptchaTemplate.getSlideImageInfo();
|
||||
// 获取背景图片的base64
|
||||
String backgroundImage = slideImageInfo.getBackgroundImage();
|
||||
// 获取滑块图片
|
||||
slideImageInfo.getSliderImage();
|
||||
// 获取滑块被背景图片的百分比, (校验图片使用)
|
||||
Float xPercent = slideImageInfo.getXPercent();
|
||||
|
||||
System.out.println(slideImageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 15:15
|
||||
* @Description 资源对象
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class Resource {
|
||||
/** 类型. */
|
||||
private String type;
|
||||
/** 数据,传输给 {@link ResourceProvider} 的参数 */
|
||||
public String data;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 15:07
|
||||
* @Description 资源提供者
|
||||
*/
|
||||
public interface ResourceProvider {
|
||||
|
||||
/**
|
||||
* 获取资源
|
||||
*
|
||||
* @param data data
|
||||
* @return InputStream
|
||||
*/
|
||||
InputStream getResourceInputStream(Resource data);
|
||||
|
||||
/**
|
||||
* 是否支持
|
||||
*
|
||||
* @param type type
|
||||
* @return boolean
|
||||
*/
|
||||
boolean supported(String type);
|
||||
|
||||
/**
|
||||
* 放弃资源提供者名称
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ResourceStore {
|
||||
|
||||
/**
|
||||
* 添加资源
|
||||
*
|
||||
* @param resource 资源
|
||||
*/
|
||||
void addResource(Resource resource);
|
||||
|
||||
/**
|
||||
* 设置资源
|
||||
*
|
||||
* @param resources resources
|
||||
*/
|
||||
void setResource(List<Resource> resources);
|
||||
|
||||
/**
|
||||
* 删除资源
|
||||
*
|
||||
* @param resource resource
|
||||
*/
|
||||
boolean deleteResource(Resource resource);
|
||||
|
||||
/**
|
||||
* 清除所有资源
|
||||
*/
|
||||
void clearResources();
|
||||
|
||||
/**
|
||||
* 添加模板
|
||||
*
|
||||
* @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>
|
||||
*/
|
||||
List<Resource> listResources();
|
||||
|
||||
/**
|
||||
* 获取所有模板
|
||||
*
|
||||
* @return List<Map < String, Resource>>
|
||||
*/
|
||||
List<Map<String, Resource>> listTemplates();
|
||||
|
||||
/**
|
||||
* 获取资源总数
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getResourceCount();
|
||||
|
||||
/**
|
||||
* 获取模板count
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getTemplateCount();
|
||||
|
||||
/**
|
||||
* 获取资源通过index
|
||||
*
|
||||
* @param index index
|
||||
* @return Resource
|
||||
*/
|
||||
Resource getResourceByIndex(int index);
|
||||
|
||||
/**
|
||||
* 获取模板通过indx
|
||||
*
|
||||
* @param index index
|
||||
* @return Map<String, Resource>
|
||||
*/
|
||||
Map<String, Resource> getTemplateByIndex(int index);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 17:14
|
||||
* @Description 滑块验证码常量
|
||||
*/
|
||||
public interface SliderCaptchaConstant {
|
||||
|
||||
/** 模板滑块固定名称. */
|
||||
String TEMPLATE_ACTIVE_IMAGE_NAME = "active.png";
|
||||
/** 模板凹槽固定名称. */
|
||||
String TEMPLATE_FIXED_IMAGE_NAME = "fixed.png";
|
||||
/** 模板背景固定名称. */
|
||||
String TEMPLATE_MATRIX_IMAGE_NAME = "matrix.png";
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cloud.tianai.captcha.template.slider;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 15:26
|
||||
* @Description 滑块验证码图片资源管理器
|
||||
*/
|
||||
public interface SliderCaptchaResourceManager {
|
||||
|
||||
/**
|
||||
* 随机获取某个模板
|
||||
*
|
||||
* @return Map<String, Resource>
|
||||
*/
|
||||
Map<String, Resource> randomGetTemplate();
|
||||
|
||||
/**
|
||||
* 随机获取某个资源对象
|
||||
*
|
||||
* @return Resource
|
||||
*/
|
||||
Resource randomGetResource();
|
||||
|
||||
/**
|
||||
* 获取真正的资源流通过资源对象
|
||||
*
|
||||
* @param resource resource
|
||||
* @return InputStream
|
||||
*/
|
||||
InputStream getResourceInputStream(Resource resource);
|
||||
|
||||
/**
|
||||
* 获取所有资源提供者
|
||||
*
|
||||
* @return List<ResourceProvider>
|
||||
*/
|
||||
List<ResourceProvider> listResourceProviders();
|
||||
|
||||
/**
|
||||
* 注册资源提供者
|
||||
*
|
||||
* @param resourceProvider 资源提供者
|
||||
*/
|
||||
void registerResourceProvider(ResourceProvider resourceProvider);
|
||||
|
||||
/**
|
||||
* 删除资源提供者
|
||||
*
|
||||
* @param name 资源提供者名称
|
||||
* @return ResourceProvider
|
||||
*/
|
||||
boolean deleteResourceProviderByName(String name);
|
||||
|
||||
/**
|
||||
* 设置资源存储
|
||||
*
|
||||
* @param resourceStore resourceStore
|
||||
*/
|
||||
void setResourceStore(ResourceStore resourceStore);
|
||||
|
||||
/**
|
||||
* 获取资源存储
|
||||
*
|
||||
* @return ResourceStore
|
||||
*/
|
||||
ResourceStore getResourceStore();
|
||||
}
|
||||
@@ -5,7 +5,7 @@ package cloud.tianai.captcha.template.slider;
|
||||
* @date 2020/10/19 18:37
|
||||
* @Description 滑块验证码模板
|
||||
*/
|
||||
public interface SliderCaptchaTemplate extends SliderCaptchaResource {
|
||||
public interface SliderCaptchaTemplate {
|
||||
|
||||
/**
|
||||
* 获取滑块验证码
|
||||
@@ -14,6 +14,16 @@ public interface SliderCaptchaTemplate extends SliderCaptchaResource {
|
||||
*/
|
||||
SliderCaptchaInfo getSlideImageInfo();
|
||||
|
||||
|
||||
/**
|
||||
* 获取滑块验证码
|
||||
*
|
||||
* @param targetFormatName jpeg或者webp格式
|
||||
* @param matrixFormatName png或者webp格式
|
||||
* @return SliderCaptchaInfo
|
||||
*/
|
||||
SliderCaptchaInfo getSlideImageInfo(String targetFormatName, String matrixFormatName);
|
||||
|
||||
/**
|
||||
* 百分比对比
|
||||
*
|
||||
@@ -22,4 +32,12 @@ public interface SliderCaptchaTemplate extends SliderCaptchaResource {
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
boolean percentageContrast(Float newPercentage, Float oriPercentage);
|
||||
|
||||
/**
|
||||
* 获取滑块验证码资源管理器
|
||||
*
|
||||
* @return SliderCaptchaResourceManager
|
||||
*/
|
||||
SliderCaptchaResourceManager getSlideImageResourceManager();
|
||||
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package cloud.tianai.captcha.template.slider.provider;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.Resource;
|
||||
import cloud.tianai.captcha.template.slider.ResourceProvider;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 16:07
|
||||
* @Description classPath
|
||||
*/
|
||||
public class ClassPathResourceProvider implements ResourceProvider {
|
||||
|
||||
public static final String NAME = "classpath";
|
||||
|
||||
@Override
|
||||
public InputStream getResourceInputStream(Resource data) {
|
||||
return getClassLoader().getResourceAsStream(data.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supported(String type) {
|
||||
return NAME.equalsIgnoreCase(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
private static ClassLoader getClassLoader() {
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassPathResourceProvider.getClassLoader();
|
||||
}
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cloud.tianai.captcha.template.slider.provider;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.Resource;
|
||||
import cloud.tianai.captcha.template.slider.ResourceProvider;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 16:05
|
||||
* @Description url
|
||||
*/
|
||||
public class URLResourceProvider implements ResourceProvider {
|
||||
|
||||
public static final String NAME = "URL";
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public InputStream getResourceInputStream(Resource data) {
|
||||
URL url = new URL(data.getData());
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supported(String type) {
|
||||
return NAME.equalsIgnoreCase(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user