Commit 07ffd8ee by 罗长华

删除现有签名类

parent 2fddcc3c
package io.geekidea.springbootplus.framework.signature;
import lombok.extern.slf4j.Slf4j;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.google.common.collect.Lists;
/**
* 签名拦截器
* @Author linux
* @Date 2021年01月20日 04:21:30
* @Version 1.0
*/
//@Order(2)
//@Aspect
//@Component
@Slf4j
public class ControllerValidatorAspect implements InitializingBean {
private static final String REQUEST_URL_OPEN = "request-url-open";
/**
* 同一个请求多长时间内有效
*/
@Value("${signature.expireTime:600000}")
private Long expireTime;
/**
* 同一个nonce 请求多长时间内不允许重复请求
*/
@Value("${signature.resubmitDuration:60000}")
private Long resubmitDuration;
/**
* appSecret
*/
@Value("${signature.appSecret}")
private String appSecret;
@Autowired
private RedisTemplate<Object, Object> redisTemplate;
@Around("@annotation(io.geekidea.springbootplus.framework.signature.Signature) " +
"&& (@annotation(org.springframework.web.bind.annotation.RequestMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.GetMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.PostMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.DeleteMapping) " +
"|| @annotation(org.springframework.web.bind.annotation.PatchMapping))"
)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {//NOSONAR
HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
//如果不是开放的URL, 进行签名校验
if (Objects.isNull(request.getHeader(REQUEST_URL_OPEN))) {
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
Signature signature = AnnotationUtils.findAnnotation(method, Signature.class);
//获取header中的相关参数
SignatureHeaders signatureHeaders = generateSignatureHeaders(signature, request);
//客户端签名
String clientSignature = signatureHeaders.getSignature();
//获取到header中的拼接结果
String headersToSplice = SignatureUtils.toSplice(signatureHeaders);
//服务端签名
List<String> allSplice = generateAllSplice(method, pjp.getArgs(), headersToSplice);
String serverSignature = SignatureUtils.signature(allSplice.toArray(new String[]{}), signatureHeaders.getAppsecret());
if (!clientSignature.equals(serverSignature)) {
if (log.isErrorEnabled()) {
log.error(String.format("签名不一致... clientSignature=%s, serverSignature=%s", clientSignature,
serverSignature));
}
throw new SignatureException("signature error");
}
// SignatureContext.setSignatureHeaders(signatureHeaders);
log.info("签名验证通过, 相关信息: " + signatureHeaders);
}
try {
return pjp.proceed();
} catch (Throwable e) {
//NOSONAR
throw e;
}
}
/**
* 根据request 中 header值生成SignatureHeaders实体
* @Author linux
* @Date 2021年02月07日 10:50:14
* @param signature
* @param request
* @Return
*/
private SignatureHeaders generateSignatureHeaders(Signature signature, HttpServletRequest request) throws Exception {//NOSONAR
// 筛选头信息
Map<String, Object> headerMap = Collections.list(request.getHeaderNames())
.stream()
.filter(SignatureHeaders.SIGNATURE_HEADER_SET::contains)
.collect(Collectors.toMap(headerName -> headerName.replaceAll("-", "."), request::getHeader));
// 自定义ConfigurationProperty源信息
ConfigurationPropertySource sources = new MapConfigurationPropertySource(headerMap);
// 创建Binder绑定类
Binder binder = new Binder(sources);
// 绑定属性
SignatureHeaders signatureHeaders = binder.bind("can.signature", Bindable.of(SignatureHeaders.class)).get();
// 检验参数合法性
Optional<String> result = ValidatorUtils.validateAll(signatureHeaders);
if (result.isPresent() && StringUtils.isNotBlank(result.get())) {
throw new SignatureException("WMH5000", result.get());
}
if (StringUtils.isBlank(appSecret)) {
log.error("未设置app secret");
throw new SignatureException("WMH5002");
}
//其他合法性校验
Long now = System.currentTimeMillis();
Long requestTimestamp = Long.parseLong(signatureHeaders.getTimestamp());
if ((now - requestTimestamp) > expireTime) {
String errMsg = "请求时间超过规定范围时间, signature=" + signatureHeaders.getSignature();
if (log.isErrorEnabled()) {
log.error(errMsg);
}
throw new SignatureException("WMH5000", errMsg);
}
String nonce = signatureHeaders.getNonce();
if (nonce.length() < 10) {
String errMsg = "6, nonce=" + nonce;
log.error(errMsg);
throw new SignatureException("WMH5000", errMsg);
}
if (!signature.resubmit()) {
String existNonce = redisTemplate.opsForValue().get(nonce).toString();
if (StringUtils.isBlank(existNonce)) {
redisTemplate.opsForValue().set(nonce, nonce);
redisTemplate.expire(nonce, (int) TimeUnit.MILLISECONDS.toSeconds(resubmitDuration), TimeUnit.SECONDS);
} else {
String errMsg = "不允许重复请求, nonce=" + nonce;
log.error(errMsg);
throw new SignatureException("WMH5000", errMsg);
}
}
signatureHeaders.setAppsecret(appSecret);
return signatureHeaders;
}
/**
* 生成header中的参数,mehtod中的参数的拼接
* @Author linux
* @Date 2021年02月07日 10:53:18
* @param method
* @param args
* @param headersToSplice
* @Return
*/
private List<String> generateAllSplice(Method method, Object[] args, String headersToSplice) {
List<String> pathVariables = Lists.newArrayList();
List<String> requestParams = Lists.newArrayList();
String beanParams = StringUtils.EMPTY;
for (int i = 0; i < method.getParameterCount(); ++i) {
MethodParameter mp = new MethodParameter(method, i);
boolean findSignature = false;
for (Annotation anno : mp.getParameterAnnotations()) {
if (anno instanceof PathVariable) {
if (!Objects.isNull(args[i])) {
pathVariables.add(args[i].toString());
}
findSignature = true;
} else if (anno instanceof RequestParam) {
RequestParam rp = (RequestParam) anno;
String name = mp.getParameterName();
if (StringUtils.isNotBlank(rp.name())) {
name = rp.name();
}
if (!Objects.isNull(args[i])) {
List<String> values = Lists.newArrayList();
if (args[i].getClass().isArray()) {
//数组
for (int j = 0; j < Array.getLength(args[i]); ++j) {
values.add(Array.get(args[i], j).toString());
}
} else if (ClassUtils.isAssignable(Collection.class, args[i].getClass())) {
//集合
for (Object o : (Collection<?>) args[i]) {
values.add(o.toString());
}
} else {
//单个值
values.add(args[i].toString());
}
values.sort(Comparator.naturalOrder());
requestParams.add(name + "=" + StringUtils.join(values));
}
findSignature = true;
} else if (anno instanceof RequestBody || anno instanceof ModelAttribute) {
beanParams = SignatureUtils.toSplice(args[i]);
findSignature = true;
}
if (findSignature) {
break;
}
}
if (!findSignature) {
log.info(String.format("签名未识别的注解, method=%s, parameter=%s, annotations=%s", method.getName(),
mp.getParameterName(), StringUtils.join(mp.getMethodAnnotations())));
}
}
List<String> toSplices = Lists.newArrayList();
toSplices.add(headersToSplice);
toSplices.addAll(pathVariables);
requestParams.sort(Comparator.naturalOrder());
toSplices.addAll(requestParams);
toSplices.add(beanParams);
return toSplices;
}
@Override
public void afterPropertiesSet() throws Exception {
if (StringUtils.isBlank(appSecret)) {
log.error("app secret is blank");
}
}
}
package io.geekidea.springbootplus.framework.signature;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 签名注解
* 指定哪些接口或者哪些实体需要签名
* @Author linux
* @Date 2021年01月20日 08:32:00
* @Version 1.0
*/
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Documented
public @interface Signature {
/**
* 按照order值排序
*/
String ORDER_SORT = "ORDER_SORT";
/**
* 字典序排序
*/
String ALPHA_SORT = "ALPHA_SORT";
boolean resubmit() default true;
String sort() default Signature.ALPHA_SORT;
}
package io.geekidea.springbootplus.framework.signature;
/**
*
* @Author linux
* @Date 2021年01月20日 18:00
* @Version 1.0
*/
public class SignatureException extends RuntimeException {
/**
*
* @Author linux
* @Date 2021年01月20日 06:01:17
* @Version 1.0
*/
public SignatureException(String code) {
super(code);
}
public SignatureException(String code, String message) {
super(code + ":" + message);
}
}
package io.geekidea.springbootplus.framework.signature;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* 签名字段
* 指定哪些字段需要签名
* @Author linux
* @Date 2021年01月20日 08:43:28
* @Version 1.0
*/
@Target({FIELD})
@Retention(RUNTIME)
@Documented
public @interface SignatureField {
//签名顺序
int order() default 0;
//字段name自定义值
String customName() default "";
//字段value自定义值
String customValue() default "";
}
package io.geekidea.springbootplus.framework.signature;
import lombok.Data;
import lombok.ToString;
import java.util.Set;
import javax.validation.constraints.NotBlank;
import org.springframework.boot.context.properties.ConfigurationProperties;
import com.google.common.collect.Sets;
/**
* 签名头信息类
* @Author linux
* @Date 2021年01月20日 16:28
* @Version 1.0
*/
@ConfigurationProperties(prefix = "can.signature")
@Signature
@Data
@ToString
public class SignatureHeaders {
public static final String SIGNATURE_HEADERS_PREFIX = "can-signature-";
public static final Set<String> SIGNATURE_HEADER_SET = Sets.newHashSet();
private static final String HEADER_APP_ID = SIGNATURE_HEADERS_PREFIX + "appid";
private static final String HEADER_TIMESTAMP = SIGNATURE_HEADERS_PREFIX + "timestamp";
private static final String HEADER_NONCE = SIGNATURE_HEADERS_PREFIX + "nonce";
private static final String HEADER_SIGNATURE = SIGNATURE_HEADERS_PREFIX + "signature";
static {
SIGNATURE_HEADER_SET.add(HEADER_APP_ID);
SIGNATURE_HEADER_SET.add(HEADER_TIMESTAMP);
SIGNATURE_HEADER_SET.add(HEADER_NONCE);
SIGNATURE_HEADER_SET.add(HEADER_SIGNATURE);
}
/**
* 线下分配的值
* 客户端和服务端各自保存appId对应的appSecret
*/
@NotBlank(message = "Header中缺少" + HEADER_APP_ID)
@SignatureField
private String appid;
/**
* 线下分配的值
* 客户端和服务端各自保存,与appId对应
*/
@SignatureField
private String appsecret;
/**
* 时间戳,单位: ms
*/
@NotBlank(message = "Header中缺少" + HEADER_TIMESTAMP)
@SignatureField
private String timestamp;
/**
* 流水号【防止重复提交】; (备注:针对查询接口,流水号只用于日志落地,便于后期日志核查; 针对办理类接口需校验流水号在有效期内的唯一性,以避免重复请求)
*/
@NotBlank(message = "Header中缺少" + HEADER_NONCE)
@SignatureField
private String nonce;
/**
* 签名
*/
@NotBlank(message = "Header中缺少" + HEADER_SIGNATURE)
private String signature;
}
package io.geekidea.springbootplus.framework.signature;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* Jwt参数配置
* @Author linux
* @Date 2020年12月28日 11:25:17
* @Version 1.0
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "signature")
public class SignatureProperties {
/**
* appSecret
*/
private String appId;
/**
* appSecret
*/
private String appSecret;
/**
* 同一个nonce 请求多长时间内不允许重复请求 单位:秒
*/
private Long expireTime;
/**
* 同一个请求多长时间内有效 单位:秒
*/
private Long resubmitDuration;
}
package io.geekidea.springbootplus.framework.signature;
import lombok.extern.slf4j.Slf4j;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import com.google.common.collect.Lists;
/**
*
* @Author linux
* @Date 2021年01月20日 16:22
* @Version 1.0
*/
@Slf4j
public class SignatureUtils {
private static final byte XOR_TOKEN = (byte) 0xFF;
private static final String NOT_FOUND = "$_$";
private static final String DELIMETER = "^_^";
/**
* 客户端调用
* @param signatureHeaders header中需要的参数
* @param pathParams @PathVariable 需要的参数
* @param requestParamMap @RequestParam需要的参数
* @param entity @ModelAttribute 或者 @RequestBody需要的参数
*/
public static String signature(SignatureHeaders signatureHeaders, List<String> pathParams, Map<String, Object> requestParamMap, Object entity) {
List<String> requestParams = Collections.emptyList();
List<String> pathVariables = Collections.emptyList();
String beanParams = StringUtils.EMPTY;
if (!CollectionUtils.isEmpty(pathParams)) {
pathVariables = pathParams;
}
if (!CollectionUtils.isEmpty(requestParamMap)) {
requestParams = new ArrayList<>();
for (Map.Entry<String, Object> entry : requestParamMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
List<String> values = Lists.newArrayList();
if (value.getClass().isArray()) {
//数组
for (int j = 0; j < Array.getLength(value); ++j) {
values.add(Array.get(value, j).toString());
}
} else if (ClassUtils.isAssignable(Collection.class, value.getClass())) {
//集合
for (Object o : (Collection<?>) value) {
values.add(o.toString());
}
} else {
//单个值
values.add(value.toString());
}
values.sort(Comparator.naturalOrder());
requestParams.add(key + "=" + StringUtils.join(values));
}
}
if (!Objects.isNull(entity)) {
beanParams = toSplice(entity);
}
String headersToSplice = SignatureUtils.toSplice(signatureHeaders);
List<String> toSplices = Lists.newArrayList();
toSplices.add(headersToSplice);
toSplices.addAll(pathVariables);
requestParams.sort(Comparator.naturalOrder());
toSplices.addAll(requestParams);
toSplices.add(beanParams);
return SignatureUtils.signature(toSplices.toArray(new String[]{}), signatureHeaders.getAppsecret());
}
public static String encode(String text, String appsecret) {
byte token = (byte) (appsecret.hashCode() & XOR_TOKEN);
byte[] tb = text.getBytes();
for (int i = 0; i < tb.length; ++i) {
tb[i] ^= token;
}
return Base64.getEncoder().encodeToString(tb);
}
public static String decode(String text, String appsecret) {
byte token = (byte) (appsecret.hashCode() & XOR_TOKEN);
byte[] tb = Base64.getDecoder().decode(text);
for (int i = 0; i < tb.length; ++i) {
tb[i] ^= token;
}
return new String(tb);
}
/** * 生成签名1 */
public static String signature(String[] args, String appsecret) {
String splice = StringUtils.join(args, DELIMETER);
System.out.println("拼接结果: " + splice);
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, appsecret).hmacHex(splice);
}
/** * 生成签名2 */
public static String signature(Object object, String appsecret) {
if (Objects.isNull(object)) {
return StringUtils.EMPTY;
}
String splice = toSplice(object);
System.out.println("拼接结果: " + splice);
if (StringUtils.isBlank(splice)) {
return splice;
}
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, appsecret).hmacHex(splice);
}
/**
* 生成所有注有 SignatureField属性 key=value的 拼接 */
public static String toSplice(Object object) {
if (Objects.isNull(object)) {
return StringUtils.EMPTY;
}
if (isAnnotated(object.getClass(), Signature.class)) {
Signature sg = findAnnotation(object.getClass(), Signature.class);
if (Signature.ORDER_SORT.equals(sg.sort())) {
return orderSignature(object);
}
return alphaSignature(object);
}
return toString(object);
}
/**
* 生成唯一nonce随机数
* 仅供参考,不一定非得使用该方法
*/
public static String generateNonce() {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, UUID.randomUUID().toString()).hmacHex(RandomStringUtils.random(10, true, true));
}
private static String alphaSignature(Object object) {
StringBuilder result = new StringBuilder();
Map<String, String> map = new TreeMap<>();
for (Field field : getAllFields(object.getClass())) {
if (field.isAnnotationPresent(SignatureField.class)) {
field.setAccessible(true);
try {
if (isAnnotated(field.getType(), Signature.class)) {
if (!Objects.isNull(field.get(object))) {
map.put(field.getName(), toSplice(field.get(object)));
}
} else {
SignatureField sgf = field.getAnnotation(SignatureField.class);
if (StringUtils.isNotEmpty(sgf.customValue()) || !Objects.isNull(field.get(object))) {
map.put(StringUtils.isNotBlank(sgf.customName()) ? sgf.customName() : field.getName()
, StringUtils.isNotEmpty(sgf.customValue()) ? sgf.customValue() : toString(field.get(object)));
}
}
} catch (Exception e) {
log.error("签名拼接(alphaSignature)异常", e);
}
}
}
for (Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, String> entry = iterator.next();
result.append(entry.getKey()).append("=").append(entry.getValue());
if (iterator.hasNext()) {
result.append(DELIMETER);
}
}
return result.toString();
}
private static String orderSignature(Object object) {
StringBuilder result = new StringBuilder();
Set<OrderNode> set = new HashSet<>(16);
for (Field field : getAllFields(object.getClass())) {
if (field.isAnnotationPresent(SignatureField.class)) {
field.setAccessible(true);
SignatureField sgf = field.getAnnotation(SignatureField.class);
try {
if (isAnnotated(field.getType(), Signature.class)) {
if (!Objects.isNull(field.get(object))) {
set.add(new OrderNode(sgf.order(), field.getName(), toSplice(field.get(object))));
}
} else {
if (StringUtils.isNotEmpty(sgf.customValue()) || !Objects.isNull(field.get(object))) {
set.add(new OrderNode(sgf.order()
, StringUtils.isNotBlank(sgf.customName()) ? sgf.customName() : field.getName()
, StringUtils.isNotEmpty(sgf.customValue()) ? sgf.customValue() : toString(field.get(object))));
}
}
} catch (Exception e) {
log.error("签名拼接(orderSignature)异常", e);
}
}
}
for (Iterator<OrderNode> iterator = set.iterator(); iterator.hasNext(); ) {
OrderNode on = iterator.next();
result.append(on.getName()).append("=").append(on.getValue());
if (iterator.hasNext()) {
result.append(DELIMETER);
}
}
return result.toString();
}
private static String toString(Object object) {
Class<?> type = object.getClass();
if (BeanUtils.isSimpleProperty(type)) {
return object.toString();
}
if (type.isArray()) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Array.getLength(object); ++i) {
sb.append(toSplice(Array.get(object, i)));
}
return sb.toString();
}
if (ClassUtils.isAssignable(Collection.class, type)) {
StringBuilder sb = new StringBuilder();
for (Iterator<?> iterator = ((Collection<?>) object).iterator(); iterator.hasNext(); ) {
sb.append(toSplice(iterator.next()));
if (iterator.hasNext()) {
sb.append(DELIMETER);
}
}
return sb.toString();
}
if (ClassUtils.isAssignable(Map.class, type)) {
StringBuilder sb = new StringBuilder();
for (Iterator<? extends Map.Entry<String, ?>> iterator = ((Map<String, ?>) object).entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, ?> entry = iterator.next();
if (Objects.isNull(entry.getValue())) {
continue;
}
sb.append(entry.getKey()).append("=").append(toSplice(entry.getValue()));
if (iterator.hasNext()) {
sb.append(DELIMETER);
}
}
return sb.toString();
}
return NOT_FOUND;
}
private static <A extends Annotation> A findAnnotation(AnnotatedElement element, Class<A> annotationType) {
return element.getAnnotation(annotationType);
}
private static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType) {
return element.isAnnotationPresent(annotationType);
}
public static Set<Field> getAllFields(final Class<?> type) {
Set<Field> result = new HashSet<>(16);
for (Class<?> t : getAllSuperTypes(type)) {
result.addAll(Arrays.asList(t.getDeclaredFields()));
}
return result;
}
private static Set<Class<?>> getAllSuperTypes(final Class<?> type) {
Set<Class<?>> result = new LinkedHashSet<>(16);
if (type != null && !type.equals(Object.class)) {
result.add(type);
for (Class<?> supertype : getSuperTypes(type)) {
result.addAll(getAllSuperTypes(supertype));
}
}
return result;
}
private static Set<Class<?>> getSuperTypes(Class<?> type) {
Set<Class<?>> result = new LinkedHashSet<>();
Class<?> superclass = type.getSuperclass();
Class<?>[] interfaces = type.getInterfaces();
if (superclass != null && !superclass.equals(Object.class)) {
result.add(superclass);
}
if (interfaces.length > 0) {
result.addAll(Arrays.asList(interfaces));
}
return result;
}
private static class OrderNode implements Comparable<OrderNode> {
private int order;
private String name;
private String value;
public OrderNode(int order, String name, String value) {
this.order = order;
this.name = name;
this.value = value;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(OrderNode o) {
if (this.order == o.order) {
return this.name.compareTo(o.name);
}
return this.order - o.order;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return Objects.hash(order, value);
}
}
}
package io.geekidea.springbootplus.framework.signature;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import org.hibernate.validator.HibernateValidator;
/**
*
* @Author linux
* @Date 2021年01月20日 18:18
* @Version 1.0
*/
public class ValidatorUtils {
private final static Validator VALIDATOR_FAST =
Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory().getValidator();
private final static Validator VALIDATOR_ALL =
Validation.byProvider(HibernateValidator.class).configure().failFast(false).buildValidatorFactory().getValidator();
/**
* 校验遇到第一个不合法的字段直接返回不合法字段,后续字段不再校验
* @Time 2020年6月22日 上午11:36:13
* @param <T>
* @param domain
* @return
*/
public static <T> Optional<String> validateFast(T domain) {
Set<ConstraintViolation<T>> validateResult = VALIDATOR_FAST.validate(domain);
if (validateResult.size() > 0) {
System.out.println(validateResult.iterator().next().getPropertyPath() + ":" + validateResult.iterator().next().getMessage());
}
StringBuilder sb = new StringBuilder();
for (Iterator<ConstraintViolation<T>> iterator = validateResult.iterator(); iterator.hasNext(); ) {
sb.append(iterator.next().getMessage());
if (iterator.hasNext()) {
sb.append(" ,");
}
}
return Optional.of(sb.toString());
}
/**
* 校验所有字段并返回不合法字段
* @Time 2020年6月22日 上午11:36:55
* @param <T>
* @param domain
* @return
*/
public static <T> Optional<String> validateAll(T domain) {
Set<ConstraintViolation<T>> validateResult = VALIDATOR_ALL.validate(domain);
if (validateResult.size() > 0) {
for (ConstraintViolation<T> cv : validateResult) {
System.out.println(cv.getPropertyPath() + ":" + cv.getMessage());
}
}
StringBuilder sb = new StringBuilder();
for (Iterator<ConstraintViolation<T>> iterator = validateResult.iterator(); iterator.hasNext(); ) {
sb.append(iterator.next().getMessage());
if (iterator.hasNext()) {
sb.append(" ,");
}
}
return Optional.of(sb.toString());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment