提交 961661c6 authored 作者: renjiancai's avatar renjiancai

--no commit message

上级 05bec6ad
<factorypath>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/5.0.5.RELEASE/spring-context-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/5.0.5.RELEASE/spring-aop-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/5.0.5.RELEASE/spring-beans-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.5.RELEASE/spring-core-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.5.RELEASE/spring-jcl-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/5.0.5.RELEASE/spring-expression-5.0.5.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/servlet/javax.servlet-api/3.1.0/javax.servlet-api-3.1.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/zxing/core/3.3.3/core-3.3.3.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/zxing/javase/3.3.3/javase-3.3.3.jar" enabled="true" runInBatchMode="false"/>
......@@ -28,11 +34,6 @@
<factorypathentry kind="VARJAR" id="M2_REPO/com/fasterxml/classmate/1.3.1/classmate-1.3.1.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.7.21/slf4j-api-1.7.21.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-core/1.2.0.RELEASE/spring-plugin-core-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-beans/4.0.9.RELEASE/spring-beans-4.0.9.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-context/4.0.9.RELEASE/spring-context-4.0.9.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-expression/4.0.9.RELEASE/spring-expression-4.0.9.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-aop/4.0.9.RELEASE/spring-aop-4.0.9.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/aopalliance/aopalliance/1.0/aopalliance-1.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/plugin/spring-plugin-metadata/1.2.0.RELEASE/spring-plugin-metadata-1.2.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/mapstruct/mapstruct/1.0.0.Final/mapstruct-1.0.0.Final.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/tk/mybatis/mapper-spring-boot-starter/1.2.4/mapper-spring-boot-starter-1.2.4.jar" enabled="true" runInBatchMode="false"/>
......@@ -46,8 +47,6 @@
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.10.0/log4j-api-2.10.0.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-core/5.0.4.RELEASE/spring-core-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/spring-jcl/5.0.4.RELEASE/spring-jcl-5.0.4.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/yaml/snakeyaml/1.19/snakeyaml-1.19.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/org/springframework/boot/spring-boot-starter-jdbc/2.0.0.RELEASE/spring-boot-starter-jdbc-2.0.0.RELEASE.jar" enabled="true" runInBatchMode="false"/>
<factorypathentry kind="VARJAR" id="M2_REPO/com/zaxxer/HikariCP/2.7.8/HikariCP-2.7.8.jar" enabled="true" runInBatchMode="false"/>
......
......@@ -15,6 +15,16 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
......
package com.zrqx.core.components;
/**
* @author lpf
* @date 2020-06-16
*/
public interface CacheService {
/**
* key:value:expiresInSeconds
* @param key
* @param value
* @param expiresInSeconds
*/
void set(String key, String value, long expiresInSeconds);
/**
* exists key
* @param key
* @return
*/
boolean exists(String key);
/**
* delete key
* @param key
*/
void delete(String key);
/**
* get key
* @param key
* @return
*/
String get(String key);
}
package com.zrqx.core.components;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* redis 缓存实现
* @author lpf
* @date 2020-06-17
*/
@Component
@Primary
@Order(Ordered.LOWEST_PRECEDENCE)
public class RedisCacheServiceImpl implements CacheService{
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public void set(String key, String value, long expiresInSeconds) {
stringRedisTemplate.opsForValue().set(key, value, expiresInSeconds, TimeUnit.SECONDS);
}
@Override
public boolean exists(String key) {
return stringRedisTemplate.hasKey(key);
}
@Override
public void delete(String key) {
stringRedisTemplate.delete(key);
}
@Override
public String get(String key) {
return stringRedisTemplate.opsForValue().get(key);
}
}
package com.zrqx.core.components;
import com.zrqx.core.exception.ValidateException;
/**
* Title: Validate
* Description: 验证接口,提供给内部其他服务访问,用于验证内部服务的处理结果
*
* @author lpf
* @version V1.0
* @date 2020-06-16
*/
public interface Validate<T> {
/**
* 验证,验证不通过抛出具体的异常信息
* @param t
* @throws ValidateException
*/
void validate(T t) throws ValidateException;
}
package com.zrqx.core.components.captcha;
import com.zrqx.core.components.Validate;
import com.zrqx.core.components.captcha.form.CaptchaForm;
/**
* @author lpf
* @date 2020-06-22
*/
public interface CaptchaService extends Validate<CaptchaForm> {
}
package com.zrqx.core.components.captcha.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lpf
* @date 2020-06-16
*/
@Data
@ApiModel(value = "CaptchaForm", description = "验证码组件Form")
public class CaptchaForm {
@ApiModelProperty("验证码id")
private String uuid;
@ApiModelProperty("*获取验证码方式,查看验证码方式接口")
private String type;
@ApiModelProperty("验证码输入结果,滑动验证码格式json:{x: 111, y: 5}")
private String value;
@ApiModelProperty("验证码业务方式,查看验证码业务方式接口")
private String businessType;
@ApiModelProperty("手机号")
private String phone;
}
package com.zrqx.core.components.captcha.service;
import com.zrqx.core.components.CacheService;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.exception.ValidateException;
import com.zrqx.core.util.datatype.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 公共验证结果处理,做公共处理逻辑
* @author lpf
* @date 2020-06-17
*/
public abstract class BaseCaptchaValidateServiceImpl implements CaptchaValidateService{
private static final Logger log = LoggerFactory.getLogger(BaseCaptchaValidateServiceImpl.class);
@Autowired
protected CacheService cacheService;
@Override
public void validate(CaptchaForm form) throws ValidateException {
log.info("公共逻辑校验{}",form);
if (StringUtils.isEmpty(form.getUuid())) {
throw new ValidateException("uuid不能为空");
}
if (StringUtils.isEmpty(form.getType())) {
throw new ValidateException("type不能为空");
}
if (StringUtils.isEmpty(form.getValue())) {
throw new ValidateException("value不能为空");
}
String key = String.format(REDIS_CAPTCHA_KEY, form.getUuid());
if (!cacheService.exists(key)) {
throw new ValidateException("验证码已失效,请重新获取");
}
String value = cacheService.get(key);
if (StringUtils.isEmpty(value)) {
throw new ValidateException("验证码已失效,请重新获取");
}
// 验证验证码次数,验证码n次之后失效
String numKey = String.format(REDIS_CAPTCHA_NUM_KEY, form.getUuid());
String numStr = cacheService.get(numKey);
if (StringUtils.isEmpty(numStr)) {
numStr = "0";
}
Integer num = Integer.valueOf(numStr);
num ++ ;
if (num > EXPIRESIN_NUM) {
cacheService.delete(key);
cacheService.delete(numKey);
throw new ValidateException("验证码在有效期内最多验证" + EXPIRESIN_NUM + "次");
}
cacheService.set(numKey, num+"", EXPIRESIN_SECONDS);
log.info("特性校验form:{},value:{}", form, value);
this.validate(form, value);
}
/**
* 特性化校验逻辑
* @param form 用户提交验证码信息
* @param value 缓存中存储信息
* @throws ValidateException 验证码验证失败异常
* @return
* @author lpf
* @date 2020-06-17 15:15
*/
protected abstract void validate(CaptchaForm form, String value) throws ValidateException;
}
package com.zrqx.core.components.captcha.service;
import com.alibaba.fastjson.JSONObject;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.exception.ValidateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.awt.*;
import java.util.Arrays;
import java.util.List;
/**
* @author lpf
* @date 2020-06-18
*/
@Component
public class BlockPuzzleCaptchaValidateServiceImpl extends BaseCaptchaValidateServiceImpl{
private static final Logger log = LoggerFactory.getLogger(BlockPuzzleCaptchaValidateServiceImpl.class);
/** 误差偏移量 */
protected int slipOffset = 5;
@Override
public List<CaptchaTypeEnum> getEnums() {
return Arrays.asList(CaptchaTypeEnum.BLOCKPUZZLE);
}
@Override
protected void validate(CaptchaForm form, String value) throws ValidateException {
String formValue = form.getValue();
if (formValue.equals(value)) {
return ;
}
Point formPoint = null;
Point valuePoint = null;
try {
formPoint = JSONObject.parseObject(formValue, Point.class);
valuePoint = JSONObject.parseObject(value, Point.class);
} catch (Exception e) {
log.error("滑块验证码解析坐标失败",e);
throw new ValidateException("滑块验证码解析坐标失败");
}
// 误差判断,误差范围内通过
if (formPoint.x < (valuePoint.x - slipOffset)
|| formPoint.x > (valuePoint.x + slipOffset)
|| formPoint.y != valuePoint.y) {
throw new ValidateException("验证失败");
}
}
}
package com.zrqx.core.components.captcha.service;
import com.zrqx.core.components.captcha.CaptchaService;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.exception.ValidateException;
import com.zrqx.core.util.spring.SpringContextUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author lpf
* @date 2020-06-22
*/
@Component
public class CaptchaServiceImpl implements CaptchaService {
@Autowired
private SpringContextUtils springContextUtils;
private CaptchaValidateService getService(CaptchaForm form) {
CaptchaValidateService service = springContextUtils.getEnumsBindBean(CaptchaTypeEnum.class, form.getType(), CaptchaValidateService.class);
return service;
}
@Override
public void validate(CaptchaForm form) throws ValidateException {
getService(form).validate(form);
}
}
package com.zrqx.core.components.captcha.service;
import com.zrqx.core.components.Validate;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.enums.interfaces.EnumsBindBean;
/**
* 验证码校验结果工具
* 使用说明:查看 BaseLoginServiceImpl
* @author lpf
* @date 2020-06-16
*/
public interface CaptchaValidateService extends Validate<CaptchaForm>, EnumsBindBean<CaptchaTypeEnum> {
/** 验证码键生成规则 */
String REDIS_CAPTCHA_KEY = "RUNNING:CAPTCHA:%s";
/** 验证码键校验次数 */
String REDIS_CAPTCHA_NUM_KEY = "RUNNING:CAPTCHA:NUM:%s";
/** 验证码失效时间,校验次数失效时间 */
long EXPIRESIN_SECONDS = 5 * 60L;
/** 验证码失效次数 */
int EXPIRESIN_NUM = 5;
}
package com.zrqx.core.components.captcha.service;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.exception.ValidateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
/**
*
* @author lpf
* @date 2020-06-16
*/
@Component
public class CodeCaptchaValidateServiceImpl extends BaseCaptchaValidateServiceImpl{
private static final Logger log = LoggerFactory.getLogger(CodeCaptchaValidateServiceImpl.class);
@Override
public List<CaptchaTypeEnum> getEnums() {
return Arrays.asList(CaptchaTypeEnum.CODE,CaptchaTypeEnum.PHONE);
}
@Override
protected void validate(CaptchaForm form, String value) throws ValidateException {
if (!form.getValue().toLowerCase().equals(value.toLowerCase())) {
throw new ValidateException("验证码输入错误");
}
}
}
package com.zrqx.core.components.message.form;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lpf
* @date 2020-06-19
*/
@Data
@ApiModel(value = "MessageForm", description = "消息组件Form")
public class MessageForm {
@ApiModelProperty("消息发送内容")
private String value;
@ApiModelProperty("消息发送目标")
private String target;
@ApiModelProperty("消息发送业务方式,详细查看业务方式接口")
private String businessType;
}
package com.zrqx.core.enums.captcha;
import java.util.HashMap;
import java.util.stream.Stream;
/**
* 验证码业务类型
* @author lpf
* @date 2020-06-19
*/
public enum CaptchaBusinessTypeEnum {
/** */
REGISTER_CAPTCHA("captcha_reg", "注册验证码"),
LOGIN_CAPTCHA("captcha_login", "登录验证码"),
RESET_PASSWORD_CAPTCHA("captcha_reset_password", "找回密码验证码");
private final String code;
private final String name;
private static final HashMap<String,String> MAP = new HashMap<String,String>();
static {
stream().forEach(e -> {
MAP.put(e.code, e.name);
});
}
public static Stream<CaptchaBusinessTypeEnum> stream(){
return Stream.of(values());
}
private CaptchaBusinessTypeEnum(String code, String name) {
this.code = code;
this.name = name;
}
public static boolean isExist(String code) {
return stream().anyMatch(e -> e.code.equals(code));
}
public static String getName(String code) {
return stream().filter(e -> e.code.equals(code)).findFirst().map(e -> e.name).orElse(null);
}
public String getCode() {
return code;
}
public String getName() {
return name;
}
public static HashMap<String, String> getMap() {
return MAP;
}
}
package com.zrqx.core.enums.captcha;
import com.zrqx.core.enums.interfaces.EnumsInterface;
import java.util.HashMap;
import java.util.stream.Stream;
/**
* 验证码类型
* @author lpf
* @date 2020-06-16
*/
public enum CaptchaTypeEnum implements EnumsInterface<String> {
/** */
CODE("code", "字母与数字混合验证码"),
BLOCKPUZZLE("blockPuzzle", "滑动验证码"),
PHONE("phone","手机验证码");
private final String code;
private final String name;
private static final HashMap<String,String> MAP = new HashMap<String,String>();
static {
stream().forEach(e -> {
MAP.put(e.code, e.name);
});
}
public static Stream<CaptchaTypeEnum> stream(){
return Stream.of(values());
}
private CaptchaTypeEnum(String code, String name) {
this.code = code;
this.name = name;
}
public static boolean isExist(String code) {
return stream().anyMatch(e -> e.code.equals(code));
}
public static String getName(String code) {
return stream().filter(e -> e.code.equals(code)).findFirst().map(e -> e.name).orElse(null);
}
@Override
public String getCode() {
return code;
}
@Override
public String getName() {
return name;
}
public static HashMap<String, String> getMap() {
return MAP;
}
}
package com.zrqx.core.exception;
import com.zrqx.core.enums.ResponseCodeEnum;
/**
* Title: ValidateException
* Description: TODO
*
* @author lpf
* @version V1.0
* @date 2020-06-16
*/
public class ValidateException extends BaseException{
public ValidateException() {
}
public ValidateException(String message) {
super(message);
}
public ValidateException(int code, String message) {
super(code, message);
}
public ValidateException(int code, String message, Object data) {
super(code, message, data);
}
public ValidateException(ResponseCodeEnum res) {
super(res);
}
public ValidateException(String message, Throwable cause) {
super(message, cause);
}
public ValidateException(Throwable cause) {
super(cause);
}
}
package com.zrqx.core.util.datatype;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 字符串的一些公共方法
* @ClassName: StringUtils
* @author
* @date 2014-7-14 上午11:14:00
*
*/
public class StringUtils extends org.apache.commons.lang3.StringUtils{
private final static String[] AGENT = { "Android", "iPhone", "iPod","iPad", "Windows Phone", "MQQBrowser" };
private final static String[] ENLETTERS = {"a","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","t","u","v","w","x","y","z"};
public static boolean isNotBlank(Integer value){
return value != null;
}
/**
* 给定指定字符串res,去除字符串首尾的指定字符c
* @Title: trim
* @param res 原字符串
* @param c 要删除的字符,只删除首尾,且不能截取Unicode 大于 'A'的字符
* @return
* @return String 返回类型
* @author
* @date 2014-7-14 上午11:21:21
*/
public static String trim(String res,char c) {
int count = res.toCharArray().length;
int len = res.toCharArray().length;
int st = 0;
/* avoid getfield opcode */
int off = 0;
/* avoid getfield opcode */
char[] val = res.toCharArray();
while ((st < len) && (val[off + st] <= c)) {
st++;
}
while ((st < len) && (val[off + len - 1] <= c)) {
len--;
}
return ((st > 0) || (len < count)) ? res.substring(st, len) : res;
}
/**
* 获取setter方法名称
* @Title: getSetterMethodName
* @param key
* @return
* @return String 返回类型
* @author
* @date 2014年7月24日 下午3:43:22
*/
public static String getMethodName(String begin,String key) {
StringBuilder result = new StringBuilder(begin);
result.append(key.substring(0,1).toUpperCase()).append(key.substring(1));
return result.toString();
}
/**
* 获取随机英文字符串
* @param caseType 1大写,其他小写
* @param length 返回字符串长度
* @param hasRepeat 是否包含重复字符 1包含0不包含
* @return
* @author ydm
* @date: 2018年7月11日 上午11:33:25
*/
public static String getRandomEnSign(int caseType,int length,int hasRepeat){
StringBuffer resultBuffer = new StringBuffer();
for(int i = 0 ; i < length ; i ++ ){
int x=1+(int)(Math.random()* ENLETTERS.length-1);
if(hasRepeat * 1 == 0){
if(resultBuffer.toString().toLowerCase().indexOf(ENLETTERS[x].toLowerCase())>0){
continue;
}
}
resultBuffer.append(caseType*1==1 ? ENLETTERS[x].toUpperCase() : ENLETTERS[x].toLowerCase());
}
return resultBuffer.toString();
}
public static Object checkNull(Object obj) {
Class<? extends Object> clazz = obj.getClass();
// 获取实体类的所有属性,返回Field数组
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 可访问私有变量
field.setAccessible(true);
// 获取属性类型
String type = field.getGenericType().toString();
// 如果type是类类型,则前面包含"class ",后面跟类名
if ("class java.lang.String".equals(type)) {
// 将属性的首字母大写
String methodName = field.getName().replaceFirst(field.getName().substring(0, 1),
field.getName().substring(0, 1).toUpperCase());
System.out.println(methodName);
try {
Method methodGet = clazz.getMethod("get" + methodName);
// 调用getter方法获取属性值
String str = (String) methodGet.invoke(obj);
if (str==null) {
// 如果为null的String类型的属性则重新复制为空字符串
field.set(obj, field.getType().getConstructor(field.getType()).newInstance(""));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return obj;
}
}
......@@ -2,8 +2,10 @@ package com.zrqx.core.util.spring;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import com.zrqx.core.exception.BaseException;
import org.slf4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
......@@ -14,7 +16,11 @@ import com.zrqx.core.enums.interfaces.EnumsInterface;
import com.zrqx.core.enums.interfaces.LoggerFactory;
import com.zrqx.core.enums.interfaces.bean.EnumsBindObject;
import com.zrqx.core.util.datatype.ArrayUtils;
/**
*
* @author lpf
* @date 2020-07-01 9:45
*/
public abstract class BaseSpringContextUtils implements ApplicationContextAware, LoggerFactory {
protected ApplicationContext context;
......@@ -90,7 +96,7 @@ public abstract class BaseSpringContextUtils implements ApplicationContextAware,
* @date: 2019年1月7日 上午11:03:08
*/
@SuppressWarnings("unchecked")
public <T,D extends EnumsInterface<T>> EnumsBindObject<D> getEnumsBindObject(Class<D> enumClass, T code){
public <T,D extends EnumsInterface<T>> List<EnumsBindObject<EnumsInterface<?>>> getEnumsBindObject(Class<D> enumClass, T code){
Map<Object, List<EnumsBindObject<EnumsInterface<?>>>> map = enumsBindMap.get(enumClass);
if (map == null) {
getLog().warn("type:"+ enumClass +",code:"+ code +"获取枚举绑定操作失败");
......@@ -101,28 +107,10 @@ public abstract class BaseSpringContextUtils implements ApplicationContextAware,
getLog().warn("type:"+ enumClass +",code:"+ code +",获取枚举绑定操作失败");
return null;
}
// TODO EnumsBindObject 同一种枚举不同的绑定接口 获取接口时会有问题
return (EnumsBindObject<D>) list.get(0);
return list;
}
/**
* 获取枚举绑定的操作接口
* @param enumClass
* @param code
* @return
* @author lpf
* @date: 2019年1月7日 上午11:08:44
*/
public <T,D extends EnumsInterface<T>> EnumsBindBean<D> getEnumsBindBean(Class<D> enumClass, T code){
EnumsBindObject<D> object = getEnumsBindObject(enumClass, code);
if (object == null) {
throw new RuntimeException("type:"+ enumClass +",code:"+ code +",获取枚举绑定操作失败");
}
return object.getBindBean();
}
/**
* 获取枚举绑定的操作接口并强转为target 接口
* @param enumClass
* @param code
......@@ -133,11 +121,15 @@ public abstract class BaseSpringContextUtils implements ApplicationContextAware,
*/
public <T,D extends EnumsInterface<T>,B> B getEnumsBindBean(Class<D> enumClass, T code, Class<B> target) {
try {
@SuppressWarnings("unchecked")
B b = (B) getEnumsBindBean(enumClass, code);
List<EnumsBindObject<EnumsInterface<?>>> list = getEnumsBindObject(enumClass, code);
Optional<EnumsBindBean<EnumsInterface<?>>> first = list.stream().map(EnumsBindObject::getBindBean)
.filter(t -> target.isAssignableFrom(t.getClass())).findFirst();
EnumsBindBean<EnumsInterface<?>> obj = first.orElseThrow(() -> new BaseException("type:"+ enumClass +",code:"+ code +",得到对象EnumsBindBean<D> 失败" ));
B b = (B) obj;
return b;
} catch (Exception e) {
throw new RuntimeException("type:"+ enumClass +",code:"+ code +",得到对象EnumsBindBean<D>" + getEnumsBindBean(enumClass, code).getClass() +" 强转 Class<B>:" + target + "失败");
e.printStackTrace();
throw new RuntimeException("type:"+ enumClass +",code:"+ code +",得到对象EnumsBindBean<D>" +" 强转 Class<B>:" + target + "失败");
}
}
}
package com.zrqx.core.util.spring;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
*
* @author lpf
* @date 2020-07-01 13:45
*/
@Component
public class SpringContextUtils extends BaseSpringContextUtils{
private static final Logger logger = LoggerFactory.getLogger(SpringContextUtils.class);
@Override
public Logger getLog() {
return logger;
}
public static HttpServletRequest getRequest(){
ServletRequestAttributes ra= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ra.getRequest();
return request;
}
}
......@@ -24,4 +24,6 @@ public class FgSearchListVO {
private Integer clickNumber;
@ApiModelProperty(value = "发布时间")
private Date newPulishDate;
@ApiModelProperty("下载地址")
private String fileName;
}
package com.zrqx.member.fg.captcha.commons.enums;
/**
*
* @author lpf
* @date 2020-07-01 9:44
*/
public enum CaptchaBaseMapEnum {
/** 滑动拼图底图 */
ORIGINAL("ORIGINAL","滑动拼图底图"),
/** 滑动拼图滑块底图 */
SLIDING_BLOCK("SLIDING_BLOCK","滑动拼图滑块底图"),
/** 文字点选底图 */
PIC_CLICK("PIC_CLICK","文字点选底图");
private String codeValue;
private String codeDesc;
private CaptchaBaseMapEnum(String codeValue, String codeDesc) {
this.codeValue = codeValue;
this.codeDesc = codeDesc;
}
public String getCodeValue(){ return this.codeValue;}
public String getCodeDesc(){ return this.codeDesc;}
public static CaptchaBaseMapEnum parseFromCodeValue(String codeValue){
for (CaptchaBaseMapEnum e : CaptchaBaseMapEnum.values()){
if(e.codeValue.equals(codeValue)){ return e;}
}
return null;
}
public static String getCodeDescByCodeBalue(String codeValue){
CaptchaBaseMapEnum enumItem = parseFromCodeValue(codeValue);
return enumItem == null ? "" : enumItem.getCodeDesc();
}
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();
}
}
/*
*Copyright © 2018 anji-plus
*安吉加加信息技术有限公司
*http://www.anji-plus.com
*All rights reserved.
*/
package com.zrqx.member.fg.captcha.commons.utils;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.imageio.ImageIO;
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 com.zrqx.core.util.datatype.StringUtils;
import com.zrqx.member.fg.captcha.commons.enums.CaptchaBaseMapEnum;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
*
* @author lpf
* @date 2020-07-01 9:49
*/
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 (StringUtils.isBlank(captchaOriginalPathJigsaw)) {
originalCacheMap.putAll(getResourcesImagesFile("classpath:images/jigsaw/original/*.png"));
slidingBlockCacheMap.putAll(getResourcesImagesFile("classpath:images/jigsaw/slidingBlock/*.png"));
} else {
originalCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "original"));
slidingBlockCacheMap.putAll(getImagesFile(captchaOriginalPathJigsaw + File.separator + "slidingBlock"));
}
//点选文字
if (StringUtils.isBlank(captchaOriginalPathClick)) {
picClickCacheMap.putAll(getResourcesImagesFile("classpath:images/pic-click/*.png"));
} 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]));
}
public static BufferedImage getOriginal() {
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.ORIGINAL.getCodeValue());
Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
String s = originalCacheMap.get(strings[randomInt]);
return getBase64StrToImage(s);
}
public static BufferedImage getslidingBlock() {
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.SLIDING_BLOCK.getCodeValue());
Integer randomInt = RandomUtils.getRandomInt(0, strings.length);
String s = slidingBlockCacheMap.get(strings[randomInt]);
return getBase64StrToImage(s);
}
public static BufferedImage getPicClick() {
String[] strings = fileNameMap.get(CaptchaBaseMapEnum.PIC_CLICK.getCodeValue());
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();
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encodeBuffer(bytes).trim();
}
/**
* base64 字符串转图片
*
* @param base64String
* @return
*/
public static BufferedImage getBase64StrToImage(String base64String) {
try {
BASE64Decoder base64Decoder = new BASE64Decoder();
byte[] bytes = base64Decoder.decodeBuffer(base64String);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
return ImageIO.read(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static Map<String, String> getResourcesImagesFile(String path) {
Map<String, String> imgMap = new HashMap<>(16);
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;
}
public static Map<String, String> getImagesFile(String path) {
Map<String, String> imgMap = new HashMap<>(16);
File file = new File(path);
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 (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
});
return imgMap;
}
}
/*
*Copyright © 2018 anji-plus
*安吉加加信息技术有限公司
*http://www.anji-plus.com
*All rights reserved.
*/
package com.zrqx.member.fg.captcha.commons.utils;
import java.util.Random;
import java.util.UUID;
/**
*
* @author lpf
* @date 2020-07-01 13:43
*/
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) {
String ch = hanZi.charAt(new Random().nextInt(hanZi.length())) + "";
return ch;
}
/**
* 随机范围内数字
* @param startNum
* @param endNum
* @return
*/
public static Integer getRandomInt(int startNum, int endNum) {
return new Random().nextInt(endNum-startNum) + startNum;
}
public static void main(String[] args) {
/* for (int i = 0; i < 100; i++) {
int randomNum = RandomUtils.getRandomInt(1, 4);
System.out.println(randomNum);
}*/
}
}
package com.zrqx.member.fg.captcha.commons.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lpf
* @date 2020-06-18
*/
@Data
@ApiModel(value = "BlockPuzzleVo", description = "滑块验证码vo")
public class BlockPuzzleVo {
@ApiModelProperty("原生图片base64")
private String originalImageBase64;
@ApiModelProperty("滑块图片base64")
private String jigsawImageBase64;
}
package com.zrqx.member.fg.captcha.commons.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lpf
* @date 2020-06-16
*/
@Data
@ApiModel(value = "CaptchaVO", description = "验证码vo")
public class CaptchaVO {
@ApiModelProperty("验证码id")
private String uuid;
@ApiModelProperty("字母与数字验证码vo")
private CodeVo codeVo;
@ApiModelProperty("滑块验证码vo")
private BlockPuzzleVo blockPuzzleVo;
}
package com.zrqx.member.fg.captcha.commons.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author lpf
* @date 2020-06-16
*/
@Data
@ApiModel(value = "CodeVo", description = "字母与数字验证码vo")
public class CodeVo {
@ApiModelProperty("验证码图片,base64")
private String img;
}
package com.zrqx.member.fg.captcha.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.components.captcha.service.BlockPuzzleCaptchaValidateServiceImpl;
import com.zrqx.core.constant.member.MemberRequestPath;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.exception.ValidateException;
import com.zrqx.core.util.datatype.StringUtils;
import com.zrqx.core.util.response.CallBack;
import com.zrqx.core.util.spring.SpringContextUtils;
import com.zrqx.member.fg.captcha.commons.vo.CaptchaVO;
import com.zrqx.member.fg.captcha.service.CaptchaService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
/**
* @author lpf
* @date 2020-06-16
*/
@RestController
@RequestMapping(MemberRequestPath.FG + "/captcha")
@Api(description = "验证码接口")
public class CaptchaController {
private static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
@Autowired
@Qualifier("blockPuzzleCaptchaServiceImpl")
private CaptchaService blockPuzzleCaptchaService;
@ApiOperation("获取普通验证码:滑块验证码")
@GetMapping("/block-puzzle")
public CallBack<CaptchaVO> getBlockPuzzle() {
log.info("获取验证码start");
CaptchaVO vo = blockPuzzleCaptchaService.get(null);
log.info("获取验证码end,{}",vo);
return CallBack.success(vo);
}
}
package com.zrqx.member.fg.captcha.listeners;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.zrqx.member.fg.captcha.commons.utils.ImageUtils;
/**
* ServletContext监听
* @author lpf
* @date 2020-06-17
*/
@Component
@WebListener
public class CaptchaServletContextListener implements ServletContextListener {
private static final Logger log = LoggerFactory.getLogger(CaptchaServletContextListener.class);
@Value("${captcha.captchaOriginalPath.jigsaw:}")
private String captchaOriginalPathJigsaw;
@Value("${captcha.captchaOriginalPath.pic-click:}")
private String captchaOriginalPathClick;
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("ServletContext创建监听start");
//初始化底图
ImageUtils.cacheImage(captchaOriginalPathJigsaw, captchaOriginalPathClick);
log.info("--->>>初始化验证码底图<<<---");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("ServletContext销毁监听start");
}
}
package com.zrqx.member.fg.captcha.service;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.components.captcha.service.CaptchaValidateService;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.enums.interfaces.EnumsBindBean;
import com.zrqx.member.fg.captcha.commons.vo.CaptchaVO;
/**
* 验证码接口
* @author lpf
* @date 2020-06-16 16:02
*/
public interface CaptchaService extends EnumsBindBean<CaptchaTypeEnum>, CaptchaValidateService{
/**
* 获取验证码
* @param form
* @return
*/
CaptchaVO get(CaptchaForm form);
}
package com.zrqx.member.fg.captcha.service.impl;
import com.zrqx.core.components.captcha.form.CaptchaForm;
import com.zrqx.core.components.captcha.service.CodeCaptchaValidateServiceImpl;
import com.zrqx.core.enums.captcha.CaptchaTypeEnum;
import com.zrqx.core.exception.BaseException;
import com.zrqx.core.util.datatype.UUIDUtil;
import com.zrqx.member.fg.captcha.commons.vo.CaptchaVO;
import com.zrqx.member.fg.captcha.commons.vo.CodeVo;
import com.zrqx.member.fg.captcha.service.CaptchaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import sun.misc.BASE64Encoder;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
* @author lpf
* @date 2020-06-16
*/
@Service
public class CodeServiceImpl extends CodeCaptchaValidateServiceImpl implements CaptchaService {
private static final Logger log = LoggerFactory.getLogger(CodeServiceImpl.class);
/** 验证码字符集 */
private final char[] chars = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
/** 字符数量 */
private final int SIZE = 4;
/** 干扰线数量 */
private final int LINES = 5;
/** 宽度 */
private final int WIDTH = 80;
/** 高度 */
private final int HEIGHT = 40;
/** 字体大小 */
private final int FONT_SIZE = 30;
@Override
public List<CaptchaTypeEnum> getEnums() {
return Arrays.asList(CaptchaTypeEnum.CODE);
}
@Override
public CaptchaVO get(CaptchaForm form) {
Object[] objs = this.createImage();
BufferedImage image = (BufferedImage)objs[1];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ImageIO.write(image, "png", baos);
} catch (IOException e) {
throw new BaseException("生成验证码失败", e);
}
BASE64Encoder encoder = new BASE64Encoder();
byte[] bytes = baos.toByteArray();
String pngBase64 = encoder.encodeBuffer(bytes).trim();
pngBase64 = pngBase64.replaceAll("\n", "").replaceAll("\r", "");
CaptchaVO vo = new CaptchaVO();
String uuid = UUIDUtil.getUUID();
vo.setUuid(uuid);
CodeVo codeVo = new CodeVo();
codeVo.setImg("data:image/png;base64," + pngBase64);
vo.setCodeVo(codeVo);
String key = String.format(REDIS_CAPTCHA_KEY, uuid);
String value = objs[0].toString();
log.info("缓存验证码:key:{},value:{}",key, value);
cacheService.set(key, value, EXPIRESIN_SECONDS);
return vo;
}
/**
* 生成随机验证码及图片
* Object[0]:验证码字符串;
* Object[1]:验证码图片。
*/
public Object[] createImage() {
StringBuffer sb = new StringBuffer();
// 1.创建空白图片
BufferedImage image = new BufferedImage(
WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
// 2.获取图片画笔
Graphics graphic = image.getGraphics();
// 3.设置背景颜色
graphic.setColor(Color.WHITE);
// 4.绘制矩形背景
graphic.fillRect(0, 0, WIDTH, HEIGHT);
// 5.画随机字符
Random ran = new Random();
for (int i = 0; i <SIZE; i++) {
// 取随机字符索引
int n = ran.nextInt(chars.length);
// 随机设置画笔颜色
graphic.setColor(getRandomColor());
// 设置字体大小
graphic.setFont(new Font(
null, Font.BOLD + Font.ITALIC, FONT_SIZE));
// 画字符
graphic.drawString(
chars[n] + "", i * WIDTH / SIZE, HEIGHT*2/3);
// 记录字符
sb.append(chars[n]);
}
// 6.画干扰线
for (int i = 0; i < LINES; i++) {
// 设置随机颜色
graphic.setColor(getRandomColor());
// 随机画线
graphic.drawLine(ran.nextInt(WIDTH), ran.nextInt(HEIGHT),
ran.nextInt(WIDTH), ran.nextInt(HEIGHT));
}
// 7.返回验证码和图片
return new Object[]{sb.toString(), image};
}
/**
* 随机取色
*/
public Color getRandomColor() {
Random ran = new Random();
Color color = new Color(ran.nextInt(256),
ran.nextInt(256), ran.nextInt(256));
return color;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论