commit
17273b0bc6
|
@ -32,3 +32,6 @@ build/
|
|||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### bak ###
|
||||
*.bak
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
|
||||
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler.ExceptionInfoHolder;
|
||||
|
||||
@Configuration
|
||||
|
@ -12,6 +13,6 @@ public class PlusoneExceptionHandlerConfig {
|
|||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ExceptionInfoHolder exceptionInfoHolder() {
|
||||
return new ExceptionInfoHolder();
|
||||
return new ExceptionInfoHolder(ErrorCodeConsts.DEFAULT_ERROR_CODE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package xyz.zhouxy.plusone.exception.handler;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 处理所有异常的处理器
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@ConditionalOnProperty(prefix = "plusone.exception", name = "handle-all-exception", havingValue = "true")
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class AllExceptionHandler extends BaseExceptionHandler {
|
||||
protected AllExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) {
|
||||
super(exceptionInfoHolder);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<RestfulResult> handleException(Throwable e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return this.buildExceptionResponse(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package xyz.zhouxy.plusone.exception.handler;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler.ExceptionInfoHolder;
|
||||
|
||||
/**
|
||||
* AllExceptionHandlerConfig
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "plusone.exception", name = "handle-all-exception", havingValue = "true")
|
||||
public class AllExceptionHandlerConfig {
|
||||
|
||||
@Bean
|
||||
AllExceptionHandler getAllExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) {
|
||||
return new AllExceptionHandler(exceptionInfoHolder);
|
||||
}
|
||||
}
|
|
@ -55,7 +55,11 @@ public class DefaultExceptionHandler extends BaseExceptionHandler {
|
|||
HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ExceptionHandler({
|
||||
IllegalArgumentException.class,
|
||||
DataAccessException.class,
|
||||
MethodArgumentNotValidException.class
|
||||
})
|
||||
public ResponseEntity<RestfulResult> handleException(Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return buildExceptionResponse(e);
|
||||
|
|
|
@ -38,9 +38,14 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-exception-handler</artifactId>
|
||||
<artifactId>plusone-validator</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy.plusone</groupId>
|
||||
<artifactId>plusone-exception-handler</artifactId>
|
||||
<version>0.0.5-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package xyz.zhouxy.plusone.constant;
|
||||
|
||||
public class ErrorCodeConsts {
|
||||
public static final int DEFAULT_ERROR_CODE = 9999999;
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package xyz.zhouxy.plusone.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* 4040200 - 无效的用户输入
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public class InvalidInputException extends PlusoneException {
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = 7956661913360059670L;
|
||||
|
||||
public static final int ERROR_CODE = 4040200;
|
||||
|
||||
private InvalidInputException(int code, String msg) {
|
||||
super(code, msg);
|
||||
}
|
||||
|
||||
private InvalidInputException(int code, Throwable cause) {
|
||||
super(code, cause);
|
||||
}
|
||||
|
||||
private InvalidInputException(int code, String msg, Throwable cause) {
|
||||
super(code, msg, cause);
|
||||
}
|
||||
|
||||
public InvalidInputException(String msg) {
|
||||
this(ERROR_CODE, msg);
|
||||
}
|
||||
|
||||
public InvalidInputException(Throwable cause) {
|
||||
this(ERROR_CODE, cause);
|
||||
}
|
||||
|
||||
public InvalidInputException(String msg, Throwable cause) {
|
||||
this(ERROR_CODE, msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不支持的 Principal 类型出现时抛出的异常
|
||||
*/
|
||||
public static InvalidInputException unsupportedPrincipalTypeException() {
|
||||
return unsupportedPrincipalTypeException("不支持的 PrincipalType");
|
||||
}
|
||||
|
||||
/**
|
||||
* 不支持的 Principal 类型出现时抛出的异常
|
||||
*/
|
||||
public static InvalidInputException unsupportedPrincipalTypeException(String message) {
|
||||
return new InvalidInputException(4040201, message);
|
||||
}
|
||||
}
|
|
@ -49,12 +49,6 @@
|
|||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
|
|
|
@ -6,9 +6,13 @@ import com.tencentcloudapi.common.profile.ClientProfile;
|
|||
import com.tencentcloudapi.common.profile.HttpProfile;
|
||||
import com.tencentcloudapi.sms.v20210111.SmsClient;
|
||||
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
|
||||
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
|
||||
import xyz.zhouxy.plusone.exception.PlusoneException;
|
||||
|
||||
/**
|
||||
* 使用腾讯 SMS 服务
|
||||
|
@ -52,17 +56,17 @@ public class TencentSmsServiceImpl implements SmsService {
|
|||
* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的 返回的 res 是一个
|
||||
* SendSmsResponse 类的实例,与请求对象对应
|
||||
*/
|
||||
// var res = client.SendSms(req);
|
||||
client.SendSms(req);
|
||||
var res = client.SendSms(req);
|
||||
|
||||
// 输出json格式的字符串回包
|
||||
// System.out.println(SendSmsResponse.toJsonString(res));
|
||||
System.out.println(SendSmsResponse.toJsonString(res));
|
||||
|
||||
// 也可以取出单个值,你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
|
||||
// System.out.println(res.getRequestId());
|
||||
|
||||
} catch (TencentCloudSDKException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* 校验器
|
||||
*
|
||||
* <p>
|
||||
* 可以使用以下方式初始化一个校验器:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* BaseValidator<Integer> validator = new BaseValidator<>() {
|
||||
* {
|
||||
* withRule(value -> Objects.nonNull(value), "value 不能为空");
|
||||
* withRule(value -> (value >= 0 && value <= 500), "value 应在 [0, 500] 内");
|
||||
* }
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 也可以通过继承本类,定义一个校验器(可使用单例模式)。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* 然后通过校验器的 {@link #validate} 方法,或
|
||||
* {@link ValidateUtil#validate(Object, Validator)} 对指定对象进行校验。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* ValidateUtil.validate(255, validator);
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* validator.validate(666);
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see IValidateRequired
|
||||
* @see ValidateUtil
|
||||
* @see Validator
|
||||
*/
|
||||
public abstract class BaseValidator<T> {
|
||||
|
||||
private final List<RuleInfo<T, ?>> rules = new ArrayList<>();
|
||||
|
||||
protected BaseValidator() {
|
||||
}
|
||||
|
||||
protected final void withRule(Predicate<T> rule, String errorMessage) {
|
||||
withRule(rule, () -> new InvalidInputException(errorMessage));
|
||||
}
|
||||
|
||||
protected final <E extends RuntimeException> void withRule(Predicate<T> rule, Supplier<E> exceptionCreator) {
|
||||
withRule(rule, value -> exceptionCreator.get());
|
||||
}
|
||||
|
||||
protected final <E extends RuntimeException> void withRule(Predicate<T> rule, Function<T, E> exceptionCreator) {
|
||||
this.rules.add(new RuleInfo<>(rule, exceptionCreator));
|
||||
}
|
||||
|
||||
public void validate(T obj) {
|
||||
this.rules.forEach(ruleInfo -> ruleInfo.validate(obj));
|
||||
}
|
||||
|
||||
protected static class RuleInfo<T, E extends RuntimeException> {
|
||||
private final Predicate<T> rule;
|
||||
private final Function<T, E> exceptionCreator;
|
||||
|
||||
private RuleInfo(Predicate<T> rule, Function<T, E> exceptionCreator) {
|
||||
this.rule = rule;
|
||||
this.exceptionCreator = exceptionCreator;
|
||||
}
|
||||
|
||||
private void validate(T obj) {
|
||||
if (!rule.test(obj)) {
|
||||
throw exceptionCreator.apply(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator;
|
||||
|
||||
/**
|
||||
* 自带校验方法,校验不通过时直接抛异常。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*
|
||||
* @see ValidateUtil
|
||||
* @see BaseValidator
|
||||
*/
|
||||
public interface IValidateRequired {
|
||||
void validate();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package xyz.zhouxy.plusone.validator;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
|
||||
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class InvalidInputExceptionHandler extends BaseExceptionHandler {
|
||||
|
||||
protected InvalidInputExceptionHandler() {
|
||||
super(new ExceptionInfoHolder(ErrorCodeConsts.DEFAULT_ERROR_CODE));
|
||||
set(InvalidInputException.class, InvalidInputException.ERROR_CODE, "无效的用户输入");
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator;
|
||||
|
||||
/**
|
||||
* 校验工具类
|
||||
* <p>
|
||||
* 对 {@link IValidateRequired} 的实现类对象进行校验
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*
|
||||
* @see BaseValidator
|
||||
* @see Validator
|
||||
* @see IValidateRequired
|
||||
*/
|
||||
public class ValidateUtil {
|
||||
private ValidateUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static void validate(Object obj) {
|
||||
if (obj instanceof IValidateRequired) {
|
||||
((IValidateRequired) obj).validate();
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void validate(T obj, BaseValidator<T> validator) {
|
||||
validator.validate(obj);
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 校验器
|
||||
*
|
||||
* <p>
|
||||
* 可以使用以下方式初始化一个校验器:
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* var validator = new Validator<Integer>()
|
||||
* .addRule(value -> Objects.nonNull(value), "value 不能为空")
|
||||
* .addRule(value -> (value >= 0 && value <= 500), "value 应在 [0, 500] 内");
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* 然后通过校验器的 {@link #validate} 方法,或
|
||||
* {@link ValidateUtil#validate(Object, Validator)} 对指定对象进行校验。
|
||||
* </p>
|
||||
*
|
||||
* <pre>
|
||||
* validator.validate(666);
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* ValidateUtil.validate(255, validator);
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see IValidateRequired
|
||||
* @see ValidateUtil
|
||||
* @see BaseValidator
|
||||
*/
|
||||
public final class Validator<T> extends BaseValidator<T> {
|
||||
public final Validator<T> addRule(final Predicate<T> rule, final String errorMessage) {
|
||||
withRule(rule, errorMessage);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator.validator2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class BaseValidator2<T> {
|
||||
|
||||
private List<ValueValidator<T, ?>> valueValidators = new ArrayList<>();
|
||||
|
||||
protected final <R> ValueValidator<T, R> ruleFor(Function<T, R> getter) {
|
||||
ValueValidator<T, R> validValueHolder = new ValueValidator<>(getter);
|
||||
valueValidators.add(validValueHolder);
|
||||
return validValueHolder;
|
||||
}
|
||||
|
||||
public void validate(T obj) {
|
||||
for (ValueValidator<T, ?> valueValidator : this.valueValidators) {
|
||||
valueValidator.validateProperty(obj);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,379 +0,0 @@
|
|||
package xyz.zhouxy.plusone.validator.validator2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.util.RegexUtil;
|
||||
|
||||
public class ValueValidator<DTO, PROPERTY> {
|
||||
Function<DTO, PROPERTY> getter;
|
||||
List<Consumer<PROPERTY>> rules = new ArrayList<>();
|
||||
|
||||
public ValueValidator(Function<DTO, PROPERTY> getter) {
|
||||
this.getter = getter;
|
||||
}
|
||||
|
||||
private <E extends RuntimeException> void withRule(Predicate<PROPERTY> condition,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> {
|
||||
if (!condition.test(value)) {
|
||||
throw exceptionCreator.apply(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private <E extends RuntimeException> void withRule(Consumer<PROPERTY> rule) {
|
||||
this.rules.add(rule);
|
||||
}
|
||||
|
||||
// ====================
|
||||
// ====== Object ======
|
||||
// ====================
|
||||
|
||||
// ====== notNull =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> notNull() {
|
||||
return notNull("Value could not be null.");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> notNull(String errMsg) {
|
||||
return notNull(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notNull(Supplier<E> exceptionCreator) {
|
||||
return notNull(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notNull(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(Objects::nonNull, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ====== isNull =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isNull(String errMsg) {
|
||||
return isNull(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isNull(Supplier<E> exceptionCreator) {
|
||||
return isNull(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isNull(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(Objects::isNull, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== equals =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> equalsThat(Object that) {
|
||||
return equalsThat(that, value -> new InvalidInputException(String.format("(%s) 必须与 (%s) 相等", value, that)));
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> equalsThat(Object that, String errMsg) {
|
||||
return equalsThat(that, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> equalsThat(
|
||||
Object that, Supplier<E> exceptionCreator) {
|
||||
return equalsThat(that, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> equalsThat(
|
||||
Object that, Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> Objects.equals(value, that), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== state =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> state(Predicate<PROPERTY> condition) {
|
||||
return state(condition, "无效的用户输入");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> state(Predicate<PROPERTY> condition, String errMsg) {
|
||||
return state(condition, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> state(
|
||||
Predicate<PROPERTY> condition,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return state(condition, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> state(
|
||||
Predicate<PROPERTY> condition,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(condition, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// =================
|
||||
// ====== int ======
|
||||
// =================
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> between(int min, int max) {
|
||||
return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max)));
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> between(int min, int max, String errMsg) {
|
||||
return between(min, max, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> between(int min, int max,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return between(min, max, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> between(int min, int max,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> ((int) value >= min && (int) value < max), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ====================
|
||||
// ====== double ======
|
||||
// ====================
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> between(double min, double max) {
|
||||
return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max)));
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> between(double min, double max, String errMsg) {
|
||||
return between(min, max, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> between(double min, double max,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return between(min, max, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> between(double min, double max,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> ((double) value >= min && (double) value < max), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ================================
|
||||
// ====== Collection, String ======
|
||||
// ================================
|
||||
|
||||
// ====== notEmpty =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> notEmpty(String errMsg) {
|
||||
return notEmpty(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notEmpty(Supplier<E> exceptionCreator) {
|
||||
return notEmpty(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notEmpty(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
return !((Collection<?>) value).isEmpty();
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return !((String) value).isEmpty();
|
||||
}
|
||||
return false;
|
||||
}, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ====== isEmpty =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isEmpty(String errMsg) {
|
||||
return isEmpty(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isEmpty(Supplier<E> exceptionCreator) {
|
||||
return isEmpty(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isEmpty(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(value -> {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
if (value instanceof Collection) {
|
||||
return ((Collection<?>) value).isEmpty();
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return ((String) value).isEmpty();
|
||||
}
|
||||
return false;
|
||||
}, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// =====================
|
||||
// ====== boolean ======
|
||||
// =====================
|
||||
|
||||
// ====== isTrue ======
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isTrue() {
|
||||
return isTrue("The value must be true.");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isTrue(String errMsg) {
|
||||
return isTrue(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isTrue(Supplier<E> exceptionCreator) {
|
||||
return isTrue(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isTrue(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(Boolean.TRUE::equals, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ====== isFalse ======
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isFalse() {
|
||||
return isFalse("The value must be false.");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> isFalse(String errMsg) {
|
||||
return isFalse(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isFalse(Supplier<E> exceptionCreator) {
|
||||
return isFalse(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> isFalse(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(Boolean.FALSE::equals, exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ====================
|
||||
// ====== String ======
|
||||
// ====================
|
||||
|
||||
// ===== matches =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> matches(String regex, String errMsg) {
|
||||
return matches(regex, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matches(
|
||||
String regex,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return matches(regex, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matches(
|
||||
String regex,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(input -> RegexUtil.matches((String) input, regex), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== matchesOr =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> matchesOr(String[] regexs, String errMsg) {
|
||||
return matchesOr(regexs, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matchesOr(
|
||||
String[] regexs,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return matchesOr(regexs, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matchesOr(
|
||||
String[] regexs,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(input -> RegexUtil.matchesOr((String) input, regexs), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== matchesAnd =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> matchesAnd(String[] regexs, String errMsg) {
|
||||
return matchesAnd(regexs, convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matchesAnd(
|
||||
String[] regexs,
|
||||
Supplier<E> exceptionCreator) {
|
||||
return matchesAnd(regexs, convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> matchesAnd(
|
||||
String[] regexs,
|
||||
Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(input -> RegexUtil.matchesAnd((String) input, regexs), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== notBlank =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> notBlank() {
|
||||
return notBlank("This String argument must have text; it must not be null, empty, or blank");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> notBlank(String errMsg) {
|
||||
return notBlank(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notBlank(Supplier<E> exceptionCreator) {
|
||||
return notBlank(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> notBlank(Function<PROPERTY, E> exceptionCreator) {
|
||||
withRule(input -> StrUtil.isNotBlank((String) input), exceptionCreator);
|
||||
return this;
|
||||
}
|
||||
|
||||
// ===== email =====
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> email() {
|
||||
return email("The value is not an email address.");
|
||||
}
|
||||
|
||||
public ValueValidator<DTO, PROPERTY> email(String errMsg) {
|
||||
return email(convertExceptionCreator(errMsg));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> email(Supplier<E> exceptionCreator) {
|
||||
return email(convertExceptionCreator(exceptionCreator));
|
||||
}
|
||||
|
||||
public <E extends RuntimeException> ValueValidator<DTO, PROPERTY> email(Function<PROPERTY, E> exceptionCreator) {
|
||||
return matches(RegexConsts.EMAIL, exceptionCreator);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
|
||||
void validateProperty(DTO obj) {
|
||||
PROPERTY value = this.getter.apply(obj);
|
||||
for (var rule : this.rules) {
|
||||
rule.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static <V> Function<V, InvalidInputException> convertExceptionCreator(String errMsg) {
|
||||
return convertExceptionCreator(errMsg);
|
||||
}
|
||||
|
||||
private static <V, E extends RuntimeException> Function<V, E> convertExceptionCreator(
|
||||
Supplier<E> exceptionSupplier) {
|
||||
return value -> exceptionSupplier.get();
|
||||
}
|
||||
}
|
|
@ -32,10 +32,10 @@ class LoginCommandValidator extends BaseValidator2<LoginCommand> {
|
|||
public static final LoginCommandValidator INSTANCE = new LoginCommandValidator();
|
||||
|
||||
private LoginCommandValidator() {
|
||||
ruleFor(loginCommand -> loginCommand.getAccount())
|
||||
ruleFor(LoginCommand::getAccount)
|
||||
.notNull("邮箱地址不能为空")
|
||||
.matchesOr(new String[] { RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE }, value -> new RuntimeException('"' + value + "\" 不是邮箱地址或手机号"));
|
||||
ruleFor(loginCommand -> loginCommand.getPwd())
|
||||
ruleFor(LoginCommand::getPwd)
|
||||
.notNull("密码不能为空")
|
||||
.notEmpty("密码不能为空")
|
||||
.matches(RegexConsts.PASSWORD, "密码格式错误");
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
restart.include.projectcommon=/plusone-[\\w\\.\\-]+\\.jar
|
|
@ -2,11 +2,11 @@ package xyz.zhouxy.plusone.system.application.common.util;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Principal;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
import xyz.zhouxy.plusone.validator.InvalidInputException;
|
||||
|
||||
/**
|
||||
* 根据字面值,判断并生成 {@link Principal} 值对象。
|
||||
|
|
|
@ -3,10 +3,13 @@ package xyz.zhouxy.plusone.system.application.controller;
|
|||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.AccountContextService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
|
@ -31,10 +34,28 @@ public class AccountContextController {
|
|||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
|
||||
@GetMapping("logout")
|
||||
public RestfulResult logout() {
|
||||
service.logout();
|
||||
return RestfulResult.success("注销成功");
|
||||
}
|
||||
|
||||
@GetMapping("menus")
|
||||
public RestfulResult getMenuTree() {
|
||||
adminAuthLogic.checkLogin();
|
||||
var result = service.getMenuTree();
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
|
||||
@PostMapping("changePassword")
|
||||
public RestfulResult changePassword(ChangePasswordCommand command) {
|
||||
service.changePassword(command);
|
||||
return RestfulResult.success("修改成功,请重新登录。");
|
||||
}
|
||||
|
||||
@PostMapping("changePasswordWithoutLogin")
|
||||
public RestfulResult changePasswordWithoutLogin(ChangePasswordWithoutLoginCommand command) {
|
||||
service.changePasswordWithoutLogin(command);
|
||||
return RestfulResult.success("修改成功,请重新登录。");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.AdminLogoutService;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* Admin 账号登出
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("logout")
|
||||
public class AdminLogoutController {
|
||||
|
||||
private final AdminLogoutService service;
|
||||
|
||||
public AdminLogoutController(AdminLogoutService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public RestfulResult execute() {
|
||||
service.execute();
|
||||
return RestfulResult.success("注销成功");
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package xyz.zhouxy.plusone.system.application.exception;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.validator.InvalidInputException;
|
||||
|
||||
public class UnsupportedMenuTypeException extends InvalidInputException {
|
||||
|
||||
|
|
|
@ -6,13 +6,13 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
|||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.DisableServiceException;
|
||||
import cn.dev33.satoken.exception.SameTokenInvalidException;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.dev33.satoken.exception.NotSafeException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.exception.SameTokenInvalidException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
|
|
@ -1,38 +1,102 @@
|
|||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
import xyz.zhouxy.plusone.system.constant.AuthLogic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
|
||||
import xyz.zhouxy.plusone.system.application.query.AccountQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordByOtpCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Account;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Principal;
|
||||
import xyz.zhouxy.plusone.validator.InvalidInputException;
|
||||
|
||||
/**
|
||||
* 账号查询本身相关信息
|
||||
* 账号对当前帐号进行操作
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
public class AccountContextService {
|
||||
|
||||
private final AccountQueries accountQueries;
|
||||
private final MenuManagementService menuManagementService;
|
||||
private final static StpLogic adminAuthLogic = AuthLogic.adminAuthLogic;
|
||||
|
||||
public AccountContextService(AccountQueries accountQueries, MenuManagementService menuManagementService) {
|
||||
this.accountQueries = accountQueries;
|
||||
this.menuManagementService = menuManagementService;
|
||||
}
|
||||
@Resource
|
||||
private AccountQueries accountQueries;
|
||||
@Resource
|
||||
private MenuManagementService menuManagementService;
|
||||
@Resource
|
||||
private AccountRepository accountRepository;
|
||||
@Resource
|
||||
private MailAndSmsVerifyService mailAndSmsVerifyService;
|
||||
|
||||
public AccountDetails getAccountInfo() {
|
||||
adminAuthLogic.checkLogin();
|
||||
long accountId = adminAuthLogic.getLoginIdAsLong();
|
||||
return accountQueries.queryAccountDetails(accountId);
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.logout();
|
||||
}
|
||||
|
||||
public List<MenuViewObject> getMenuTree() {
|
||||
adminAuthLogic.checkLogin();
|
||||
long accountId = adminAuthLogic.getLoginIdAsLong();
|
||||
return menuManagementService.queryByAccountId(accountId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void changePassword(ChangePasswordCommand command) {
|
||||
adminAuthLogic.checkLogin();
|
||||
Account account = accountRepository.find(adminAuthLogic.getLoginIdAsLong());
|
||||
account.checkPassword(command.getPassword());
|
||||
account.changePassword(command.getNewPassword(), command.getPasswordConfirmation());
|
||||
accountRepository.save(account);
|
||||
adminAuthLogic.logout();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void changePasswordWithoutLogin(ChangePasswordWithoutLoginCommand command) {
|
||||
String principal = command.getAccount();
|
||||
Principal emailOrMobilePhone = PrincipalUtil.getEmailOrMobilePhone(principal);
|
||||
|
||||
Account account = emailOrMobilePhone instanceof Email
|
||||
? accountRepository.findByEmail((Email) emailOrMobilePhone)
|
||||
: accountRepository.findByMobilePhone((MobilePhone) emailOrMobilePhone);
|
||||
account.checkPassword(command.getOldPassword());
|
||||
account.changePassword(command.getNewPassword(), command.getPasswordConfirmation());
|
||||
accountRepository.save(account);
|
||||
adminAuthLogic.logout();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void changePasswordByOtp(ChangePasswordByOtpCommand command) {
|
||||
|
||||
var principal = command.getAccount();
|
||||
Account account = switch (command.getPrincipalType()) {
|
||||
case EMAIL -> accountRepository.findByEmail(Email.of(principal));
|
||||
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal));
|
||||
default -> throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号");
|
||||
};
|
||||
Assert.notNull(account, () -> AccountLoginException.accountNotExistException());
|
||||
|
||||
mailAndSmsVerifyService.checkOtp(principal, command.getOtp());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
|
||||
|
@ -17,8 +17,8 @@ import xyz.zhouxy.plusone.system.domain.model.account.Account;
|
|||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Principal;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
import xyz.zhouxy.plusone.validator.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.validator.ValidateDto;
|
||||
|
||||
/**
|
||||
|
@ -43,62 +43,45 @@ public class AdminLoginService {
|
|||
|
||||
@ValidateDto
|
||||
public LoginInfoViewObject loginByPassword(LoginByPasswordCommand command) {
|
||||
Principal principal = PrincipalUtil.getPrincipal(command.getPrincipal());
|
||||
Account account;
|
||||
if (principal instanceof Email) {
|
||||
account = accountRepository.findByEmail((Email) principal);
|
||||
} else if (principal instanceof MobilePhone) {
|
||||
account = accountRepository.findByMobilePhone((MobilePhone) principal);
|
||||
} else {
|
||||
account = accountRepository.findByUsername((Username) principal);
|
||||
}
|
||||
var principal = command.getPrincipal();
|
||||
Account account = switch (command.getPrincipalType()) {
|
||||
case USERNAME -> accountRepository.findByUsername(Username.of(principal));
|
||||
case EMAIL -> accountRepository.findByEmail(Email.of(principal));
|
||||
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal));
|
||||
};
|
||||
Assert.notNull(account, () -> AccountLoginException.accountNotExistException());
|
||||
var isPasswordCorrect = account.checkPassword(command.getPassword());
|
||||
Assert.isTrue(isPasswordCorrect, () -> AccountLoginException.passwordErrorException());
|
||||
|
||||
if (account == null) {
|
||||
throw AccountLoginException.accountNotExistException();
|
||||
}
|
||||
@SuppressWarnings("null")
|
||||
boolean isPasswordCorrect = account.checkPassword(command.getPassword());
|
||||
if (!isPasswordCorrect) {
|
||||
throw AccountLoginException.passwordErrorException();
|
||||
}
|
||||
adminAuthLogic.login(account.getId().orElseThrow(), command.isRememberMe());
|
||||
|
||||
var accountDetails = accountQueries.queryAccountDetails(account.getId().orElseThrow());
|
||||
return LoginInfoViewObject.of(adminAuthLogic.getTokenValue(), accountDetails);
|
||||
}
|
||||
|
||||
@ValidateDto
|
||||
public LoginInfoViewObject loginByOtp(LoginByOtpCommand command) {
|
||||
String principal = command.getPrincipal();
|
||||
PrincipalType principalType = PrincipalUtil.getPrincipalType(principal);
|
||||
String otp = command.getOtp();
|
||||
boolean rememberMe = command.isRememberMe();
|
||||
var principal = command.getPrincipal();
|
||||
Account account = switch (command.getPrincipalType()) {
|
||||
case EMAIL -> accountRepository.findByEmail(Email.of(principal));
|
||||
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal));
|
||||
default -> throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号");
|
||||
};
|
||||
Assert.notNull(account, () -> AccountLoginException.accountNotExistException());
|
||||
|
||||
Account account;
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
account = accountRepository.findByEmail(Email.of(principal));
|
||||
} else if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
account = accountRepository.findByMobilePhone(MobilePhone.of(principal));
|
||||
} else {
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号");
|
||||
}
|
||||
mailAndSmsVerifyService.checkOtp(principal, command.getOtp());
|
||||
|
||||
if (account == null) {
|
||||
throw AccountLoginException.accountNotExistException();
|
||||
}
|
||||
mailAndSmsVerifyService.checkOtp(principal, otp);
|
||||
adminAuthLogic.login(account.getId().orElseThrow(), rememberMe);
|
||||
adminAuthLogic.login(account.getId().orElseThrow(), command.isRememberMe());
|
||||
|
||||
var accountDetails = accountQueries.queryAccountDetails(account.getId().orElseThrow());
|
||||
return LoginInfoViewObject.of(adminAuthLogic.getTokenValue(), accountDetails);
|
||||
}
|
||||
|
||||
public void sendOtp(String principal) {
|
||||
Principal emailOrMobilePhone = PrincipalUtil.getEmailOrMobilePhone(principal);
|
||||
if (emailOrMobilePhone instanceof Email) {
|
||||
mailAndSmsVerifyService.sendOtpToEmail((Email) emailOrMobilePhone);
|
||||
PrincipalType principalType = PrincipalUtil.getPrincipalType(principal);
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
mailAndSmsVerifyService.sendOtpToEmail(Email.of(principal));
|
||||
} else {
|
||||
mailAndSmsVerifyService.sendOtpToMobilePhone((MobilePhone) emailOrMobilePhone);
|
||||
mailAndSmsVerifyService.sendOtpToMobilePhone(MobilePhone.of(principal));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Admin 账号登出
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
public class AdminLogoutService {
|
||||
|
||||
public void execute() {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.logout();
|
||||
}
|
||||
}
|
|
@ -107,7 +107,7 @@ public class MailAndSmsVerifyService {
|
|||
}
|
||||
|
||||
private static String generateCode() {
|
||||
return RandomUtil.randomString(CODE_LENGTH);
|
||||
return RandomUtil.randomString(RandomUtil.BASE_NUMBER, CODE_LENGTH);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import java.util.Set;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
|
||||
|
@ -18,6 +17,7 @@ import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
|||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Password;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
import xyz.zhouxy.plusone.validator.InvalidInputException;
|
||||
|
||||
/**
|
||||
* 注册账号服务
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
|
||||
@Data
|
||||
public class ChangePasswordByOtpCommand {
|
||||
String account;
|
||||
String otp;
|
||||
PrincipalType principalType;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
@Data
|
||||
public class ChangePasswordCommand implements ICommand {
|
||||
private String password;
|
||||
private String newPassword;
|
||||
private String passwordConfirmation;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
@Data
|
||||
public class ChangePasswordWithoutLoginCommand implements ICommand {
|
||||
private String account;
|
||||
private String oldPassword;
|
||||
private String newPassword;
|
||||
private String passwordConfirmation;
|
||||
}
|
|
@ -2,6 +2,7 @@ package xyz.zhouxy.plusone.system.application.service.command;
|
|||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
|
||||
/**
|
||||
* 登录命令
|
||||
|
@ -14,6 +15,7 @@ public class LoginByOtpCommand implements ICommand {
|
|||
String principal; // 邮箱地址 / 手机号
|
||||
String otp; // 密码
|
||||
boolean rememberMe; // 记住我
|
||||
PrincipalType principalType;
|
||||
|
||||
// 进入登陆界面时或刷新验证码时,前端发送图形验证码的请求,后端生成 captcha 并暂存到 redis 中,key 为 UUID,将图形和 uuid 响应给前端。
|
||||
// String uuid; // 校验码的 key
|
||||
|
|
|
@ -2,6 +2,7 @@ package xyz.zhouxy.plusone.system.application.service.command;
|
|||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
|
||||
/**
|
||||
* 登录命令
|
||||
|
@ -14,6 +15,7 @@ public class LoginByPasswordCommand implements ICommand {
|
|||
String principal; // 用户名 / 邮箱地址 / 手机号
|
||||
String password; // 密码
|
||||
boolean rememberMe; // 记住我
|
||||
PrincipalType principalType;
|
||||
|
||||
// 进入登陆界面时或刷新验证码时,前端发送图形验证码的请求,后端生成 captcha 并暂存到 redis 中,key 为 UUID,将图形和 uuid 响应给前端。
|
||||
// String uuid; // 校验码的 key
|
||||
|
|
|
@ -4,6 +4,7 @@ import javax.annotation.Nonnull;
|
|||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
|
||||
import xyz.zhouxy.plusone.exception.PlusoneException;
|
||||
|
||||
/**
|
||||
|
@ -30,7 +31,7 @@ public final class PasswordUtil {
|
|||
+ salt.substring(1);
|
||||
String sha512Hex = DigestUtil.sha512Hex(passwordWithSalt);
|
||||
if (sha512Hex == null) {
|
||||
throw new PlusoneException(9999999, "未知错误:哈希加密失败!");
|
||||
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:哈希加密失败!");
|
||||
}
|
||||
return sha512Hex;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@ import java.util.HashSet;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
@ -115,7 +113,7 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
|
|||
addDomainEvent(new AccountRolesBound(this));
|
||||
}
|
||||
|
||||
public boolean checkPassword(@Nonnull String password) {
|
||||
public boolean checkPassword(String password) {
|
||||
return this.password.check(password);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import javax.annotation.Nonnull;
|
|||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.domain.IValueObject;
|
||||
import xyz.zhouxy.plusone.exception.PlusoneException;
|
||||
|
@ -36,7 +37,7 @@ public class Password implements IValueObject {
|
|||
}
|
||||
var salt = PasswordUtil.generateRandomSalt();
|
||||
if (salt == null) {
|
||||
throw new PlusoneException(9999999, "未知错误:生成随机盐失败");
|
||||
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:生成随机盐失败");
|
||||
}
|
||||
this.saltVal = salt;
|
||||
this.passwordVal = PasswordUtil.hashPassword(password, salt);
|
||||
|
|
Loading…
Reference in New Issue