@ -1,14 +0,0 @@
|
|||||||
package com.anji.captcha.config;
|
|
||||||
|
|
||||||
import com.anji.captcha.properties.AjCaptchaProperties;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableConfigurationProperties(AjCaptchaProperties.class)
|
|
||||||
@ComponentScan("com.anji.captcha")
|
|
||||||
@Import({AjCaptchaServiceAutoConfiguration.class, AjCaptchaStorageAutoConfiguration.class})
|
|
||||||
public class AjCaptchaAutoConfiguration {
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
package com.anji.captcha.config;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.anji.captcha.model.common.Const;
|
|
||||||
import com.anji.captcha.properties.AjCaptchaProperties;
|
|
||||||
import com.anji.captcha.service.CaptchaService;
|
|
||||||
import com.anji.captcha.service.impl.CaptchaServiceFactory;
|
|
||||||
import com.anji.captcha.util.ImageUtils;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.util.Base64Utils;
|
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Configuration
|
|
||||||
public class AjCaptchaServiceAutoConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public CaptchaService captchaService(AjCaptchaProperties prop) {
|
|
||||||
log.info("自定义配置项:{}", prop.toString());
|
|
||||||
Properties config = new Properties();
|
|
||||||
config.put(Const.CAPTCHA_CACHETYPE, prop.getCacheType().name());
|
|
||||||
config.put(Const.CAPTCHA_WATER_MARK, prop.getWaterMark());
|
|
||||||
config.put(Const.CAPTCHA_FONT_TYPE, prop.getFontType());
|
|
||||||
config.put(Const.CAPTCHA_TYPE, prop.getType().getCodeValue());
|
|
||||||
config.put(Const.CAPTCHA_INTERFERENCE_OPTIONS, prop.getInterferenceOptions());
|
|
||||||
config.put(Const.ORIGINAL_PATH_JIGSAW, prop.getJigsaw());
|
|
||||||
config.put(Const.ORIGINAL_PATH_PIC_CLICK, prop.getPicClick());
|
|
||||||
config.put(Const.CAPTCHA_SLIP_OFFSET, prop.getSlipOffset());
|
|
||||||
config.put(Const.CAPTCHA_AES_STATUS, String.valueOf(prop.getAesStatus()));
|
|
||||||
config.put(Const.CAPTCHA_WATER_FONT, prop.getWaterFont());
|
|
||||||
config.put(Const.CAPTCHA_CACAHE_MAX_NUMBER, prop.getCacheNumber());
|
|
||||||
config.put(Const.CAPTCHA_TIMING_CLEAR_SECOND, prop.getTimingClear());
|
|
||||||
|
|
||||||
config.put(Const.HISTORY_DATA_CLEAR_ENABLE, prop.isHistoryDataClearEnable() ? "1" : "0");
|
|
||||||
|
|
||||||
config.put(Const.REQ_FREQUENCY_LIMIT_ENABLE, prop.getReqFrequencyLimitEnable() ? "1" : "0");
|
|
||||||
config.put(Const.REQ_GET_LOCK_LIMIT, prop.getReqGetLockLimit() + "");
|
|
||||||
config.put(Const.REQ_GET_LOCK_SECONDS, prop.getReqGetLockSeconds() + "");
|
|
||||||
config.put(Const.REQ_GET_MINUTE_LIMIT, prop.getReqGetMinuteLimit() + "");
|
|
||||||
config.put(Const.REQ_CHECK_MINUTE_LIMIT, prop.getReqCheckMinuteLimit() + "");
|
|
||||||
config.put(Const.REQ_VALIDATE_MINUTE_LIMIT, prop.getReqVerifyMinuteLimit() + "");
|
|
||||||
|
|
||||||
config.put(Const.CAPTCHA_FONT_SIZE, prop.getFontSize() + "");
|
|
||||||
config.put(Const.CAPTCHA_FONT_STYLE, prop.getFontStyle() + "");
|
|
||||||
config.put(Const.CAPTCHA_WORD_COUNT, prop.getClickWordCount() + "");
|
|
||||||
|
|
||||||
if ((StrUtil.isNotBlank(prop.getJigsaw()) && prop.getJigsaw().startsWith("classpath:"))
|
|
||||||
|| (StrUtil.isNotBlank(prop.getPicClick()) && prop.getPicClick().startsWith("classpath:"))) {
|
|
||||||
//自定义resources目录下初始化底图
|
|
||||||
config.put(Const.CAPTCHA_INIT_ORIGINAL, "true");
|
|
||||||
initializeBaseMap(prop.getJigsaw(), prop.getPicClick());
|
|
||||||
}
|
|
||||||
return CaptchaServiceFactory.getInstance(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void initializeBaseMap(String jigsaw, String picClick) {
|
|
||||||
ImageUtils.cacheBootImage(getResourcesImagesFile(jigsaw + "/original/*.png"),
|
|
||||||
getResourcesImagesFile(jigsaw + "/slidingBlock/*.png"),
|
|
||||||
getResourcesImagesFile(picClick + "/*.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String, String> getResourcesImagesFile(String path) {
|
|
||||||
Map<String, String> imgMap = new HashMap<>();
|
|
||||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
|
||||||
try {
|
|
||||||
Resource[] resources = resolver.getResources(path);
|
|
||||||
for (Resource resource : resources) {
|
|
||||||
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
|
|
||||||
String string = Base64Utils.encodeToString(bytes);
|
|
||||||
String filename = resource.getFilename();
|
|
||||||
imgMap.put(filename, string);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return imgMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
package com.anji.captcha.config;
|
|
||||||
|
|
||||||
import com.anji.captcha.properties.AjCaptchaProperties;
|
|
||||||
import com.anji.captcha.service.CaptchaCacheService;
|
|
||||||
import com.anji.captcha.service.impl.CaptchaServiceFactory;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 存储策略自动配置.
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class AjCaptchaStorageAutoConfiguration {
|
|
||||||
|
|
||||||
@Bean(name = "AjCaptchaCacheService")
|
|
||||||
public CaptchaCacheService captchaCacheService(AjCaptchaProperties ajCaptchaProperties) {
|
|
||||||
// 缓存类型redis/local/....
|
|
||||||
return CaptchaServiceFactory.getCache(ajCaptchaProperties.getCacheType().name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
package com.anji.captcha.model.common;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 底图类型枚举
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum CaptchaBaseMapEnum {
|
|
||||||
ORIGINAL("ORIGINAL", "滑动拼图底图"),
|
|
||||||
SLIDING_BLOCK("SLIDING_BLOCK", "滑动拼图滑块底图"),
|
|
||||||
PIC_CLICK("PIC_CLICK", "文字点选底图");
|
|
||||||
|
|
||||||
private final String codeValue;
|
|
||||||
private final String codeDesc;
|
|
||||||
|
|
||||||
//根据codeValue获取枚举
|
|
||||||
public static CaptchaBaseMapEnum parseFromCodeValue(String codeValue) {
|
|
||||||
for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) {
|
|
||||||
if (e.codeValue.equals(codeValue)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//根据codeValue获取描述
|
|
||||||
public static String getCodeDescByCodeBalue(String codeValue) {
|
|
||||||
CaptchaBaseMapEnum enumItem = parseFromCodeValue(codeValue);
|
|
||||||
return enumItem == null ? "" : enumItem.getCodeDesc();
|
|
||||||
}
|
|
||||||
|
|
||||||
//验证codeValue是否有效
|
|
||||||
public static boolean validateCodeValue(String codeValue) {
|
|
||||||
return parseFromCodeValue(codeValue) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//列出所有值字符串
|
|
||||||
public static String getString() {
|
|
||||||
StringBuffer buffer = new StringBuffer();
|
|
||||||
for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()) {
|
|
||||||
buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
|
|
||||||
}
|
|
||||||
buffer.deleteCharAt(buffer.lastIndexOf(","));
|
|
||||||
return buffer.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
package com.anji.captcha.model.common;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum CaptchaTypeEnum {
|
|
||||||
/**
|
|
||||||
* 滑块拼图.
|
|
||||||
*/
|
|
||||||
BLOCKPUZZLE("blockPuzzle", "滑块拼图"),
|
|
||||||
/**
|
|
||||||
* 文字点选.
|
|
||||||
*/
|
|
||||||
CLICKWORD("clickWord", "文字点选"),
|
|
||||||
/**
|
|
||||||
* 默认.
|
|
||||||
*/
|
|
||||||
DEFAULT("default", "默认");
|
|
||||||
|
|
||||||
private final String codeValue;
|
|
||||||
private final String codeDesc;
|
|
||||||
|
|
||||||
//根据codeValue获取枚举
|
|
||||||
public static CaptchaTypeEnum parseFromCodeValue(String codeValue) {
|
|
||||||
for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) {
|
|
||||||
if (e.codeValue.equals(codeValue)) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//根据codeValue获取描述
|
|
||||||
public static String getCodeDescByCodeBalue(String codeValue) {
|
|
||||||
CaptchaTypeEnum enumItem = parseFromCodeValue(codeValue);
|
|
||||||
return enumItem == null ? "" : enumItem.getCodeDesc();
|
|
||||||
}
|
|
||||||
|
|
||||||
//验证codeValue是否有效
|
|
||||||
public static boolean validateCodeValue(String codeValue) {
|
|
||||||
return parseFromCodeValue(codeValue) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//列出所有值字符串
|
|
||||||
public static String getString() {
|
|
||||||
StringBuilder buffer = new StringBuilder();
|
|
||||||
for (CaptchaTypeEnum e : CaptchaTypeEnum.values()) {
|
|
||||||
buffer.append(e.codeValue).append("--").append(e.getCodeDesc()).append(", ");
|
|
||||||
}
|
|
||||||
buffer.deleteCharAt(buffer.lastIndexOf(","));
|
|
||||||
return buffer.toString().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
*Copyright © 2018 anji-plus
|
|
||||||
*安吉加加信息技术有限公司
|
|
||||||
*http://www.anji-plus.com
|
|
||||||
*All rights reserved.
|
|
||||||
*/
|
|
||||||
package com.anji.captcha.model.common;
|
|
||||||
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class RequestModel implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -5800786065305114784L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前请求接口路径 /business/accessUser/login
|
|
||||||
*/
|
|
||||||
private String servletPath;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {"reqData":{"password":"*****","userName":"admin"},"sign":"a304a7f296f565b6d2009797f68180f0","time":"1542456453355","token":""}
|
|
||||||
*/
|
|
||||||
private String requestString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {"password":"****","userName":"admin"}
|
|
||||||
*/
|
|
||||||
private HashMap reqData;
|
|
||||||
|
|
||||||
private String token;
|
|
||||||
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
private String userName;
|
|
||||||
|
|
||||||
private List<Long> projectList;
|
|
||||||
|
|
||||||
//拥有哪些分组
|
|
||||||
private List<Long> groupIdList;
|
|
||||||
|
|
||||||
private String target;
|
|
||||||
|
|
||||||
private String sign;
|
|
||||||
|
|
||||||
private String time;
|
|
||||||
|
|
||||||
private String sourceIP;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验自身参数合法性
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean isVaildateRequest() {
|
|
||||||
if (StrUtil.isBlank(sign) || StrUtil.isBlank(time)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getServletPath() {
|
|
||||||
return servletPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setServletPath(String servletPath) {
|
|
||||||
this.servletPath = servletPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
*Copyright © 2018 anji-plus
|
|
||||||
*安吉加加信息技术有限公司
|
|
||||||
*http://www.anji-plus.com
|
|
||||||
*All rights reserved.
|
|
||||||
*/
|
|
||||||
package com.anji.captcha.model.common;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ResponseModel implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 8445617032523881407L;
|
|
||||||
|
|
||||||
private String repCode;
|
|
||||||
|
|
||||||
private String repMsg;
|
|
||||||
|
|
||||||
private Object repData;
|
|
||||||
|
|
||||||
public ResponseModel() {
|
|
||||||
this.repCode = RepCodeEnum.SUCCESS.getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseModel(RepCodeEnum repCodeEnum) {
|
|
||||||
this.setRepCodeEnum(repCodeEnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
//成功
|
|
||||||
public static ResponseModel success() {
|
|
||||||
return ResponseModel.successMsg("成功");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseModel successMsg(String message) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepMsg(message);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseModel successData(Object data) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepCode(RepCodeEnum.SUCCESS.getCode());
|
|
||||||
responseModel.setRepData(data);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
//失败
|
|
||||||
public static ResponseModel errorMsg(RepCodeEnum message) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepCodeEnum(message);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseModel errorMsg(String message) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepCode(RepCodeEnum.ERROR.getCode());
|
|
||||||
responseModel.setRepMsg(message);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseModel errorMsg(RepCodeEnum repCodeEnum, String message) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepCode(repCodeEnum.getCode());
|
|
||||||
responseModel.setRepMsg(message);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResponseModel exceptionMsg(String message) {
|
|
||||||
ResponseModel responseModel = new ResponseModel();
|
|
||||||
responseModel.setRepCode(RepCodeEnum.EXCEPTION.getCode());
|
|
||||||
responseModel.setRepMsg(RepCodeEnum.EXCEPTION.getDesc() + ": " + message);
|
|
||||||
return responseModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isSuccess() {
|
|
||||||
return StrUtil.equals(repCode, RepCodeEnum.SUCCESS.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRepCode() {
|
|
||||||
return repCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRepCodeEnum(RepCodeEnum repCodeEnum) {
|
|
||||||
this.repCode = repCodeEnum.getCode();
|
|
||||||
this.repMsg = repCodeEnum.getDesc();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
package com.anji.captcha.model.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by raodeming on 2020/5/16.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class PointVO {
|
|
||||||
private String secretKey;
|
|
||||||
|
|
||||||
public int x;
|
|
||||||
|
|
||||||
public int y;
|
|
||||||
|
|
||||||
public PointVO(int x, int y, String secretKey) {
|
|
||||||
this.secretKey = secretKey;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PointVO() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public PointVO(int x, int y) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toJsonString() {
|
|
||||||
return String.format("{\"secretKey\":\"%s\",\"x\":%d,\"y\":%d}", secretKey, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PointVO parse(String jsonStr) {
|
|
||||||
Map<String, Object> m = new HashMap();
|
|
||||||
Arrays.stream(jsonStr
|
|
||||||
.replaceFirst(",\\{", "\\{")
|
|
||||||
.replaceFirst("\\{", "")
|
|
||||||
.replaceFirst("\\}", "")
|
|
||||||
.replaceAll("\"", "")
|
|
||||||
.split(",")).forEach(item -> {
|
|
||||||
m.put(item.split(":")[0], item.split(":")[1]);
|
|
||||||
});
|
|
||||||
//PointVO d = new PointVO();
|
|
||||||
setX(Double.valueOf("" + m.get("x")).intValue());
|
|
||||||
setY(Double.valueOf("" + m.get("y")).intValue());
|
|
||||||
setSecretKey(m.getOrDefault("secretKey", "") + "");
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (o == null || getClass() != o.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
PointVO pointVO = (PointVO) o;
|
|
||||||
return x == pointVO.x && y == pointVO.y && Objects.equals(secretKey, pointVO.secretKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
|
|
||||||
return Objects.hash(secretKey, x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
*Copyright © 2018 anji-plus
|
|
||||||
*安吉加加信息技术有限公司
|
|
||||||
*http://www.anji-plus.com
|
|
||||||
*All rights reserved.
|
|
||||||
*/
|
|
||||||
package com.anji.captcha.service.impl;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.anji.captcha.model.common.RepCodeEnum;
|
|
||||||
import com.anji.captcha.model.common.ResponseModel;
|
|
||||||
import com.anji.captcha.model.vo.CaptchaVO;
|
|
||||||
import com.anji.captcha.service.CaptchaService;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by raodeming on 2019/12/25.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public class DefaultCaptchaServiceImpl extends AbstractCaptchaService{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String captchaType() {
|
|
||||||
return "default";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Properties config) {
|
|
||||||
for (String s : CaptchaServiceFactory.instances.keySet()) {
|
|
||||||
if(captchaType().equals(s)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
getService(s).init(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy(Properties config) {
|
|
||||||
for (String s : CaptchaServiceFactory.instances.keySet()) {
|
|
||||||
if(captchaType().equals(s)){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
getService(s).destroy(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CaptchaService getService(String captchaType){
|
|
||||||
return CaptchaServiceFactory.instances.get(captchaType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseModel get(CaptchaVO captchaVO) {
|
|
||||||
if (captchaVO == null) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
|
|
||||||
}
|
|
||||||
if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("类型");
|
|
||||||
}
|
|
||||||
return getService(captchaVO.getCaptchaType()).get(captchaVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseModel check(CaptchaVO captchaVO) {
|
|
||||||
if (captchaVO == null) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
|
|
||||||
}
|
|
||||||
if (StrUtil.isEmpty(captchaVO.getCaptchaType())) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("类型");
|
|
||||||
}
|
|
||||||
if (StrUtil.isEmpty(captchaVO.getToken())) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("token");
|
|
||||||
}
|
|
||||||
return getService(captchaVO.getCaptchaType()).check(captchaVO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseModel verification(CaptchaVO captchaVO) {
|
|
||||||
if (captchaVO == null) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("captchaVO");
|
|
||||||
}
|
|
||||||
if (StrUtil.isEmpty(captchaVO.getCaptchaVerification())) {
|
|
||||||
return RepCodeEnum.NULL_ERROR.parseError("二次校验参数");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
|
|
||||||
if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
|
|
||||||
return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
|
|
||||||
}
|
|
||||||
//二次校验取值后,即刻失效
|
|
||||||
CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("验证码坐标解析失败", e);
|
|
||||||
return ResponseModel.errorMsg(e.getMessage());
|
|
||||||
}
|
|
||||||
return ResponseModel.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,120 +0,0 @@
|
|||||||
package com.anji.captcha.util;
|
|
||||||
//
|
|
||||||
// Source code recreated from a .class file by IntelliJ IDEA
|
|
||||||
// (powered by Fernflower decompiler)
|
|
||||||
//
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
|
|
||||||
public abstract class FileCopyUtils {
|
|
||||||
public static final int BUFFER_SIZE = 4096;
|
|
||||||
|
|
||||||
public FileCopyUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int copy(File in, File out) throws IOException {
|
|
||||||
return copy(Files.newInputStream(in.toPath()), Files.newOutputStream(out.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(byte[] in, File out) throws IOException {
|
|
||||||
copy((InputStream) (new ByteArrayInputStream(in)), (OutputStream) Files.newOutputStream(out.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] copyToByteArray(File in) throws IOException {
|
|
||||||
return copyToByteArray(Files.newInputStream(in.toPath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int copy(InputStream in, OutputStream out) throws IOException {
|
|
||||||
int var2;
|
|
||||||
try {
|
|
||||||
var2 = StreamUtils.copy(in, out);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException var12) {
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException var11) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return var2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(byte[] in, OutputStream out) throws IOException {
|
|
||||||
try {
|
|
||||||
out.write(in);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException var8) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] copyToByteArray(InputStream in) throws IOException {
|
|
||||||
if (in == null) {
|
|
||||||
return new byte[0];
|
|
||||||
} else {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
|
|
||||||
copy((InputStream) in, (OutputStream) out);
|
|
||||||
return out.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int copy(Reader in, Writer out) throws IOException {
|
|
||||||
try {
|
|
||||||
int byteCount = 0;
|
|
||||||
char[] buffer = new char[4096];
|
|
||||||
|
|
||||||
int bytesRead;
|
|
||||||
for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.flush();
|
|
||||||
return byteCount;
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException var15) {
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException var14) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(String in, Writer out) throws IOException {
|
|
||||||
try {
|
|
||||||
out.write(in);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
out.close();
|
|
||||||
} catch (IOException var8) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String copyToString(Reader in) throws IOException {
|
|
||||||
if (in == null) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
StringWriter out = new StringWriter();
|
|
||||||
copy((Reader) in, (Writer) out);
|
|
||||||
return out.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,169 +0,0 @@
|
|||||||
/*
|
|
||||||
*Copyright © 2018 anji-plus
|
|
||||||
*安吉加加信息技术有限公司
|
|
||||||
*http://www.anji-plus.com
|
|
||||||
*All rights reserved.
|
|
||||||
*/
|
|
||||||
package com.anji.captcha.util;
|
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import com.anji.captcha.model.common.CaptchaBaseMapEnum;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.util.Base64Utils;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class ImageUtils {
|
|
||||||
private static Map<String, String> originalCacheMap = new ConcurrentHashMap(); //滑块底图
|
|
||||||
private static Map<String, String> slidingBlockCacheMap = new ConcurrentHashMap(); //滑块
|
|
||||||
private static Map<String, String> picClickCacheMap = new ConcurrentHashMap(); //点选文字
|
|
||||||
private static Map<String, String[]> fileNameMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
public static void cacheImage(String captchaOriginalPathJigsaw, String captchaOriginalPathClick) {
|
|
||||||
//滑动拼图
|
|
||||||
if (StrUtil.isBlank(captchaOriginalPathJigsaw)) {
|
|
||||||
originalCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/original"));
|
|
||||||
slidingBlockCacheMap.putAll(getResourcesImagesFile("defaultImages/jigsaw/slidingBlock"));
|
|
||||||
} else {
|
|
||||||
originalCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "original"));
|
|
||||||
slidingBlockCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "slidingBlock"));
|
|
||||||
}
|
|
||||||
//点选文字
|
|
||||||
if (StrUtil.isBlank(captchaOriginalPathClick)) {
|
|
||||||
picClickCacheMap.putAll(getResourcesImagesFile("defaultImages/pic-click"));
|
|
||||||
} else {
|
|
||||||
picClickCacheMap.putAll(getImagesFile(captchaOriginalPathClick));
|
|
||||||
}
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
|
|
||||||
log.info("初始化底图:{}", JsonUtil.toJSONString(fileNameMap));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cacheBootImage(Map<String, String> originalMap, Map<String, String> slidingBlockMap, Map<String, String> picClickMap) {
|
|
||||||
originalCacheMap.putAll(originalMap);
|
|
||||||
slidingBlockCacheMap.putAll(slidingBlockMap);
|
|
||||||
picClickCacheMap.putAll(picClickMap);
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
|
|
||||||
fileNameMap.put(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
|
|
||||||
log.info("自定义resource底图:{}", JsonUtil.toJSONString(fileNameMap));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static BufferedImage getOriginal() {
|
|
||||||
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.ORIGINAL.getCodeValue());
|
|
||||||
if (null == strings || strings.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
|
|
||||||
String s = originalCacheMap.get(strings[randomInt]);
|
|
||||||
return getBase64StrToImage(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getslidingBlock() {
|
|
||||||
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue());
|
|
||||||
if (null == strings || strings.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
|
|
||||||
return slidingBlockCacheMap.get(strings[randomInt]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferedImage getPicClick() {
|
|
||||||
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue());
|
|
||||||
if (null == strings || strings.length == 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
|
|
||||||
String s = picClickCacheMap.get(strings[randomInt]);
|
|
||||||
return getBase64StrToImage(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 图片转base64 字符串
|
|
||||||
*
|
|
||||||
* @param templateImage
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getImageToBase64Str(BufferedImage templateImage) {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
try {
|
|
||||||
ImageIO.write(templateImage, "png", baos);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
byte[] bytes = baos.toByteArray();
|
|
||||||
|
|
||||||
Base64.Encoder encoder = Base64.getEncoder();
|
|
||||||
|
|
||||||
return encoder.encodeToString(bytes).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* base64 字符串转图片
|
|
||||||
*
|
|
||||||
* @param base64String
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static BufferedImage getBase64StrToImage(String base64String) {
|
|
||||||
try {
|
|
||||||
Base64.Decoder decoder = Base64.getDecoder();
|
|
||||||
byte[] bytes = decoder.decode(base64String);
|
|
||||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
|
|
||||||
return ImageIO.read(inputStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Map<String, String> getResourcesImagesFile(String path) {
|
|
||||||
//默认提供六张底图
|
|
||||||
Map<String, String> imgMap = new HashMap<>();
|
|
||||||
ClassLoader classLoader = ImageUtils.class.getClassLoader();
|
|
||||||
for (int i = 1; i <= 6; i++) {
|
|
||||||
InputStream resourceAsStream = classLoader.getResourceAsStream(path.concat("/").concat(String.valueOf(i).concat(".png")));
|
|
||||||
byte[] bytes = new byte[0];
|
|
||||||
try {
|
|
||||||
bytes = FileCopyUtils.copyToByteArray(resourceAsStream);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
String string = Base64Utils.encodeToString(bytes);
|
|
||||||
String filename = String.valueOf(i).concat(".png");
|
|
||||||
imgMap.put(filename, string);
|
|
||||||
}
|
|
||||||
return imgMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, String> getImagesFile(String path) {
|
|
||||||
Map<String, String> imgMap = new HashMap<>();
|
|
||||||
File file = new File(path);
|
|
||||||
if (!file.exists()) {
|
|
||||||
return new HashMap<>();
|
|
||||||
}
|
|
||||||
File[] files = file.listFiles();
|
|
||||||
Arrays.stream(files).forEach(item -> {
|
|
||||||
try {
|
|
||||||
FileInputStream fileInputStream = new FileInputStream(item);
|
|
||||||
byte[] bytes = FileCopyUtils.copyToByteArray(fileInputStream);
|
|
||||||
String string = Base64Utils.encodeToString(bytes);
|
|
||||||
imgMap.put(item.getName(), string);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return imgMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package com.anji.captcha.util;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Title: MD5工具类
|
|
||||||
*/
|
|
||||||
public abstract class MD5Util {
|
|
||||||
/**
|
|
||||||
* 获取指定字符串的md5值
|
|
||||||
*
|
|
||||||
* @param dataStr 明文
|
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public static String md5(String dataStr) {
|
|
||||||
try {
|
|
||||||
MessageDigest m = MessageDigest.getInstance("MD5");
|
|
||||||
m.update(dataStr.getBytes(StandardCharsets.UTF_8));
|
|
||||||
byte[] s = m.digest();
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
for (byte b : s) {
|
|
||||||
result.append(Integer.toHexString((0x000000FF & b) | 0xFFFFFF00).substring(6));
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定字符串的md5值, md5(str+salt)
|
|
||||||
*
|
|
||||||
* @param dataStr 明文
|
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public static String md5WithSalt(String dataStr, String salt) {
|
|
||||||
return md5(dataStr + salt);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
*Copyright © 2018 anji-plus
|
|
||||||
*安吉加加信息技术有限公司
|
|
||||||
*http://www.anji-plus.com
|
|
||||||
*All rights reserved.
|
|
||||||
*/
|
|
||||||
package com.anji.captcha.util;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
|
|
||||||
public class RandomUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成UUID
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getUUID() {
|
|
||||||
String uuid = UUID.randomUUID().toString();
|
|
||||||
uuid = uuid.replace("-", "");
|
|
||||||
return uuid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定文字的随机中文
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getRandomHan(String hanZi) {
|
|
||||||
return hanZi.charAt(new Random().nextInt(hanZi.length())) + "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getRandomInt(int bound) {
|
|
||||||
return ThreadLocalRandom.current().nextInt(bound);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取随机中文
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getRandomHan() {
|
|
||||||
String str = "";
|
|
||||||
int highCode;
|
|
||||||
int lowCode;
|
|
||||||
|
|
||||||
Random random = new Random();
|
|
||||||
|
|
||||||
highCode = (176 + Math.abs(random.nextInt(39))); //B0 + 0~39(16~55) 一级汉字所占区
|
|
||||||
lowCode = (161 + Math.abs(random.nextInt(93))); //A1 + 0~93 每区有94个汉字
|
|
||||||
|
|
||||||
byte[] b = new byte[2];
|
|
||||||
b[0] = (Integer.valueOf(highCode)).byteValue();
|
|
||||||
b[1] = (Integer.valueOf(lowCode)).byteValue();
|
|
||||||
|
|
||||||
try {
|
|
||||||
str = new String(b, "GBK");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 随机范围内数字
|
|
||||||
*
|
|
||||||
* @param startNum
|
|
||||||
* @param endNum
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static Integer getRandomInt(int startNum, int endNum) {
|
|
||||||
return ThreadLocalRandom.current().nextInt(endNum - startNum) + startNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取随机字符串
|
|
||||||
*
|
|
||||||
* @param length
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String getRandomString(int length) {
|
|
||||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
||||||
Random random = new Random();
|
|
||||||
StringBuffer sb = new StringBuffer();
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
int number = random.nextInt(62);
|
|
||||||
sb.append(str.charAt(number));
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
package com.anji.captcha.util;
|
|
||||||
//
|
|
||||||
// Source code recreated from a .class file by IntelliJ IDEA
|
|
||||||
// (powered by Fernflower decompiler)
|
|
||||||
//
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
public abstract class StreamUtils {
|
|
||||||
public static final int BUFFER_SIZE = 4096;
|
|
||||||
private static final byte[] EMPTY_CONTENT = new byte[0];
|
|
||||||
|
|
||||||
public StreamUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] copyToByteArray(InputStream in) throws IOException {
|
|
||||||
if (in == null) {
|
|
||||||
return new byte[0];
|
|
||||||
} else {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
|
|
||||||
copy((InputStream) in, out);
|
|
||||||
return out.toByteArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String copyToString(InputStream in, Charset charset) throws IOException {
|
|
||||||
if (in == null) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
StringBuilder out = new StringBuilder();
|
|
||||||
InputStreamReader reader = new InputStreamReader(in, charset);
|
|
||||||
char[] buffer = new char[4096];
|
|
||||||
|
|
||||||
int bytesRead;
|
|
||||||
while ((bytesRead = reader.read(buffer)) != -1) {
|
|
||||||
out.append(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(byte[] in, OutputStream out) throws IOException {
|
|
||||||
out.write(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void copy(String in, Charset charset, OutputStream out) throws IOException {
|
|
||||||
Writer writer = new OutputStreamWriter(out, charset);
|
|
||||||
writer.write(in);
|
|
||||||
writer.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int copy(InputStream in, OutputStream out) throws IOException {
|
|
||||||
int byteCount = 0;
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
|
|
||||||
int bytesRead;
|
|
||||||
for (boolean var4 = true; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
out.flush();
|
|
||||||
return byteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long copyRange(InputStream in, OutputStream out, long start, long end) throws IOException {
|
|
||||||
long skipped = in.skip(start);
|
|
||||||
if (skipped < start) {
|
|
||||||
throw new IOException("Skipped only " + skipped + " bytes out of " + start + " required");
|
|
||||||
} else {
|
|
||||||
long bytesToCopy = end - start + 1L;
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
|
|
||||||
while (bytesToCopy > 0L) {
|
|
||||||
int bytesRead = in.read(buffer);
|
|
||||||
if (bytesRead == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((long) bytesRead <= bytesToCopy) {
|
|
||||||
out.write(buffer, 0, bytesRead);
|
|
||||||
bytesToCopy -= (long) bytesRead;
|
|
||||||
} else {
|
|
||||||
out.write(buffer, 0, (int) bytesToCopy);
|
|
||||||
bytesToCopy = 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return end - start + 1L - bytesToCopy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int drain(InputStream in) throws IOException {
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int byteCount;
|
|
||||||
int bytesRead;
|
|
||||||
for (byteCount = 0; (bytesRead = in.read(buffer)) != -1; byteCount += bytesRead) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return byteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream emptyInput() {
|
|
||||||
return new ByteArrayInputStream(EMPTY_CONTENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream nonClosing(InputStream in) {
|
|
||||||
return new NonClosingInputStream(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OutputStream nonClosing(OutputStream out) {
|
|
||||||
return new NonClosingOutputStream(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class NonClosingOutputStream extends FilterOutputStream {
|
|
||||||
public NonClosingOutputStream(OutputStream out) {
|
|
||||||
super(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int let) throws IOException {
|
|
||||||
this.out.write(b, off, let);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class NonClosingInputStream extends FilterInputStream {
|
|
||||||
public NonClosingInputStream(InputStream in) {
|
|
||||||
super(in);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
com.anji.captcha.service.impl.BlockPuzzleCaptchaServiceImpl
|
|
||||||
com.anji.captcha.service.impl.ClickWordCaptchaServiceImpl
|
|
||||||
com.anji.captcha.service.impl.DefaultCaptchaServiceImpl
|
|
||||||
@ -1,2 +1 @@
|
|||||||
com.anji.captcha.config.AjCaptchaAutoConfiguration
|
|
||||||
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration
|
cn.iocoder.yudao.framework.captcha.config.YudaoCaptchaConfiguration
|
||||||
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 72 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 58 KiB |
@ -0,0 +1,259 @@
|
|||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"EffectScope": true,
|
||||||
|
"ElMessage": true,
|
||||||
|
"ElMessageBox": true,
|
||||||
|
"ElTag": true,
|
||||||
|
"asyncComputed": true,
|
||||||
|
"autoResetRef": true,
|
||||||
|
"computed": true,
|
||||||
|
"computedAsync": true,
|
||||||
|
"computedEager": true,
|
||||||
|
"computedInject": true,
|
||||||
|
"computedWithControl": true,
|
||||||
|
"controlledComputed": true,
|
||||||
|
"controlledRef": true,
|
||||||
|
"createApp": true,
|
||||||
|
"createEventHook": true,
|
||||||
|
"createGlobalState": true,
|
||||||
|
"createInjectionState": true,
|
||||||
|
"createReactiveFn": true,
|
||||||
|
"createSharedComposable": true,
|
||||||
|
"createUnrefFn": true,
|
||||||
|
"customRef": true,
|
||||||
|
"debouncedRef": true,
|
||||||
|
"debouncedWatch": true,
|
||||||
|
"defineAsyncComponent": true,
|
||||||
|
"defineComponent": true,
|
||||||
|
"eagerComputed": true,
|
||||||
|
"effectScope": true,
|
||||||
|
"extendRef": true,
|
||||||
|
"getCurrentInstance": true,
|
||||||
|
"getCurrentScope": true,
|
||||||
|
"h": true,
|
||||||
|
"ignorableWatch": true,
|
||||||
|
"inject": true,
|
||||||
|
"isDefined": true,
|
||||||
|
"isProxy": true,
|
||||||
|
"isReactive": true,
|
||||||
|
"isReadonly": true,
|
||||||
|
"isRef": true,
|
||||||
|
"makeDestructurable": true,
|
||||||
|
"markRaw": true,
|
||||||
|
"nextTick": true,
|
||||||
|
"onActivated": true,
|
||||||
|
"onBeforeMount": true,
|
||||||
|
"onBeforeUnmount": true,
|
||||||
|
"onBeforeUpdate": true,
|
||||||
|
"onClickOutside": true,
|
||||||
|
"onDeactivated": true,
|
||||||
|
"onErrorCaptured": true,
|
||||||
|
"onKeyStroke": true,
|
||||||
|
"onLongPress": true,
|
||||||
|
"onMounted": true,
|
||||||
|
"onRenderTracked": true,
|
||||||
|
"onRenderTriggered": true,
|
||||||
|
"onScopeDispose": true,
|
||||||
|
"onServerPrefetch": true,
|
||||||
|
"onStartTyping": true,
|
||||||
|
"onUnmounted": true,
|
||||||
|
"onUpdated": true,
|
||||||
|
"pausableWatch": true,
|
||||||
|
"provide": true,
|
||||||
|
"reactify": true,
|
||||||
|
"reactifyObject": true,
|
||||||
|
"reactive": true,
|
||||||
|
"reactiveComputed": true,
|
||||||
|
"reactiveOmit": true,
|
||||||
|
"reactivePick": true,
|
||||||
|
"readonly": true,
|
||||||
|
"ref": true,
|
||||||
|
"refAutoReset": true,
|
||||||
|
"refDebounced": true,
|
||||||
|
"refDefault": true,
|
||||||
|
"refThrottled": true,
|
||||||
|
"refWithControl": true,
|
||||||
|
"resolveComponent": true,
|
||||||
|
"resolveRef": true,
|
||||||
|
"resolveUnref": true,
|
||||||
|
"shallowReactive": true,
|
||||||
|
"shallowReadonly": true,
|
||||||
|
"shallowRef": true,
|
||||||
|
"syncRef": true,
|
||||||
|
"syncRefs": true,
|
||||||
|
"templateRef": true,
|
||||||
|
"throttledRef": true,
|
||||||
|
"throttledWatch": true,
|
||||||
|
"toRaw": true,
|
||||||
|
"toReactive": true,
|
||||||
|
"toRef": true,
|
||||||
|
"toRefs": true,
|
||||||
|
"triggerRef": true,
|
||||||
|
"tryOnBeforeMount": true,
|
||||||
|
"tryOnBeforeUnmount": true,
|
||||||
|
"tryOnMounted": true,
|
||||||
|
"tryOnScopeDispose": true,
|
||||||
|
"tryOnUnmounted": true,
|
||||||
|
"unref": true,
|
||||||
|
"unrefElement": true,
|
||||||
|
"until": true,
|
||||||
|
"useActiveElement": true,
|
||||||
|
"useArrayEvery": true,
|
||||||
|
"useArrayFilter": true,
|
||||||
|
"useArrayFind": true,
|
||||||
|
"useArrayFindIndex": true,
|
||||||
|
"useArrayJoin": true,
|
||||||
|
"useArrayMap": true,
|
||||||
|
"useArrayReduce": true,
|
||||||
|
"useArraySome": true,
|
||||||
|
"useAsyncQueue": true,
|
||||||
|
"useAsyncState": true,
|
||||||
|
"useAttrs": true,
|
||||||
|
"useBase64": true,
|
||||||
|
"useBattery": true,
|
||||||
|
"useBluetooth": true,
|
||||||
|
"useBreakpoints": true,
|
||||||
|
"useBroadcastChannel": true,
|
||||||
|
"useBrowserLocation": true,
|
||||||
|
"useCached": true,
|
||||||
|
"useClipboard": true,
|
||||||
|
"useColorMode": true,
|
||||||
|
"useConfirmDialog": true,
|
||||||
|
"useCounter": true,
|
||||||
|
"useCssModule": true,
|
||||||
|
"useCssVar": true,
|
||||||
|
"useCssVars": true,
|
||||||
|
"useCurrentElement": true,
|
||||||
|
"useCycleList": true,
|
||||||
|
"useDark": true,
|
||||||
|
"useDateFormat": true,
|
||||||
|
"useDebounce": true,
|
||||||
|
"useDebounceFn": true,
|
||||||
|
"useDebouncedRefHistory": true,
|
||||||
|
"useDeviceMotion": true,
|
||||||
|
"useDeviceOrientation": true,
|
||||||
|
"useDevicePixelRatio": true,
|
||||||
|
"useDevicesList": true,
|
||||||
|
"useDisplayMedia": true,
|
||||||
|
"useDocumentVisibility": true,
|
||||||
|
"useDraggable": true,
|
||||||
|
"useDropZone": true,
|
||||||
|
"useElementBounding": true,
|
||||||
|
"useElementByPoint": true,
|
||||||
|
"useElementHover": true,
|
||||||
|
"useElementSize": true,
|
||||||
|
"useElementVisibility": true,
|
||||||
|
"useEventBus": true,
|
||||||
|
"useEventListener": true,
|
||||||
|
"useEventSource": true,
|
||||||
|
"useEyeDropper": true,
|
||||||
|
"useFavicon": true,
|
||||||
|
"useFetch": true,
|
||||||
|
"useFileDialog": true,
|
||||||
|
"useFileSystemAccess": true,
|
||||||
|
"useFocus": true,
|
||||||
|
"useFocusWithin": true,
|
||||||
|
"useFps": true,
|
||||||
|
"useFullscreen": true,
|
||||||
|
"useGamepad": true,
|
||||||
|
"useGeolocation": true,
|
||||||
|
"useIdle": true,
|
||||||
|
"useImage": true,
|
||||||
|
"useInfiniteScroll": true,
|
||||||
|
"useIntersectionObserver": true,
|
||||||
|
"useInterval": true,
|
||||||
|
"useIntervalFn": true,
|
||||||
|
"useKeyModifier": true,
|
||||||
|
"useLastChanged": true,
|
||||||
|
"useLocalStorage": true,
|
||||||
|
"useMagicKeys": true,
|
||||||
|
"useManualRefHistory": true,
|
||||||
|
"useMediaControls": true,
|
||||||
|
"useMediaQuery": true,
|
||||||
|
"useMemoize": true,
|
||||||
|
"useMemory": true,
|
||||||
|
"useMounted": true,
|
||||||
|
"useMouse": true,
|
||||||
|
"useMouseInElement": true,
|
||||||
|
"useMousePressed": true,
|
||||||
|
"useMutationObserver": true,
|
||||||
|
"useNavigatorLanguage": true,
|
||||||
|
"useNetwork": true,
|
||||||
|
"useNow": true,
|
||||||
|
"useObjectUrl": true,
|
||||||
|
"useOffsetPagination": true,
|
||||||
|
"useOnline": true,
|
||||||
|
"usePageLeave": true,
|
||||||
|
"useParallax": true,
|
||||||
|
"usePermission": true,
|
||||||
|
"usePointer": true,
|
||||||
|
"usePointerSwipe": true,
|
||||||
|
"usePreferredColorScheme": true,
|
||||||
|
"usePreferredDark": true,
|
||||||
|
"usePreferredLanguages": true,
|
||||||
|
"useRafFn": true,
|
||||||
|
"useRefHistory": true,
|
||||||
|
"useResizeObserver": true,
|
||||||
|
"useRoute": true,
|
||||||
|
"useRouter": true,
|
||||||
|
"useScreenOrientation": true,
|
||||||
|
"useScreenSafeArea": true,
|
||||||
|
"useScriptTag": true,
|
||||||
|
"useScroll": true,
|
||||||
|
"useScrollLock": true,
|
||||||
|
"useSessionStorage": true,
|
||||||
|
"useShare": true,
|
||||||
|
"useSlots": true,
|
||||||
|
"useSpeechRecognition": true,
|
||||||
|
"useSpeechSynthesis": true,
|
||||||
|
"useStepper": true,
|
||||||
|
"useStorage": true,
|
||||||
|
"useStorageAsync": true,
|
||||||
|
"useStyleTag": true,
|
||||||
|
"useSupported": true,
|
||||||
|
"useSwipe": true,
|
||||||
|
"useTemplateRefsList": true,
|
||||||
|
"useTextDirection": true,
|
||||||
|
"useTextSelection": true,
|
||||||
|
"useTextareaAutosize": true,
|
||||||
|
"useThrottle": true,
|
||||||
|
"useThrottleFn": true,
|
||||||
|
"useThrottledRefHistory": true,
|
||||||
|
"useTimeAgo": true,
|
||||||
|
"useTimeout": true,
|
||||||
|
"useTimeoutFn": true,
|
||||||
|
"useTimeoutPoll": true,
|
||||||
|
"useTimestamp": true,
|
||||||
|
"useTitle": true,
|
||||||
|
"useToggle": true,
|
||||||
|
"useTransition": true,
|
||||||
|
"useUrlSearchParams": true,
|
||||||
|
"useUserMedia": true,
|
||||||
|
"useVModel": true,
|
||||||
|
"useVModels": true,
|
||||||
|
"useVibrate": true,
|
||||||
|
"useVirtualList": true,
|
||||||
|
"useWakeLock": true,
|
||||||
|
"useWebNotification": true,
|
||||||
|
"useWebSocket": true,
|
||||||
|
"useWebWorker": true,
|
||||||
|
"useWebWorkerFn": true,
|
||||||
|
"useWindowFocus": true,
|
||||||
|
"useWindowScroll": true,
|
||||||
|
"useWindowSize": true,
|
||||||
|
"watch": true,
|
||||||
|
"watchArray": true,
|
||||||
|
"watchAtMost": true,
|
||||||
|
"watchDebounced": true,
|
||||||
|
"watchEffect": true,
|
||||||
|
"watchIgnorable": true,
|
||||||
|
"watchOnce": true,
|
||||||
|
"watchPausable": true,
|
||||||
|
"watchPostEffect": true,
|
||||||
|
"watchSyncEffect": true,
|
||||||
|
"watchThrottled": true,
|
||||||
|
"watchTriggerable": true,
|
||||||
|
"watchWithFilter": true,
|
||||||
|
"whenever": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,18 +0,0 @@
|
|||||||
export const styleImportPlugin = {
|
|
||||||
libs: [
|
|
||||||
{
|
|
||||||
libraryName: 'element-plus',
|
|
||||||
esModule: true,
|
|
||||||
resolveStyle: (name) => {
|
|
||||||
return `element-plus/es/components/${name.substring(3)}/style/css`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
libraryName: 'vxe-table',
|
|
||||||
esModule: true,
|
|
||||||
resolveStyle: (name) => {
|
|
||||||
return `vxe-table/es/${name}/style.css`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||