48 Commits

Author SHA1 Message Date
8460b9da29 修改部分 jsr305 注解的使用。 2023-04-16 00:08:04 +08:00
19fc97362c 更改 Exception Handler 版本。 2023-04-16 00:06:36 +08:00
d91f818c96 Merge remote-tracking branch 'origin/main' into main 2023-04-15 22:06:58 +08:00
0e0d6f1808 plusone-commons 做了调整。 2023-04-15 05:24:03 +08:00
06ffc8d858 避免实例化。 2023-04-04 00:32:25 +08:00
60b4f18e8c 更改 hutool 版本。 2023-04-04 00:27:53 +08:00
2b282039ad 更新 plusone-validator 和 plusone-exception-handler。 2023-04-04 00:24:31 +08:00
ea7a8ee6a0 Merge pull request '整合多次更改' (#1) from dev into main
Reviewed-on: http://zhouxy.xyz:3000/ZhouXY108/plusone-admin/pulls/1
2023-03-29 18:54:03 +08:00
67313938e1 提交代码。 2023-03-28 15:41:15 +08:00
27be582bfb 升级 Spring Boot 版本。 2023-03-28 15:40:49 +08:00
288ce9689f postgresql:42.3.8 依赖 checker-qual:3.5.0,将 guava 的版本更改为 30.1-jre,避免依赖冲突。 2023-03-21 15:52:38 +08:00
71edaa60a4 整理依赖。 2023-03-17 18:46:39 +08:00
39cd57e675 使用原生哈希算法。使用自己实现的随机盐生成方法。 2023-03-17 18:46:06 +08:00
7a44c43402 使用原生 UUID。 2023-03-17 18:44:51 +08:00
55395ed327 自己实现随机字符串的生成。 2023-03-17 18:44:33 +08:00
956da350ed 更改 plusone-exception-handler 版本。 2023-03-17 18:43:24 +08:00
78cdded667 int 数组的值总和可能大于 int 的最大值,使用 long 类型的变量存储其结果。 2023-03-17 18:42:43 +08:00
cc3c4be8de 升级 hutool。 2023-03-14 18:10:02 +08:00
1e31e1f327 使用 Integer 接收前端的参数,而不是枚举类。 2023-03-14 10:51:11 +08:00
993ba7fa7b 枚举类不允许继承。 2023-03-12 13:44:28 +08:00
8ae0faa04d 优化正则的使用。 2023-03-12 13:42:08 +08:00
920971c640 Merge branch 'dev' of http://zhouxy.xyz:3000/ZhouXY108/plusone-admin into dev 2023-03-12 13:29:15 +08:00
5f1cb36235 AccountInfo 的构建使用 Builder 模式。 2023-03-12 13:29:07 +08:00
b4bccfe663 升级 Spring Boot 到 2.7.9。 2023-03-12 13:28:39 +08:00
dc09022919 update hutool to 5.8.14 2023-03-08 19:48:17 +08:00
f0b6014e77 整理代码。 2023-03-08 17:42:04 +08:00
19557734ed Update Spring Boot to 2.7.9. 2023-03-03 21:02:03 +08:00
ff54aca271 Merge branch 'dev' of http://zhouxy.xyz:3000/ZhouXY108/plusone-admin into dev 2023-02-26 13:49:09 +08:00
5d9e6ae5b3 修改 Optional.map 方法的错误使用。 2023-02-26 13:49:03 +08:00
5c3b31bb18 更新方法名。 2023-02-25 02:00:12 +08:00
33d3d86393 Merge branch 'dev' into main 2023-02-25 00:32:34 +08:00
a0b16afde2 plusone-commons 重构,代码随之重构调整。 2023-02-24 17:30:18 +08:00
9293ba6817 20230219 2023-02-19 04:21:39 +08:00
92dbc613d2 统一空格。 2023-02-18 11:00:40 +08:00
1b551eeb4c Merge branch 'dev' into main 2023-02-17 15:57:05 +08:00
5b80f70373 添加 guava 依赖。 2023-02-17 15:29:51 +08:00
cf068566a1 Merge branch 'dev' of http://zhouxy.xyz:3000/ZhouXY108/plusone-admin into dev 2023-02-17 11:25:07 +08:00
0212020dcf 修改领域模型。 2023-02-17 11:24:55 +08:00
699ba2394d 更新 fastdfs-client-java 的版本。 2023-02-16 20:30:05 +08:00
5ad6980bf7 Merge branch 'feature/jdbc-next' into dev 2023-02-16 15:57:22 +08:00
bac7a007e6 将 find 方法的返回值改为 Optional<T>。 2023-02-16 15:42:30 +08:00
02d918d0a4 添加工厂方法的重载。 2023-02-16 15:03:41 +08:00
f70e9575ea 改造 exists 相关方法。 2023-02-16 14:35:10 +08:00
cbc2711540 重构 DAO 基础代码。 2023-02-11 20:34:16 +08:00
960a4d4ef3 重构代码,调整配置的加载。 2023-02-10 13:34:08 +08:00
1611bf38e8 Merge branch 'dev' into main 2023-01-28 17:37:12 +08:00
17273b0bc6 Merge pull request 'dev' (#3) from dev into master
Reviewed-on: http://zhouxy.xyz:3000/ZhouXY108/plusone-admin/pulls/3
2022-12-17 22:55:06 +08:00
2d02899372 Merge pull request 'dev' (#1) from dev into master
Reviewed-on: http://zhouxy.xyz:3000/ZhouXY108/plusone-admin/pulls/1
2022-12-10 03:46:53 +08:00
110 changed files with 1216 additions and 663 deletions

View File

@@ -1,10 +1,13 @@
package xyz.zhouxy.plusone.exception.handler; package xyz.zhouxy.plusone.exception.handler;
import javax.annotation.Nonnull;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler.ExceptionInfoHolder; import xyz.zhouxy.plusone.commons.exception.handler.AllExceptionHandler;
import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler.ExceptionInfoHolder;
/** /**
* AllExceptionHandlerConfig * AllExceptionHandlerConfig
@@ -14,7 +17,7 @@ import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler.ExceptionInfoHo
public class AllExceptionHandlerConfig { public class AllExceptionHandlerConfig {
@Bean @Bean
AllExceptionHandler getAllExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) { AllExceptionHandler getAllExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
return new AllExceptionHandler(exceptionInfoHolder); return new AllExceptionHandler(exceptionInfoHolder);
} }
} }

View File

@@ -1,5 +1,7 @@
package xyz.zhouxy.plusone.exception.handler; package xyz.zhouxy.plusone.exception.handler;
import javax.annotation.Nonnull;
import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
@@ -11,7 +13,8 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
/** /**
* 默认异常的处理器 * 默认异常的处理器
@@ -40,7 +43,7 @@ import xyz.zhouxy.plusone.util.RestfulResult;
@Order(Ordered.LOWEST_PRECEDENCE - 1) @Order(Ordered.LOWEST_PRECEDENCE - 1)
@Slf4j @Slf4j
public class DefaultExceptionHandler extends BaseExceptionHandler { public class DefaultExceptionHandler extends BaseExceptionHandler {
public DefaultExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) { public DefaultExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder); super(exceptionInfoHolder);
set(IllegalArgumentException.class, 4010000, "格式错误", HttpStatus.FORBIDDEN); set(IllegalArgumentException.class, 4010000, "格式错误", HttpStatus.FORBIDDEN);
set(DataAccessException.class, 6030000, "数据库错误", HttpStatus.INTERNAL_SERVER_ERROR, true); set(DataAccessException.class, 6030000, "数据库错误", HttpStatus.INTERNAL_SERVER_ERROR, true);

View File

@@ -0,0 +1,29 @@
package xyz.zhouxy.plusone.exception.handler;
import javax.annotation.Nonnull;
import org.springframework.http.HttpStatus;
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.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.exception.SysException;
@RestControllerAdvice
@Slf4j
public class SysExceptionHandler extends BaseExceptionHandler {
public SysExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder);
}
@ExceptionHandler({ SysException.class })
public ResponseEntity<RestfulResult> handleException(@Nonnull Exception e) {
log.error(e.getMessage(), e);
HttpStatus httpStatus = getHttpStatus(e);
return new ResponseEntity<>(RestfulResult.error(getErrorCode(e), "系统错误"), httpStatus);
}
}

View File

@@ -39,17 +39,17 @@
<dependency> <dependency>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-commons</artifactId> <artifactId>plusone-commons</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-validator</artifactId>
<version>0.1.0-SNAPSHOT</version> <version>0.1.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-validator</artifactId>
<version>0.1.3-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-exception-handler</artifactId> <artifactId>plusone-exception-handler</artifactId>
<version>0.0.6-SNAPSHOT</version> <version>0.0.9-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -2,4 +2,8 @@ package xyz.zhouxy.plusone.constant;
public class ErrorCodeConsts { public class ErrorCodeConsts {
public static final int DEFAULT_ERROR_CODE = 9999999; public static final int DEFAULT_ERROR_CODE = 9999999;
private ErrorCodeConsts() {
throw new IllegalStateException("Utility class");
}
} }

View File

@@ -0,0 +1,39 @@
package xyz.zhouxy.plusone.exception;
import xyz.zhouxy.plusone.commons.exception.BaseException;
/**
* 业务异常
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public class BizException extends BaseException {
@java.io.Serial
private static final long serialVersionUID = -5524759033245815405L;
public static final int DEFAULT_ERROR_CODE = 4000000;
public BizException(int code, String msg) {
super(code, msg);
}
public BizException(int code, Throwable cause) {
super(code, cause);
}
public BizException(int code, String msg, Throwable cause) {
super(code, msg, cause);
}
public BizException(String msg) {
super(DEFAULT_ERROR_CODE, msg);
}
public BizException(Throwable cause) {
super(DEFAULT_ERROR_CODE, cause);
}
public BizException(String msg, Throwable cause) {
super(DEFAULT_ERROR_CODE, msg, cause);
}
}

View File

@@ -6,15 +6,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
/** /**
* 需要时,当查询数据不存在时抛出的异常 * 需要时,当查询数据不存在时抛出的异常
* *
* <p>
* 暂时先这样,后续完善异常体系时可能会更改。
* </p>
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see xyz.zhouxy.plusone.util.AssertResult
*/ */
@ResponseStatus(HttpStatus.NOT_FOUND) @ResponseStatus(HttpStatus.NOT_FOUND)
public class DataNotExistException extends PlusoneException { public class DataNotExistException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 6536955800679703111L; private static final long serialVersionUID = 6536955800679703111L;

View File

@@ -4,28 +4,27 @@ import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
/** /**
* 需要时当数据操作的行数不符合预期时抛出的异常 * 需要时当数据操作的结果不符合预期时抛出的异常
* *
* <p> * <p>
* 暂时先这样后续完善异常体系时可能会更改 * 暂时先这样后续完善异常体系时可能会更改
* </p>
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see xyz.zhouxy.plusone.util.AssertResult * @see xyz.zhouxy.plusone.util.AssertResult
*/ */
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class DataOperationNumberException extends PlusoneException { public class DataOperationResultException extends SysException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = -9220765735990318186L; private static final long serialVersionUID = -9220765735990318186L;
public static final int ERROR_CODE = 4110200; public static final int ERROR_CODE = 4110200;
public DataOperationNumberException() { public DataOperationResultException() {
super(ERROR_CODE, "数据操作的行数不符合预期"); super(ERROR_CODE, "数据操作结果不符合预期");
} }
public DataOperationNumberException(String message) { public DataOperationResultException(String message) {
super(ERROR_CODE, message); super(ERROR_CODE, message);
} }
} }

View File

@@ -0,0 +1,34 @@
package xyz.zhouxy.plusone.exception;
import xyz.zhouxy.plusone.commons.exception.BaseException;
public class SysException extends BaseException {
@java.io.Serial
private static final long serialVersionUID = 8821240827443168118L;
public static final int DEFAULT_ERROR_CODE = 5000000;
public SysException(int code, String msg) {
super(code, msg);
}
public SysException(int code, Throwable cause) {
super(code, cause);
}
public SysException(int code, String msg, Throwable cause) {
super(code, msg, cause);
}
public SysException(String msg) {
super(DEFAULT_ERROR_CODE, msg);
}
public SysException(Throwable cause) {
super(DEFAULT_ERROR_CODE, cause);
}
public SysException(String msg, Throwable cause) {
super(DEFAULT_ERROR_CODE, msg, cause);
}
}

View File

@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
* @author ZhouXY * @author ZhouXY
*/ */
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public class UserOperationException extends PlusoneException { public class UserOperationException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 4371055414421991940L; private static final long serialVersionUID = 4371055414421991940L;

View File

@@ -1,10 +1,10 @@
package xyz.zhouxy.plusone.util; package xyz.zhouxy.plusone.util;
import xyz.zhouxy.plusone.exception.DataNotExistException; import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.exception.DataOperationNumberException; import xyz.zhouxy.plusone.exception.DataOperationResultException;
import java.util.Objects; import java.util.Objects;
import java.util.function.Supplier;
/** /**
* 对数据库执行结果进行判断 * 对数据库执行结果进行判断
@@ -17,59 +17,34 @@ public final class AssertResult {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
public static void update(boolean expression) { public static <E extends Throwable> void isTrue(boolean condition, Supplier<E> e) throws E {
if (!expression) { if (!condition) {
throw new DataOperationNumberException(); throw e.get();
} }
} }
public static void update(boolean expression, String message) { public static <T> void equals(T result, T expectedValue) {
if (!expression) { isTrue(Objects.equals(result, expectedValue), DataOperationResultException::new);
throw new DataOperationNumberException(message);
}
} }
public static void update(Object i, int expectedValue) { public static <T> void equals(T result, T expectedValue, String msgTemplate, Object... args) {
if (!Objects.equals(i, expectedValue)) { isTrue(!Objects.equals(result, expectedValue),
throw new DataOperationNumberException(); () -> new DataOperationResultException(String.format(msgTemplate, args)));
}
}
public static void update(Object i, int expectedValue, String format) {
if (!Objects.equals(i, expectedValue)) {
throw new DataOperationNumberException(String.format(format, i));
}
} }
public static void updateOneRow(int i) { public static void updateOneRow(int i) {
update(i, 1); equals(i, 1);
} }
public static void updateOneRow(Object i, String format) { public static void updateOneRow(int i, String format, Object... args) {
update(i, 1, format); equals(i, 1, format, args);
}
public static void exist(boolean expression) {
if (!expression) {
throw new DataNotExistException();
}
}
public static void exist(boolean expression, String message) {
if (!expression) {
throw new DataNotExistException(message);
}
} }
public static void nonNull(Object obj) { public static void nonNull(Object obj) {
if (Objects.isNull(obj)) { isTrue(Objects.nonNull(obj), DataNotExistException::new);
throw new DataNotExistException();
}
} }
public static void nonNull(Object obj, String message) { public static void nonNull(Object obj, String message) {
if (Objects.isNull(obj)) { isTrue(Objects.nonNull(obj), () -> new DataNotExistException(message));
throw new DataNotExistException(message);
}
} }
} }

View File

@@ -0,0 +1,18 @@
package xyz.zhouxy.plusone.util;
import java.util.concurrent.ThreadLocalRandom;
public final class RandomUtil {
private RandomUtil() {
throw new IllegalStateException("Utility class");
}
public static String randomStr(char[] sourceCharacters, int length) {
ThreadLocalRandom random = ThreadLocalRandom.current();
char[] result = new char[length];
for (int i = 0; i < length; i++) {
result[i] = sourceCharacters[random.nextInt(sourceCharacters.length)];
}
return String.valueOf(result);
}
}

View File

@@ -0,0 +1,23 @@
package xyz.zhouxy.plusone.util;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import lombok.extern.slf4j.Slf4j;
@Slf4j
class RandomUtilTests {
@Test
void testRandom() {
String[] s = new String[20];
for (int i = 0; i < 20; i++) {
s[i] = RandomUtil.randomStr(
"0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM~`!@#$%^&*()_-+={[\\|/:;\"',.<>?]}"
.toCharArray(),
28);
}
log.info("{}", Arrays.toString(s));
}
}

View File

@@ -15,11 +15,6 @@
<groupId>xyz.zhouxy</groupId> <groupId>xyz.zhouxy</groupId>
</dependency> </dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
@@ -28,12 +23,10 @@
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId> <artifactId>jackson-core</artifactId>
<version>2.13.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId> <artifactId>jackson-annotations</artifactId>
<version>2.13.4</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,32 +1,34 @@
package xyz.zhouxy.plusone.constant; package xyz.zhouxy.plusone.constant;
import xyz.zhouxy.plusone.util.Enumeration; import java.util.Collection;
import xyz.zhouxy.plusone.util.EnumerationValuesHolder;
import javax.annotation.Nonnull;
import xyz.zhouxy.plusone.commons.util.Enumeration;
/** /**
* 实体状态 * 实体状态
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
public class EntityStatus extends Enumeration<EntityStatus> { public final class EntityStatus extends Enumeration<EntityStatus> {
private EntityStatus(int value, String name) { private EntityStatus(int id, @Nonnull String name) {
super(value, name); super(id, name);
} }
// 常量 // 常量
public static final EntityStatus AVAILABLE = new EntityStatus(0, "正常"); public static final EntityStatus AVAILABLE = new EntityStatus(0, "正常");
public static final EntityStatus DISABLED = new EntityStatus(1, "禁用"); public static final EntityStatus DISABLED = new EntityStatus(1, "禁用");
private static final EnumerationValuesHolder<EntityStatus> ENUMERATION_VALUES = new EnumerationValuesHolder<>( private static final ValueSet<EntityStatus> VALUE_SET = new ValueSet<>(
new EntityStatus[] { AVAILABLE, DISABLED }); AVAILABLE, DISABLED);
public static EntityStatus of(int value) { public static EntityStatus of(int id) {
return ENUMERATION_VALUES.get(value); return VALUE_SET.get(id);
} }
@Override public static Collection<EntityStatus> constants() {
public String toString() { return VALUE_SET.getValues();
return "EntityStatus" + super.toString();
} }
} }

View File

@@ -1,27 +0,0 @@
package xyz.zhouxy.plusone.constant;
/**
* 正则表达式常量
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public final class RegexConsts {
public static final String DATE = "^\\d{4}-\\d{2}-\\d{2}";
public static final String PASSWORD = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[\\w\\\\!#$%&'*\\+\\-/=?^`{|}~@\\(\\)\\[\\]\",\\.;':><]{8,32}$";
public static final String CAPTCHA = "^[0-9A-Za-z]{4,6}$";
public static final String EMAIL = "^\\w+([-+.]\\w+)*@[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*(\\.(?![0-9]+$)[a-zA-Z0-9][-0-9A-Za-z]{0,62})$";
public static final String MOBILE_PHONE = "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$";
public static final String USERNAME = "^[\\da-zA-Z_.@\\\\]{4,36}$";
public static final String NICKNAME = "^[\\da-zA-Z_.@\\\\]{4,36}$";
private RegexConsts() {
throw new IllegalStateException("Utility class");
}
}

View File

@@ -1,6 +1,7 @@
package xyz.zhouxy.plusone.domain; package xyz.zhouxy.plusone.domain;
import cn.hutool.core.lang.UUID; import java.util.UUID;
import lombok.Getter; import lombok.Getter;
/** /**
@@ -20,7 +21,7 @@ public abstract class DomainEvent {
private long happenedAt; private long happenedAt;
protected DomainEvent() { protected DomainEvent() {
this.identifier = UUID.randomUUID().toString(true); this.identifier = UUID.randomUUID().toString();
this.happenedAt = System.currentTimeMillis(); this.happenedAt = System.currentTimeMillis();
} }
} }

View File

@@ -1,6 +1,7 @@
package xyz.zhouxy.plusone.domain; package xyz.zhouxy.plusone.domain;
import java.io.Serializable; import java.io.Serializable;
import java.util.Optional;
/** /**
* Repository 基础接口 * Repository 基础接口
@@ -10,7 +11,7 @@ import java.io.Serializable;
*/ */
public interface IRepository<T extends AggregateRoot<ID>, ID extends Serializable> { public interface IRepository<T extends AggregateRoot<ID>, ID extends Serializable> {
T find(ID id); Optional<T> find(ID id);
T save(T entity); T save(T entity);

View File

@@ -1,5 +1,8 @@
package xyz.zhouxy.plusone.domain; package xyz.zhouxy.plusone.domain;
import java.util.Optional;
import java.util.regex.Pattern;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue; import com.fasterxml.jackson.annotation.JsonValue;
@@ -11,15 +14,15 @@ import com.fasterxml.jackson.annotation.JsonValue;
public abstract class ValidatableStringRecord implements IValueObject { public abstract class ValidatableStringRecord implements IValueObject {
protected String value; protected String value;
protected final String format; protected final Pattern format;
protected ValidatableStringRecord(String format) { protected ValidatableStringRecord(Pattern format) {
this.format = format; this.format = format;
} }
@JsonIgnore @JsonIgnore
protected boolean isValid() { protected boolean isValid() {
return value.matches(format); return format.matcher(value).matches();
} }
@JsonValue @JsonValue
@@ -31,4 +34,8 @@ public abstract class ValidatableStringRecord implements IValueObject {
public String toString() { public String toString() {
return value; return value;
} }
public static String getValueOrNull(Optional<? extends ValidatableStringRecord> s) {
return s.isPresent() ? s.get().value() : null;
}
} }

View File

@@ -1,36 +0,0 @@
package xyz.zhouxy.plusone.util;
import java.util.regex.Pattern;
public class RegexUtil {
private RegexUtil() {
throw new IllegalStateException("Utility class");
}
public static boolean matches(CharSequence input, String regex) {
return Pattern.matches(regex, input);
}
public static boolean matchesOr(CharSequence input, String... regexs) {
boolean isMatched;
for (var regex : regexs) {
isMatched = Pattern.matches(regex, input);
if (isMatched) {
return true;
}
}
return false;
}
public static boolean matchesAnd(CharSequence input, String... regexs) {
boolean isMatched;
for (var regex : regexs) {
isMatched = Pattern.matches(regex, input);
if (!isMatched) {
return false;
}
}
return true;
}
}

View File

@@ -5,7 +5,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts; import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler.ExceptionInfoHolder; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler.ExceptionInfoHolder;
@Configuration @Configuration
public class PlusoneExceptionHandlerConfig { public class PlusoneExceptionHandlerConfig {

View File

@@ -4,6 +4,7 @@ import java.io.Serializable;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -16,70 +17,48 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import xyz.zhouxy.plusone.domain.Entity; import xyz.zhouxy.plusone.domain.Entity;
public abstract class JdbcEntityDaoSupport<T extends Entity<ID>, ID extends Serializable> { public abstract class JdbcEntityDaoSupport<T extends Entity<ID>, ID extends Serializable>
protected final NamedParameterJdbcTemplate jdbc; extends PlusoneJdbcDaoSupport {
protected RowMapper<T> rowMapper; protected RowMapper<T> rowMapper;
protected ResultSetExtractor<T> resultSetExtractor; protected ResultSetExtractor<Optional<T>> resultSetExtractor;
protected JdbcEntityDaoSupport(@Nonnull NamedParameterJdbcTemplate namedParameterJdbcTemplate) { protected JdbcEntityDaoSupport(@Nonnull NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.jdbc = namedParameterJdbcTemplate; super(namedParameterJdbcTemplate);
this.rowMapper = (ResultSet rs, int rowNum) -> mapRow(rs); this.rowMapper = (ResultSet rs, int rowNum) -> mapRow(rs);
this.resultSetExtractor = (ResultSet rs) -> rs.next() ? mapRow(rs) : null; this.resultSetExtractor = (ResultSet rs) -> rs.next() ? Optional.of(mapRow(rs)) : Optional.empty();
} }
protected final T queryForObject(String sql) { protected final Optional<T> queryForObject(String sql) {
return this.jdbc.query(sql, this.resultSetExtractor); return queryForObject(sql, this.resultSetExtractor);
} }
protected final T queryForObject(String sql, SqlParameterSource paramSource) { protected final Optional<T> queryForObject(String sql, SqlParameterSource paramSource) {
return this.jdbc.query(sql, paramSource, this.resultSetExtractor); return queryForObject(sql, paramSource, this.resultSetExtractor);
} }
protected final T queryForObject(String sql, String paramName, Object value) { protected final Optional<T> queryForObject(String sql, String paramName, Object value) {
return this.jdbc.query(sql, new MapSqlParameterSource(paramName, value), this.resultSetExtractor); return queryForObject(sql, new MapSqlParameterSource(paramName, value), this.resultSetExtractor);
} }
protected final List<T> queryForList(String sql) { protected final List<T> queryForList(String sql) {
return this.jdbc.query(sql, this.rowMapper); return queryForList(sql, this.rowMapper);
} }
protected final List<T> queryForList(String sql, SqlParameterSource parameterSource) { protected final List<T> queryForList(String sql, SqlParameterSource parameterSource) {
return this.jdbc.query(sql, parameterSource, this.rowMapper); return queryForList(sql, parameterSource, this.rowMapper);
} }
protected final List<T> queryForList(String sql, String paramName, Object value) { protected final List<T> queryForList(String sql, String paramName, Object value) {
return this.jdbc.query(sql, new MapSqlParameterSource(paramName, value), this.rowMapper); return queryForList(sql, new MapSqlParameterSource(paramName, value), this.rowMapper);
} }
protected final Stream<T> queryForStream(String sql, SqlParameterSource parameterSource) { protected final Stream<T> queryForStream(String sql, SqlParameterSource parameterSource) {
return this.jdbc.queryForStream(sql, parameterSource, this.rowMapper); return queryForStream(sql, parameterSource, this.rowMapper);
} }
protected final Stream<T> queryForStream(String sql, String paramName, Object value) { protected final Stream<T> queryForStream(String sql, String paramName, Object value) {
return this.jdbc.queryForStream(sql, new MapSqlParameterSource(paramName, value), this.rowMapper); return queryForStream(sql, new MapSqlParameterSource(paramName, value), this.rowMapper);
}
protected final <E> Stream<E> queryForStream(String sql, SqlParameterSource parameterSource, Class<E> elementType) {
return this.jdbc.queryForList(sql, parameterSource, elementType).stream();
}
protected final <E> Stream<E> queryForStream(String sql, String paramName, Object value, Class<E> elementType) {
return this.jdbc.queryForList(sql, new MapSqlParameterSource(paramName, value), elementType).stream();
}
protected final boolean queryExists(String sql, SqlParameterSource parameterSource) {
Boolean isExists = this.jdbc.query(sql, parameterSource, ResultSet::next);
return Boolean.TRUE.equals(isExists);
}
protected final boolean queryExists(String sql, String paramName, Object value) {
Boolean isExists = this.jdbc.query(sql, new MapSqlParameterSource(paramName, value), ResultSet::next);
return Boolean.TRUE.equals(isExists);
}
protected final int update(String sql, SqlParameterSource parameterSource) {
return this.jdbc.update(sql, parameterSource);
} }
protected abstract T mapRow(ResultSet rs) throws SQLException; protected abstract T mapRow(ResultSet rs) throws SQLException;
@@ -88,7 +67,7 @@ public abstract class JdbcEntityDaoSupport<T extends Entity<ID>, ID extends Seri
this.rowMapper = rowMapper; this.rowMapper = rowMapper;
} }
protected void setResultSetExtractor(@Nonnull ResultSetExtractor<T> resultSetExtractor) { protected void setResultSetExtractor(@Nonnull ResultSetExtractor<Optional<T>> resultSetExtractor) {
this.resultSetExtractor = resultSetExtractor; this.resultSetExtractor = resultSetExtractor;
} }
} }

View File

@@ -1,5 +1,6 @@
package xyz.zhouxy.plusone.jdbc; package xyz.zhouxy.plusone.jdbc;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@@ -16,15 +17,17 @@ import xyz.zhouxy.plusone.spring.SpringContextHolder;
*/ */
public final class JdbcFactory { public final class JdbcFactory {
private static final ApplicationContext CONTEXT = SpringContextHolder.getContext();
private JdbcFactory() { private JdbcFactory() {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
public static JdbcTemplate getJdbcTemplate() { public static JdbcTemplate getJdbcTemplate() {
return SpringContextHolder.getContext().getBean(JdbcTemplate.class); return CONTEXT.getBean(JdbcTemplate.class);
} }
public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return SpringContextHolder.getContext().getBean(NamedParameterJdbcTemplate.class); return CONTEXT.getBean(NamedParameterJdbcTemplate.class);
} }
} }

View File

@@ -1,6 +1,7 @@
package xyz.zhouxy.plusone.jdbc; package xyz.zhouxy.plusone.jdbc;
import java.io.Serializable; import java.io.Serializable;
import java.util.Optional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -20,7 +21,7 @@ public abstract class JdbcRepositorySupport<T extends AggregateRoot<ID>, ID exte
protected abstract void doDelete(@Nonnull T entity); protected abstract void doDelete(@Nonnull T entity);
protected abstract T doFindById(@Nonnull ID id); protected abstract Optional<T> doFindById(@Nonnull ID id);
protected abstract T doInsert(@Nonnull T entity); protected abstract T doInsert(@Nonnull T entity);
@@ -35,7 +36,7 @@ public abstract class JdbcRepositorySupport<T extends AggregateRoot<ID>, ID exte
} }
@Override @Override
public final T find(ID id) { public final Optional<T> find(ID id) {
if (id == null) { if (id == null) {
throw new IllegalArgumentException("Id cannot be null."); throw new IllegalArgumentException("Id cannot be null.");
} }

View File

@@ -0,0 +1,173 @@
package xyz.zhouxy.plusone.jdbc;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.util.CollectionUtils;
import xyz.zhouxy.plusone.commons.util.NumberUtil;
import xyz.zhouxy.plusone.exception.DataOperationResultException;
public abstract class PlusoneJdbcDaoSupport {
protected final NamedParameterJdbcTemplate jdbc;
protected PlusoneJdbcDaoSupport(@Nonnull NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.jdbc = namedParameterJdbcTemplate;
}
protected final <T> T queryForObject(String sql, ResultSetExtractor<T> resultSetExtractor) {
return this.jdbc.query(sql, resultSetExtractor);
}
protected final <T> T queryForObject(String sql, SqlParameterSource paramSource,
ResultSetExtractor<T> resultSetExtractor) {
return this.jdbc.query(sql, paramSource, resultSetExtractor);
}
protected final <T> T queryForObject(String sql, String paramName, Object value,
ResultSetExtractor<T> resultSetExtractor) {
return this.jdbc.query(sql, new MapSqlParameterSource(paramName, value), resultSetExtractor);
}
protected final <T> List<T> queryForList(String sql, RowMapper<T> rowMapper) {
return this.jdbc.query(sql, rowMapper);
}
protected final <T> List<T> queryForList(String sql, SqlParameterSource parameterSource, RowMapper<T> rowMapper) {
return this.jdbc.query(sql, parameterSource, rowMapper);
}
protected final <T> List<T> queryForList(String sql, String paramName, Object value, RowMapper<T> rowMapper) {
return this.jdbc.query(sql, new MapSqlParameterSource(paramName, value), rowMapper);
}
protected final <T> Stream<T> queryForStream(String sql, SqlParameterSource parameterSource,
RowMapper<T> rowMapper) {
return this.jdbc.queryForStream(sql, parameterSource, rowMapper);
}
protected final <T> Stream<T> queryForStream(String sql, String paramName, Object value, RowMapper<T> rowMapper) {
return this.jdbc.queryForStream(sql, new MapSqlParameterSource(paramName, value), rowMapper);
}
protected final <T> Stream<T> queryForStream(String sql, SqlParameterSource parameterSource, Class<T> elementType) {
return this.jdbc.queryForList(sql, parameterSource, elementType).stream();
}
protected final <T> Stream<T> queryForStream(String sql, String paramName, Object value, Class<T> elementType) {
return queryForStream(sql, new MapSqlParameterSource(paramName, value), elementType);
}
protected final boolean queryForBool(String sql, SqlParameterSource parameterSource) {
Boolean result = this.jdbc.queryForObject(sql, parameterSource, Boolean.TYPE);
return Boolean.TRUE.equals(result);
}
protected final boolean queryForBool(String sql, String paramName, Object value) {
return queryForBool(sql, new MapSqlParameterSource(paramName, value));
}
protected final int update(String sql, SqlParameterSource parameterSource) {
return this.jdbc.update(sql, parameterSource);
}
protected final int update(String sql, String paramName, Object value) {
return update(sql, new MapSqlParameterSource(paramName, value));
}
protected final long batchUpdate(String sql, SqlParameterSource[] batchArgs) {
int[] i = this.jdbc.batchUpdate(sql, batchArgs);
return NumberUtil.sum(i);
}
protected final <T> long batchUpdate(String sql, Stream<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder));
return NumberUtil.sum(i);
}
protected final <T> long batchUpdate(String sql, Collection<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder));
return NumberUtil.sum(i);
}
protected static final <T> void assertResultEquals(T result, T expectedValue) {
if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException();
}
}
protected static final <T> void assertResultEquals(T result, T expectedValue, Function<T, String> errMsg) {
if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException(errMsg.apply(result));
}
}
protected static final <T> void assertResultEquals(T result, T expectedValue, String msgTemplate, Object... args) {
if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException(String.format(msgTemplate, args));
}
}
protected static final <T, E extends Throwable> void assertResultEqualsOrThrow(T result, T expectedValue,
Function<T, E> e) throws E {
if (!Objects.equals(result, expectedValue)) {
throw e.apply(result);
}
}
protected static final void assertUpdateOneRow(int result) {
assertResultEquals(result, 1);
}
protected static final void assertUpdateOneRow(int result, Function<Integer, String> errMsg) {
assertResultEquals(result, 1, errMsg);
}
protected static final void assertUpdateOneRow(int result, String msgTemplate, Object... args) {
assertResultEquals(result, 1, msgTemplate, args);
}
protected static final <E extends Throwable> void assertUpdateOneRowOrThrow(int result, Function<Integer, E> e)
throws E {
assertResultEqualsOrThrow(result, 1, e);
}
protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
T[] c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
if (c == null || c.length == 0) {
return new SqlParameterSource[] {};
}
return buildSqlParameterSourceArray(Arrays.stream(c), paramSourceBuilder);
}
protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
Collection<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
if (CollectionUtils.isEmpty(c)) {
return new SqlParameterSource[] {};
}
return buildSqlParameterSourceArray(c.stream(), paramSourceBuilder);
}
protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
Stream<T> stream,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
Objects.requireNonNull(stream);
Objects.requireNonNull(paramSourceBuilder);
return stream.map(paramSourceBuilder).toArray(SqlParameterSource[]::new);
}
}

View File

@@ -1,6 +1,5 @@
package xyz.zhouxy.plusone.mail; package xyz.zhouxy.plusone.mail;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -15,11 +14,10 @@ import org.springframework.mail.javamail.JavaMailSender;
@Configuration @Configuration
@EnableConfigurationProperties(PlusoneMailProperties.class) @EnableConfigurationProperties(PlusoneMailProperties.class)
@ConditionalOnClass(MailService.class) @ConditionalOnClass(MailService.class)
@EnableAutoConfiguration
public class PlusoneMailAutoConfiguration { public class PlusoneMailAutoConfiguration {
@Bean @Bean
public MailService mailService(JavaMailSender mailSender, PlusoneMailProperties mailProperties) { MailService mailService(JavaMailSender mailSender, PlusoneMailProperties mailProperties) {
MailMessageFactory mailMessageFactory = new MailMessageFactory(mailProperties); MailMessageFactory mailMessageFactory = new MailMessageFactory(mailProperties);
return new SimpleMailService(mailSender, mailMessageFactory); return new SimpleMailService(mailSender, mailMessageFactory);
} }

View File

@@ -7,7 +7,6 @@ import java.util.Objects;
import org.csource.common.MyException; import org.csource.common.MyException;
import org.csource.fastdfs.ClientGlobal; import org.csource.fastdfs.ClientGlobal;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@@ -20,7 +19,6 @@ import xyz.zhouxy.plusone.oss.FastDFSProperties.ConnectionPool;
@Configuration @Configuration
@EnableConfigurationProperties(FastDFSProperties.class) @EnableConfigurationProperties(FastDFSProperties.class)
@ConditionalOnClass(FastDFSUtil.class) @ConditionalOnClass(FastDFSUtil.class)
@EnableAutoConfiguration
public class FastDFSAutoConfig { public class FastDFSAutoConfig {
@Bean @Bean

View File

@@ -6,6 +6,7 @@ package xyz.zhouxy.plusone.oss;
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
public class FastDFSException extends Exception { public class FastDFSException extends Exception {
private static final long serialVersionUID = 7871031982887742468L;
public FastDFSException() { public FastDFSException() {
} }

View File

@@ -4,11 +4,6 @@ import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@ConfigurationProperties("fastdfs") @ConfigurationProperties("fastdfs")
public class FastDFSProperties { public class FastDFSProperties {
private Integer connectTimeoutInSeconds; private Integer connectTimeoutInSeconds;
@@ -21,12 +16,106 @@ public class FastDFSProperties {
private ConnectionPool connectionPool; private ConnectionPool connectionPool;
@Getter public Integer getConnectTimeoutInSeconds() {
@Setter return connectTimeoutInSeconds;
}
public void setConnectTimeoutInSeconds(Integer connectTimeoutInSeconds) {
this.connectTimeoutInSeconds = connectTimeoutInSeconds;
}
public Integer getNetworkTimeoutInSeconds() {
return networkTimeoutInSeconds;
}
public void setNetworkTimeoutInSeconds(Integer networkTimeoutInSeconds) {
this.networkTimeoutInSeconds = networkTimeoutInSeconds;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public Boolean getHttpAntiStealToken() {
return httpAntiStealToken;
}
public void setHttpAntiStealToken(Boolean httpAntiStealToken) {
this.httpAntiStealToken = httpAntiStealToken;
}
public String getHttpSecretKey() {
return httpSecretKey;
}
public void setHttpSecretKey(String httpSecretKey) {
this.httpSecretKey = httpSecretKey;
}
public Integer getHttpTrackerHttpPort() {
return httpTrackerHttpPort;
}
public void setHttpTrackerHttpPort(Integer httpTrackerHttpPort) {
this.httpTrackerHttpPort = httpTrackerHttpPort;
}
public List<String> getTrackerServers() {
return trackerServers;
}
public void setTrackerServers(List<String> trackerServers) {
this.trackerServers = trackerServers;
}
public ConnectionPool getConnectionPool() {
return connectionPool;
}
public void setConnectionPool(ConnectionPool connectionPool) {
this.connectionPool = connectionPool;
}
public static class ConnectionPool { public static class ConnectionPool {
private Boolean enabled; private Boolean enabled;
private Integer maxCountPerEntry; private Integer maxCountPerEntry;
private Integer maxIdleTime; private Integer maxIdleTime;
private Integer maxWaitTimeInMs; private Integer maxWaitTimeInMs;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Integer getMaxCountPerEntry() {
return maxCountPerEntry;
}
public void setMaxCountPerEntry(Integer maxCountPerEntry) {
this.maxCountPerEntry = maxCountPerEntry;
}
public Integer getMaxIdleTime() {
return maxIdleTime;
}
public void setMaxIdleTime(Integer maxIdleTime) {
this.maxIdleTime = maxIdleTime;
}
public Integer getMaxWaitTimeInMs() {
return maxWaitTimeInMs;
}
public void setMaxWaitTimeInMs(Integer maxWaitTimeInMs) {
this.maxWaitTimeInMs = maxWaitTimeInMs;
}
} }
} }

View File

@@ -11,17 +11,12 @@ import org.springframework.context.annotation.Configuration;
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@Configuration @Configuration
@EnableConfigurationProperties(value = { @EnableConfigurationProperties(SmsProperties.class)
SmsProperties.class,
SmsCredentialProperties.class,
SmsClientProperties.class,
SmsHttpProperties.class,
SmsProxyProperties.class})
@ConditionalOnClass(SmsService.class) @ConditionalOnClass(SmsService.class)
public class PlusoneSmsAutoConfiguration { public class PlusoneSmsAutoConfiguration {
@Bean @Bean
public SmsService smsService(SmsProperties smsProperties) { SmsService smsService(SmsProperties smsProperties) {
return new TencentSmsServiceImpl(smsProperties); return new TencentSmsServiceImpl(smsProperties);
} }
} }

View File

@@ -4,14 +4,11 @@ import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import lombok.Data;
/** /**
* SMS 相关参数 * SMS 相关参数
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@Data
@ConfigurationProperties("plusone.sms") @ConfigurationProperties("plusone.sms")
public class SmsProperties { public class SmsProperties {
private String region; private String region;
@@ -19,33 +16,138 @@ public class SmsProperties {
private SmsClientProperties client; private SmsClientProperties client;
private String appId; private String appId;
private Map<String, String> templates; private Map<String, String> templates;
public String getRegion() {
return region;
} }
@Data public void setRegion(String region) {
@ConfigurationProperties("plusone.sms.credential") this.region = region;
class SmsCredentialProperties { }
public SmsCredentialProperties getCredential() {
return credential;
}
public void setCredential(SmsCredentialProperties credential) {
this.credential = credential;
}
public SmsClientProperties getClient() {
return client;
}
public void setClient(SmsClientProperties client) {
this.client = client;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public Map<String, String> getTemplates() {
return templates;
}
public void setTemplates(Map<String, String> templates) {
this.templates = templates;
}
public static class SmsCredentialProperties {
private String secretId; private String secretId;
private String secretKey; private String secretKey;
public String getSecretId() {
return secretId;
} }
@Data public void setSecretId(String secretId) {
@ConfigurationProperties("plusone.sms.client") this.secretId = secretId;
class SmsClientProperties { }
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
}
public static class SmsClientProperties {
private String signMethod; private String signMethod;
private SmsHttpProperties http; private SmsHttpProperties http;
public String getSignMethod() {
return signMethod;
} }
@Data public void setSignMethod(String signMethod) {
@ConfigurationProperties("plusone.sms.client.http") this.signMethod = signMethod;
class SmsHttpProperties { }
public SmsHttpProperties getHttp() {
return http;
}
public void setHttp(SmsHttpProperties http) {
this.http = http;
}
}
public static class SmsHttpProperties {
private SmsProxyProperties proxy; private SmsProxyProperties proxy;
private String reqMethod; private String reqMethod;
private Integer connTimeout; private Integer connTimeout;
public SmsProxyProperties getProxy() {
return proxy;
} }
@Data public void setProxy(SmsProxyProperties proxy) {
@ConfigurationProperties("plusone.sms.client.http.proxy") this.proxy = proxy;
class SmsProxyProperties { }
public String getReqMethod() {
return reqMethod;
}
public void setReqMethod(String reqMethod) {
this.reqMethod = reqMethod;
}
public Integer getConnTimeout() {
return connTimeout;
}
public void setConnTimeout(Integer connTimeout) {
this.connTimeout = connTimeout;
}
}
public static class SmsProxyProperties {
private String host; private String host;
private Integer port; private Integer port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
}
} }

View File

@@ -12,7 +12,10 @@ import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts; import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsCredentialProperties;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsHttpProperties;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsProxyProperties;
/** /**
* 使用腾讯 SMS 服务 * 使用腾讯 SMS 服务
@@ -66,7 +69,7 @@ public class TencentSmsServiceImpl implements SmsService {
} catch (TencentCloudSDKException e) { } catch (TencentCloudSDKException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, e); throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, e);
} }
} }

View File

@@ -1,13 +1,15 @@
package xyz.zhouxy.plusone.validator; package xyz.zhouxy.plusone.validator;
import javax.annotation.Nonnull;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
@RestControllerAdvice @RestControllerAdvice
public class InvalidInputExceptionHandler extends BaseExceptionHandler { public class InvalidInputExceptionHandler extends BaseExceptionHandler {
public InvalidInputExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) { public InvalidInputExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder); super(exceptionInfoHolder);
set(InvalidInputException.class, InvalidInputException.ERROR_CODE, "无效的用户输入"); set(InvalidInputException.class, InvalidInputException.ERROR_CODE, "无效的用户输入");
} }

View File

@@ -0,0 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xyz.zhouxy.plusone.sms.PlusoneSmsAutoConfiguration,\
xyz.zhouxy.plusone.mail.PlusoneMailAutoConfiguration,\
xyz.zhouxy.plusone.oss.FastDFSAutoConfig

View File

@@ -1,11 +1,13 @@
package xyz.zhouxy.plusone.validatortest; package xyz.zhouxy.plusone.validatortest;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.validator.BaseValidator; import xyz.zhouxy.plusone.validator.BaseValidator;
class BaseValidatorTest { class BaseValidatorTest {
@@ -34,11 +36,11 @@ class LoginCommandValidator extends BaseValidator<LoginCommand> {
private LoginCommandValidator() { private LoginCommandValidator() {
ruleForString(LoginCommand::getAccount) ruleForString(LoginCommand::getAccount)
.notNull("邮箱地址不能为空") .notNull("邮箱地址不能为空")
.matchesOr(new String[] { RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE }, .matchesOr(new Pattern[] { PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE },
value -> new RuntimeException('"' + value + "\" 不是邮箱地址或手机号")); value -> new RuntimeException('"' + value + "\" 不是邮箱地址或手机号"));
ruleForString(LoginCommand::getPwd) ruleForString(LoginCommand::getPwd)
.notNull("密码不能为空") .notNull("密码不能为空")
.notEmpty("密码不能为空") .notEmpty("密码不能为空")
.matches(RegexConsts.PASSWORD, "密码格式错误"); .matches(PatternConsts.PASSWORD, "密码格式错误");
} }
} }

View File

@@ -7,9 +7,7 @@
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
</parent> </parent>
<groupId>xyz.zhouxy</groupId>
<artifactId>plusone-basic</artifactId> <artifactId>plusone-basic</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>

View File

@@ -7,10 +7,7 @@
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
</parent> </parent>
<groupId>xyz.zhouxy</groupId>
<artifactId>plusone-start</artifactId> <artifactId>plusone-start</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>plusone-start</name> <name>plusone-start</name>
<description>参考 DDD 落地的脚手架</description> <description>参考 DDD 落地的脚手架</description>

View File

@@ -28,30 +28,5 @@
"name": "plusone.exception.handle-all-exception", "name": "plusone.exception.handle-all-exception",
"type": "java.lang.Boolean", "type": "java.lang.Boolean",
"description": "A description for 'plusone.exception.handle-all-exception'" "description": "A description for 'plusone.exception.handle-all-exception'"
},
{
"name": "fastdfs.http_anti_steal_token",
"type": "java.lang.String",
"description": "A description for 'fastdfs.http_anti_steal_token'"
},
{
"name": "fastdfs.http_secret_key",
"type": "java.lang.String",
"description": "A description for 'fastdfs.http_secret_key'"
},
{
"name": "fastdfs.http_tracker_http_port",
"type": "java.lang.String",
"description": "A description for 'fastdfs.http_tracker_http_port'"
},
{
"name": "fastdfs.network_timeout_in_seconds",
"type": "java.lang.String",
"description": "A description for 'fastdfs.network_timeout_in_seconds'"
},
{
"name": "fastdfs.tracker_servers",
"type": "java.util.List",
"description": "A description for 'fastdfs.tracker_servers'"
} }
]} ]}

View File

@@ -50,7 +50,7 @@ plusone:
conn-timeout: 60 conn-timeout: 60
app-id: 1111111111 app-id: 1111111111
templates: templates:
code: 0000000 '[code]': 0000000
# 邮件发送相关参数 # 邮件发送相关参数
mail: mail:

View File

@@ -6,9 +6,9 @@ plusone:
# 邮件发送相关参数 # 邮件发送相关参数
mail: mail:
subject: subject:
code: Plusone '[code]': Plusone
template: template:
code: 【Plusone】验证码%s10分钟内有效请勿泄露。 '[code]': 【Plusone】验证码%s10分钟内有效请勿泄露。
# 日志配置 # 日志配置
logging: logging:
level: level:

View File

@@ -5,14 +5,14 @@ import java.io.ObjectStreamClass;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.*;
@Slf4j @Slf4j
class SerialTests { class SerialTests {
@Test @Test
void testSerialVersionUID() { void testSerialVersionUID() {
var cl = PlusoneException.class; var cl = SysException.class;
var c = ObjectStreamClass.lookup(cl); var c = ObjectStreamClass.lookup(cl);
var uid = c.getSerialVersionUID(); var uid = c.getSerialVersionUID();
log.info("\n @java.io.Serial" + log.info("\n @java.io.Serial" +

View File

@@ -1,5 +1,7 @@
package xyz.zhouxy.plusone; package xyz.zhouxy.plusone;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -25,6 +27,7 @@ class TestAop {
command.setPrincipal("Code108"); command.setPrincipal("Code108");
command.setPassword("2333"); command.setPassword("2333");
command.setRememberMe(false); command.setRememberMe(false);
assertNotNull(service);
LoginInfoViewObject loginInfo = service.loginByPassword(command); LoginInfoViewObject loginInfo = service.loginByPassword(command);
System.err.println(loginInfo); System.err.println(loginInfo);
} }

View File

@@ -6,9 +6,9 @@ plusone:
# 邮件发送相关参数 # 邮件发送相关参数
mail: mail:
subject: subject:
code: Plusone '[code]': Plusone
template: template:
code: 【Plusone】验证码%s10分钟内有效请勿泄露。 '[code]': 【Plusone】验证码%s10分钟内有效请勿泄露。
# 日志配置 # 日志配置
logging: logging:
level: level:

View File

@@ -0,0 +1,32 @@
package xyz.zhouxy.plusone.system.application.common.exception;
import xyz.zhouxy.plusone.exception.BizException;
/**
* 不支持的 Principal 类型出现时抛出的异常
*
* @author <a href="https://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
*/
public class UnsupportedPrincipalTypeException extends BizException {
private static final long serialVersionUID = 5207757290868470762L;
public static final int ERR_CODE = 4040201;
private static final String DEFAULT_ERROR_MSG = "不支持的 PrincipalType";
public UnsupportedPrincipalTypeException() {
super(ERR_CODE, DEFAULT_ERROR_MSG);
}
public UnsupportedPrincipalTypeException(String msg) {
super(ERR_CODE, msg);
}
public UnsupportedPrincipalTypeException(Throwable cause) {
super(ERR_CODE, cause);
}
public UnsupportedPrincipalTypeException(String msg, Throwable cause) {
super(ERR_CODE, msg, cause);
}
}

View File

@@ -1,18 +1,20 @@
package xyz.zhouxy.plusone.system.application.common.util; package xyz.zhouxy.plusone.system.application.common.util;
import java.util.regex.Pattern;
import lombok.Getter; import lombok.Getter;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
public enum PrincipalType { public enum PrincipalType {
EMAIL(RegexConsts.EMAIL), EMAIL(PatternConsts.EMAIL),
MOBILE_PHONE(RegexConsts.MOBILE_PHONE), MOBILE_PHONE(PatternConsts.MOBILE_PHONE),
USERNAME(RegexConsts.USERNAME) USERNAME(PatternConsts.USERNAME)
; ;
@Getter @Getter
private final String regex; private final Pattern regex;
PrincipalType(String regex) { PrincipalType(Pattern regex) {
this.regex = regex; this.regex = regex;
} }
} }

View File

@@ -2,11 +2,11 @@ package xyz.zhouxy.plusone.system.application.common.util;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException;
import xyz.zhouxy.plusone.system.domain.model.account.Email; 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.MobilePhone;
import xyz.zhouxy.plusone.system.domain.model.account.Principal; import xyz.zhouxy.plusone.system.domain.model.account.Principal;
import xyz.zhouxy.plusone.system.domain.model.account.Username; import xyz.zhouxy.plusone.system.domain.model.account.Username;
import xyz.zhouxy.plusone.validator.InvalidInputException;
/** /**
* 根据字面值,判断并生成 {@link Principal} 值对象。 * 根据字面值,判断并生成 {@link Principal} 值对象。
@@ -16,7 +16,7 @@ import xyz.zhouxy.plusone.validator.InvalidInputException;
* @see Username * @see Username
* @see Email * @see Email
* @see MobilePhone * @see MobilePhone
* @see InvalidInputException * @see UnsupportedPrincipalTypeException
*/ */
public class PrincipalUtil { public class PrincipalUtil {
@@ -30,11 +30,11 @@ public class PrincipalUtil {
} }
PrincipalType[] principalTypes = PrincipalType.values(); PrincipalType[] principalTypes = PrincipalType.values();
for (var principalType : principalTypes) { for (var principalType : principalTypes) {
if (principal.matches(principalType.getRegex())) { if (principalType.getRegex().matcher(principal).matches()) {
return principalType; return principalType;
} }
} }
throw InvalidInputException.unsupportedPrincipalTypeException(); throw new UnsupportedPrincipalTypeException();
} }
public static Principal getPrincipal(@Nullable String principal) { public static Principal getPrincipal(@Nullable String principal) {
@@ -48,7 +48,7 @@ public class PrincipalUtil {
if (principalType == PrincipalType.USERNAME) { if (principalType == PrincipalType.USERNAME) {
return Username.of(principal); return Username.of(principal);
} }
throw InvalidInputException.unsupportedPrincipalTypeException(); throw new UnsupportedPrincipalTypeException();
} }
public static Principal getEmailOrMobilePhone(@Nullable String principal) { public static Principal getEmailOrMobilePhone(@Nullable String principal) {
@@ -59,6 +59,6 @@ public class PrincipalUtil {
if (principalType == PrincipalType.MOBILE_PHONE) { if (principalType == PrincipalType.MOBILE_PHONE) {
return MobilePhone.of(principal); return MobilePhone.of(principal);
} }
throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号"); throw new UnsupportedPrincipalTypeException("输入邮箱地址或手机号");
} }
} }

View File

@@ -7,10 +7,10 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.system.application.service.AccountContextService; 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.ChangePasswordCommand;
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand; import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand;
import xyz.zhouxy.plusone.util.RestfulResult;
/** /**
* 账号查询本身相关信息 * 账号查询本身相关信息

View File

@@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic; import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
import static xyz.zhouxy.plusone.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import java.util.List; import java.util.List;
@@ -16,12 +16,11 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams; import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
import xyz.zhouxy.plusone.system.application.service.AccountManagementService; import xyz.zhouxy.plusone.system.application.service.AccountManagementService;
import xyz.zhouxy.plusone.system.application.service.command.CreateAccountCommand; import xyz.zhouxy.plusone.system.application.service.command.CreateAccountCommand;
import xyz.zhouxy.plusone.system.application.service.command.UpdateAccountCommand; import xyz.zhouxy.plusone.system.application.service.command.UpdateAccountCommand;
import xyz.zhouxy.plusone.util.AssertResult;
import xyz.zhouxy.plusone.util.RestfulResult;
/** /**
* 账号管理 * 账号管理
@@ -77,7 +76,6 @@ public class AccountManagementController {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
adminAuthLogic.checkPermission("sys-account-details"); adminAuthLogic.checkPermission("sys-account-details");
var accountDetails = service.queryAccountDetails(accountId); var accountDetails = service.queryAccountDetails(accountId);
AssertResult.nonNull(accountDetails);
return success("查询成功", accountDetails); return success("查询成功", accountDetails);
} }
} }

View File

@@ -1,6 +1,6 @@
package xyz.zhouxy.plusone.system.application.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.system.application.service.AdminLoginService; import xyz.zhouxy.plusone.system.application.service.AdminLoginService;
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand; import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;
import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand; import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* Admin 账号登录 * Admin 账号登录

View File

@@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic; import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
import static xyz.zhouxy.plusone.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import java.util.List; import java.util.List;
@@ -20,7 +20,7 @@ import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams;
import xyz.zhouxy.plusone.system.application.service.DictManagementService; import xyz.zhouxy.plusone.system.application.service.DictManagementService;
import xyz.zhouxy.plusone.system.application.service.command.CreateDictCommand; import xyz.zhouxy.plusone.system.application.service.command.CreateDictCommand;
import xyz.zhouxy.plusone.system.application.service.command.UpdateDictCommand; import xyz.zhouxy.plusone.system.application.service.command.UpdateDictCommand;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* 数据字典管理 * 数据字典管理

View File

@@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic; import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
import static xyz.zhouxy.plusone.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import javax.validation.Valid; import javax.validation.Valid;
@@ -18,7 +18,7 @@ import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.system.application.service.MenuManagementService; import xyz.zhouxy.plusone.system.application.service.MenuManagementService;
import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand; import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand;
import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand; import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* 菜单管理 * 菜单管理

View File

@@ -1,6 +1,6 @@
package xyz.zhouxy.plusone.system.application.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.system.application.service.RegisterAccountService; import xyz.zhouxy.plusone.system.application.service.RegisterAccountService;
import xyz.zhouxy.plusone.system.application.service.command.RegisterAccountCommand; import xyz.zhouxy.plusone.system.application.service.command.RegisterAccountCommand;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* 注册账号服务 * 注册账号服务

View File

@@ -17,7 +17,7 @@ import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams;
import xyz.zhouxy.plusone.system.application.service.RoleManagementService; import xyz.zhouxy.plusone.system.application.service.RoleManagementService;
import xyz.zhouxy.plusone.system.application.service.command.CreateRoleCommand; import xyz.zhouxy.plusone.system.application.service.command.CreateRoleCommand;
import xyz.zhouxy.plusone.system.application.service.command.UpdateRoleCommand; import xyz.zhouxy.plusone.system.application.service.command.UpdateRoleCommand;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* 角色管理服务 * 角色管理服务

View File

@@ -3,10 +3,10 @@ package xyz.zhouxy.plusone.system.application.exception;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.BizException;
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public class AccountLoginException extends PlusoneException { public class AccountLoginException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = -3040996790739138556L; private static final long serialVersionUID = -3040996790739138556L;
@@ -21,18 +21,34 @@ public class AccountLoginException extends PlusoneException {
} }
public static AccountLoginException accountNotExistException() { public static AccountLoginException accountNotExistException() {
return new AccountLoginException(4030101, "用户账户不存在"); return accountNotExistException("用户账户不存在");
}
public static AccountLoginException accountNotExistException(String msg) {
return new AccountLoginException(4030101, msg);
} }
public static AccountLoginException otpErrorException() { public static AccountLoginException otpErrorException() {
return new AccountLoginException(4030501, "验证码错误"); return otpErrorException("验证码错误");
}
public static AccountLoginException otpErrorException(String msg) {
return new AccountLoginException(4030501, msg);
} }
public static AccountLoginException otpNotExistsException() { public static AccountLoginException otpNotExistsException() {
return new AccountLoginException(4030502, "验证码不存在或已过期"); return otpNotExistsException("验证码不存在或已过期");
}
public static AccountLoginException otpNotExistsException(String msg) {
return new AccountLoginException(4030502, msg);
} }
public static AccountLoginException passwordErrorException() { public static AccountLoginException passwordErrorException() {
return new AccountLoginException(4030200, "用户密码错误"); return passwordErrorException("用户密码错误");
}
public static AccountLoginException passwordErrorException(String msg) {
return new AccountLoginException(4030200, msg);
} }
} }

View File

@@ -3,10 +3,10 @@ package xyz.zhouxy.plusone.system.application.exception;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.BizException;
@ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseStatus(HttpStatus.BAD_REQUEST)
public class AccountRegisterException extends PlusoneException { public class AccountRegisterException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 7580245181633370195L; private static final long serialVersionUID = 7580245181633370195L;

View File

@@ -6,14 +6,14 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException; import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
@RestControllerAdvice @RestControllerAdvice
public class AccountLoginExceptionHandler extends BaseExceptionHandler { public class AccountLoginExceptionHandler extends BaseExceptionHandler {
public AccountLoginExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) { public AccountLoginExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder); super(exceptionInfoHolder);
} }

View File

@@ -1,5 +1,7 @@
package xyz.zhouxy.plusone.system.application.exception.handler; package xyz.zhouxy.plusone.system.application.exception.handler;
import javax.annotation.Nonnull;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -14,8 +16,8 @@ import cn.dev33.satoken.exception.NotSafeException;
import cn.dev33.satoken.exception.SaTokenException; import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.exception.SameTokenInvalidException; import cn.dev33.satoken.exception.SameTokenInvalidException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.util.RestfulResult; import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
/** /**
* Sa-Token 异常处理器 * Sa-Token 异常处理器
@@ -27,7 +29,7 @@ import xyz.zhouxy.plusone.util.RestfulResult;
public class SaTokenExceptionHandler extends BaseExceptionHandler { public class SaTokenExceptionHandler extends BaseExceptionHandler {
public SaTokenExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) { public SaTokenExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder); super(exceptionInfoHolder);
set(NotPermissionException.class, 4030103, "会话未能通过权限认证", HttpStatus.FORBIDDEN); set(NotPermissionException.class, 4030103, "会话未能通过权限认证", HttpStatus.FORBIDDEN);
set(NotRoleException.class, 4030103, "会话未能通过角色认证", HttpStatus.FORBIDDEN); set(NotRoleException.class, 4030103, "会话未能通过角色认证", HttpStatus.FORBIDDEN);

View File

@@ -2,12 +2,14 @@ package xyz.zhouxy.plusone.system.application.query;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import xyz.zhouxy.plusone.commons.util.PageDTO;
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams; import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails; import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
import xyz.zhouxy.plusone.system.application.query.result.AccountOverview; import xyz.zhouxy.plusone.system.application.query.result.AccountOverview;
import xyz.zhouxy.plusone.util.PageDTO;
/** /**
* 账号信息查询器 * 账号信息查询器
@@ -23,6 +25,7 @@ public interface AccountQueries {
return PageDTO.of(content, total); return PageDTO.of(content, total);
} }
@Nonnull
List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams); List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams);
long count(AccountQueryParams queryParams); long count(AccountQueryParams queryParams);

View File

@@ -5,7 +5,7 @@ import java.time.LocalDate;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams; import xyz.zhouxy.plusone.commons.util.PagingAndSortingQueryParams;
/** /**
* 账号信息查询参数 * 账号信息查询参数

View File

@@ -4,7 +4,7 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams; import xyz.zhouxy.plusone.commons.util.PagingAndSortingQueryParams;
/** /**
* 数据字典查询参数 * 数据字典查询参数

View File

@@ -5,7 +5,7 @@ import java.time.LocalDate;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams; import xyz.zhouxy.plusone.commons.util.PagingAndSortingQueryParams;
/** /**
* 角色信息查询参数 * 角色信息查询参数

View File

@@ -109,7 +109,7 @@ public class MenuViewObject implements IWithOrderNumber {
viewObject.icon = menu.getIcon(); viewObject.icon = menu.getIcon();
viewObject.hidden = menu.isHidden(); viewObject.hidden = menu.isHidden();
viewObject.orderNumber = menu.getOrderNumber(); viewObject.orderNumber = menu.getOrderNumber();
viewObject.status = menu.getStatus().getValue(); viewObject.status = menu.getStatus().getId();
viewObject.remarks = menu.getRemarks(); viewObject.remarks = menu.getRemarks();
if (viewObject.type == MenuType.MENU_ITEM.ordinal()) { if (viewObject.type == MenuType.MENU_ITEM.ordinal()) {
viewObject.component = menu.getComponent(); viewObject.component = menu.getComponent();

View File

@@ -1,7 +1,5 @@
package xyz.zhouxy.plusone.system.application.service; package xyz.zhouxy.plusone.system.application.service;
import xyz.zhouxy.plusone.system.constant.AuthLogic;
import java.util.List; import java.util.List;
import javax.annotation.Resource; import javax.annotation.Resource;
@@ -10,7 +8,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import cn.dev33.satoken.stp.StpLogic; import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.lang.Assert; import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException;
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil; import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException; import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
import xyz.zhouxy.plusone.system.application.query.AccountQueries; import xyz.zhouxy.plusone.system.application.query.AccountQueries;
@@ -19,12 +17,12 @@ 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.ChangePasswordByOtpCommand;
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordCommand; import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordCommand;
import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand; import xyz.zhouxy.plusone.system.application.service.command.ChangePasswordWithoutLoginCommand;
import xyz.zhouxy.plusone.system.constant.AuthLogic;
import xyz.zhouxy.plusone.system.domain.model.account.Account; 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.AccountRepository;
import xyz.zhouxy.plusone.system.domain.model.account.Email; 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.MobilePhone;
import xyz.zhouxy.plusone.system.domain.model.account.Principal; import xyz.zhouxy.plusone.system.domain.model.account.Principal;
import xyz.zhouxy.plusone.validator.InvalidInputException;
/** /**
* 账号对当前帐号进行操作 * 账号对当前帐号进行操作
@@ -65,7 +63,8 @@ public class AccountContextService {
@Transactional @Transactional
public void changePassword(ChangePasswordCommand command) { public void changePassword(ChangePasswordCommand command) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
Account account = accountRepository.find(adminAuthLogic.getLoginIdAsLong()); Account account = accountRepository.find(adminAuthLogic.getLoginIdAsLong())
.orElseThrow(() -> AccountLoginException.accountNotExistException("当前所登录的账号不存在"));
account.checkPassword(command.getPassword()); account.checkPassword(command.getPassword());
account.changePassword(command.getNewPassword(), command.getPasswordConfirmation()); account.changePassword(command.getNewPassword(), command.getPasswordConfirmation());
accountRepository.save(account); accountRepository.save(account);
@@ -77,9 +76,10 @@ public class AccountContextService {
String principal = command.getAccount(); String principal = command.getAccount();
Principal emailOrMobilePhone = PrincipalUtil.getEmailOrMobilePhone(principal); Principal emailOrMobilePhone = PrincipalUtil.getEmailOrMobilePhone(principal);
Account account = emailOrMobilePhone instanceof Email Account account = (emailOrMobilePhone instanceof Email
? accountRepository.findByEmail((Email) emailOrMobilePhone) ? accountRepository.findByEmail((Email) emailOrMobilePhone)
: accountRepository.findByMobilePhone((MobilePhone) emailOrMobilePhone); : accountRepository.findByMobilePhone((MobilePhone) emailOrMobilePhone))
.orElseThrow(() -> AccountLoginException.accountNotExistException("当前所登录的账号不存在"));
account.checkPassword(command.getOldPassword()); account.checkPassword(command.getOldPassword());
account.changePassword(command.getNewPassword(), command.getPasswordConfirmation()); account.changePassword(command.getNewPassword(), command.getPasswordConfirmation());
accountRepository.save(account); accountRepository.save(account);
@@ -90,13 +90,14 @@ public class AccountContextService {
public void changePasswordByOtp(ChangePasswordByOtpCommand command) { public void changePasswordByOtp(ChangePasswordByOtpCommand command) {
var principal = command.getAccount(); var principal = command.getAccount();
Account account = switch (command.getPrincipalType()) { boolean accountExists = switch (command.getPrincipalType()) {
case EMAIL -> accountRepository.findByEmail(Email.of(principal)); case EMAIL -> accountRepository.existsEmail(Email.of(principal));
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal)); case MOBILE_PHONE -> accountRepository.existsMobilePhone(MobilePhone.of(principal));
default -> throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号"); default -> throw new UnsupportedPrincipalTypeException("输入邮箱地址或手机号");
}; };
Assert.notNull(account, AccountLoginException::accountNotExistException); if (accountExists) {
throw AccountLoginException.accountNotExistException();
}
mailAndSmsVerifyService.checkOtp(principal, command.getOtp()); mailAndSmsVerifyService.checkOtp(principal, command.getOtp());
} }
} }

View File

@@ -14,6 +14,8 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import xyz.zhouxy.plusone.commons.util.PageDTO;
import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException; import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
import xyz.zhouxy.plusone.system.application.query.AccountQueries; import xyz.zhouxy.plusone.system.application.query.AccountQueries;
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams; import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
@@ -24,11 +26,12 @@ import xyz.zhouxy.plusone.system.application.service.command.UpdateAccountComman
import xyz.zhouxy.plusone.system.domain.model.account.Account; import xyz.zhouxy.plusone.system.domain.model.account.Account;
import xyz.zhouxy.plusone.system.domain.model.account.AccountInfo; import xyz.zhouxy.plusone.system.domain.model.account.AccountInfo;
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository; import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
import xyz.zhouxy.plusone.system.domain.model.account.AccountStatus;
import xyz.zhouxy.plusone.system.domain.model.account.Email; 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.MobilePhone;
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
import xyz.zhouxy.plusone.system.domain.model.account.Username; import xyz.zhouxy.plusone.system.domain.model.account.Username;
import xyz.zhouxy.plusone.util.AssertResult; import xyz.zhouxy.plusone.util.AssertResult;
import xyz.zhouxy.plusone.util.PageDTO;
/** /**
* 账号管理 * 账号管理
@@ -66,9 +69,13 @@ public class AccountManagementService {
mobilePhone, mobilePhone,
command.getPassword(), command.getPassword(),
command.getPasswordConfirmation(), command.getPasswordConfirmation(),
command.getStatus(), AccountStatus.of(command.getStatus()),
command.getRoleRefs(), command.getRoleRefs(),
AccountInfo.of(command.getNickname(), command.getAvatar(), command.getSex()), AccountInfo.builder()
.nickname(command.getNickname())
.avatar(command.getAvatar())
.sex(Sex.of(command.getSex()))
.build(),
adminAuthLogic.getLoginIdAsLong()); adminAuthLogic.getLoginIdAsLong());
accountRepository.save(account); accountRepository.save(account);
} }
@@ -76,17 +83,17 @@ public class AccountManagementService {
public void deleteAccounts(List<Long> ids) { public void deleteAccounts(List<Long> ids) {
Account accountToDelete; Account accountToDelete;
for (var id : ids) { for (var id : ids) {
accountToDelete = accountRepository.find(id); accountToDelete = accountRepository.find(id)
AssertResult.nonNull(accountToDelete); .orElseThrow(() -> new DataNotExistException("该账号不存在"));
accountRepository.delete(accountToDelete); accountRepository.delete(accountToDelete);
} }
} }
public void updateAccountInfo(Long id, @Valid UpdateAccountCommand command) { public void updateAccountInfo(Long id, @Valid UpdateAccountCommand command) {
Assert.isTrue(Objects.equals(id, command.getId()), "参数错误: id 不匹配"); Assert.isTrue(Objects.equals(id, command.getId()), "参数错误: id 不匹配");
Account account = accountRepository.find(id); Account account = accountRepository.find(id)
AssertResult.nonNull(account, "该账号不存在"); .orElseThrow(() -> new DataNotExistException("该账号不存在"));
account.setAccountInfo(command.getNickname(), command.getAvatar(), command.getSex()); account.setAccountInfo(command.getNickname(), command.getAvatar(), Sex.of(command.getSex()));
account.setUpdatedBy(adminAuthLogic.getLoginIdAsLong()); account.setUpdatedBy(adminAuthLogic.getLoginIdAsLong());
accountRepository.save(account); accountRepository.save(account);
} }
@@ -96,6 +103,13 @@ public class AccountManagementService {
return accountQueries.queryAccountOverviewPage(queryParams); return accountQueries.queryAccountOverviewPage(queryParams);
} }
/**
* 查询账号详细信息,如果查不到将抛出 {@link DataNotExistException}。
*
* @param accountId 账号 id
* @return 账号信息
* @throws DataNotExistException 查询不到数据时抛出异常
*/
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public AccountDetails queryAccountDetails(@PathVariable("accountId") Long accountId) { public AccountDetails queryAccountDetails(@PathVariable("accountId") Long accountId) {
var accountDetails = accountQueries.queryAccountDetails(accountId); var accountDetails = accountQueries.queryAccountDetails(accountId);

View File

@@ -6,6 +6,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException;
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType; import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil; import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException; import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
@@ -18,7 +19,6 @@ 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.Email;
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone; import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
import xyz.zhouxy.plusone.system.domain.model.account.Username; import xyz.zhouxy.plusone.system.domain.model.account.Username;
import xyz.zhouxy.plusone.validator.InvalidInputException;
import xyz.zhouxy.plusone.validator.ValidateDto; import xyz.zhouxy.plusone.validator.ValidateDto;
/** /**
@@ -44,12 +44,11 @@ public class AdminLoginService {
@ValidateDto @ValidateDto
public LoginInfoViewObject loginByPassword(LoginByPasswordCommand command) { public LoginInfoViewObject loginByPassword(LoginByPasswordCommand command) {
var principal = command.getPrincipal(); var principal = command.getPrincipal();
Account account = switch (command.getPrincipalType()) { Account account = (switch (command.getPrincipalType()) {
case USERNAME -> accountRepository.findByUsername(Username.of(principal)); case USERNAME -> accountRepository.findByUsername(Username.of(principal));
case EMAIL -> accountRepository.findByEmail(Email.of(principal)); case EMAIL -> accountRepository.findByEmail(Email.of(principal));
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal)); case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal));
}; }).orElseThrow(AccountLoginException::accountNotExistException);
Assert.notNull(account, AccountLoginException::accountNotExistException);
var isPasswordCorrect = account.checkPassword(command.getPassword()); var isPasswordCorrect = account.checkPassword(command.getPassword());
Assert.isTrue(isPasswordCorrect, AccountLoginException::passwordErrorException); Assert.isTrue(isPasswordCorrect, AccountLoginException::passwordErrorException);
@@ -61,12 +60,11 @@ public class AdminLoginService {
@ValidateDto @ValidateDto
public LoginInfoViewObject loginByOtp(LoginByOtpCommand command) { public LoginInfoViewObject loginByOtp(LoginByOtpCommand command) {
var principal = command.getPrincipal(); var principal = command.getPrincipal();
Account account = switch (command.getPrincipalType()) { Account account = (switch (command.getPrincipalType()) {
case EMAIL -> accountRepository.findByEmail(Email.of(principal)); case EMAIL -> accountRepository.findByEmail(Email.of(principal));
case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal)); case MOBILE_PHONE -> accountRepository.findByMobilePhone(MobilePhone.of(principal));
default -> throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号"); default -> throw new UnsupportedPrincipalTypeException("输入邮箱地址或手机号");
}; }).orElseThrow(AccountLoginException::accountNotExistException);
Assert.notNull(account, AccountLoginException::accountNotExistException);
mailAndSmsVerifyService.checkOtp(principal, command.getOtp()); mailAndSmsVerifyService.checkOtp(principal, command.getOtp());

View File

@@ -10,6 +10,7 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.query.DictQueries; import xyz.zhouxy.plusone.system.application.query.DictQueries;
import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams; import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams;
import xyz.zhouxy.plusone.system.application.query.result.DictOverview; import xyz.zhouxy.plusone.system.application.query.result.DictOverview;
@@ -45,21 +46,21 @@ public class DictManagementService {
public void deleteDicts(List<Long> ids) { public void deleteDicts(List<Long> ids) {
Dict dictToDelete; Dict dictToDelete;
for (Long id : ids) { for (Long id : ids) {
dictToDelete = dictRepository.find(id); dictToDelete = dictRepository.find(id).orElseThrow(DataNotExistException::new);
dictRepository.delete(dictToDelete); dictRepository.delete(dictToDelete);
} }
} }
public void updateDict(Long id, @Valid UpdateDictCommand command) { public void updateDict(Long id, @Valid UpdateDictCommand command) {
Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配"); Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配");
Dict dictToUpdate = dictRepository.find(command.getId()); Dict dictToUpdate = dictRepository.find(command.getId()).orElseThrow(DataNotExistException::new);
dictToUpdate.updateDict(command.getDictType(), command.getDictLabel(), command.getKeyLabelMap()); dictToUpdate.updateDict(command.getDictType(), command.getDictLabel(), command.getKeyLabelMap());
dictRepository.save(dictToUpdate); dictRepository.save(dictToUpdate);
} }
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public Dict findDictDetails(Long dictId) { public Dict findDictDetails(Long dictId) {
return dictRepository.find(dictId); return dictRepository.find(dictId).orElseThrow(DataNotExistException::new);
} }
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)

View File

@@ -13,7 +13,9 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.IWithOrderNumber; import xyz.zhouxy.plusone.domain.IWithOrderNumber;
import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.exception.UnsupportedMenuTypeException; import xyz.zhouxy.plusone.system.application.exception.UnsupportedMenuTypeException;
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject; import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand; import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand;
@@ -22,7 +24,6 @@ import xyz.zhouxy.plusone.system.domain.model.menu.Menu;
import xyz.zhouxy.plusone.system.domain.model.menu.MenuConstructor; import xyz.zhouxy.plusone.system.domain.model.menu.MenuConstructor;
import xyz.zhouxy.plusone.system.domain.model.menu.MenuRepository; import xyz.zhouxy.plusone.system.domain.model.menu.MenuRepository;
import xyz.zhouxy.plusone.system.domain.service.MenuService; import xyz.zhouxy.plusone.system.domain.service.MenuService;
import xyz.zhouxy.plusone.util.AssertResult;
/** /**
* 菜单管理 * 菜单管理
@@ -66,7 +67,7 @@ public class MenuManagementService {
command.getIcon(), command.getIcon(),
command.getHidden(), command.getHidden(),
command.getOrderNumber(), command.getOrderNumber(),
command.getStatus(), EntityStatus.of(command.getStatus()),
command.getRemarks()); command.getRemarks());
} }
@@ -79,7 +80,7 @@ public class MenuManagementService {
command.getIcon(), command.getIcon(),
command.getHidden(), command.getHidden(),
command.getOrderNumber(), command.getOrderNumber(),
command.getStatus(), EntityStatus.of(command.getStatus()),
command.getComponent(), command.getComponent(),
command.getResource(), command.getResource(),
command.getCache(), command.getCache(),
@@ -88,15 +89,16 @@ public class MenuManagementService {
// ==================== delete ==================== // ==================== delete ====================
public void deleteMenu(Long id) { public void deleteMenu(Long id) {
Menu menuToDelete = menuRepository.find(id); Menu menuToDelete = menuRepository.find(id)
AssertResult.nonNull(menuToDelete); .orElseThrow(DataNotExistException::new);
menuRepository.delete(menuToDelete); menuRepository.delete(menuToDelete);
} }
// ==================== update ==================== // ==================== update ====================
public void updateMenu(Long id, @Valid UpdateMenuCommand command) { public void updateMenu(Long id, @Valid UpdateMenuCommand command) {
Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配"); Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配");
Menu menuToUpdate = menuRepository.find(command.getId()); Menu menuToUpdate = menuRepository.find(command.getId())
.orElseThrow(DataNotExistException::new);
menuToUpdate.updateMenuInfo( menuToUpdate.updateMenuInfo(
command.getMenuType(), command.getMenuType(),
command.getParentId(), command.getParentId(),
@@ -106,7 +108,7 @@ public class MenuManagementService {
command.getIcon(), command.getIcon(),
command.getHidden(), command.getHidden(),
command.getOrderNumber(), command.getOrderNumber(),
command.getStatus(), EntityStatus.of(command.getStatus()),
command.getComponent(), command.getComponent(),
command.getResource(), command.getResource(),
command.getCache(), command.getCache(),
@@ -118,7 +120,7 @@ public class MenuManagementService {
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public MenuViewObject findById(Long id) { public MenuViewObject findById(Long id) {
var menu = menuRepository.find(id); var menu = menuRepository.find(id);
return MenuViewObject.of(menu); return MenuViewObject.of(menu.orElseThrow(DataNotExistException::new));
} }
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)

View File

@@ -5,6 +5,7 @@ import java.util.Set;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException;
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType; import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil; import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException; import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
@@ -16,9 +17,7 @@ import xyz.zhouxy.plusone.system.domain.model.account.AccountStatus;
import xyz.zhouxy.plusone.system.domain.model.account.Email; 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.MobilePhone;
import xyz.zhouxy.plusone.system.domain.model.account.Password; import xyz.zhouxy.plusone.system.domain.model.account.Password;
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
import xyz.zhouxy.plusone.system.domain.model.account.Username; import xyz.zhouxy.plusone.system.domain.model.account.Username;
import xyz.zhouxy.plusone.validator.InvalidInputException;
/** /**
* 注册账号服务 * 注册账号服务
@@ -70,7 +69,7 @@ public class RegisterAccountService {
throw AccountRegisterException.emailAlreadyExists(mobilePhone.value()); throw AccountRegisterException.emailAlreadyExists(mobilePhone.value());
} }
} else { } else {
throw InvalidInputException.unsupportedPrincipalTypeException(); throw new UnsupportedPrincipalTypeException();
} }
verifyService.checkCode(emailOrMobilePhone, command.getCode()); verifyService.checkCode(emailOrMobilePhone, command.getCode());
@@ -82,7 +81,9 @@ public class RegisterAccountService {
Password.newPassword(command.getPassword(), command.getReenteredPassword()), Password.newPassword(command.getPassword(), command.getReenteredPassword()),
AccountStatus.AVAILABLE, AccountStatus.AVAILABLE,
Set.of(DEFAULT_ROLE_ID), Set.of(DEFAULT_ROLE_ID),
AccountInfo.of(command.getNickname(), null, Sex.UNSET)); AccountInfo.builder()
.nickname(command.getNickname())
.build());
accountRepository.save(accountToSave); accountRepository.save(accountToSave);
} }
@@ -93,7 +94,7 @@ public class RegisterAccountService {
} else if (principalType == PrincipalType.MOBILE_PHONE) { } else if (principalType == PrincipalType.MOBILE_PHONE) {
verifyService.sendCodeToMobilePhone(MobilePhone.of(principal)); verifyService.sendCodeToMobilePhone(MobilePhone.of(principal));
} else { } else {
throw InvalidInputException.unsupportedPrincipalTypeException(); throw new UnsupportedPrincipalTypeException();
} }
} }
} }

View File

@@ -10,6 +10,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.query.RoleQueries; import xyz.zhouxy.plusone.system.application.query.RoleQueries;
import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams; import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams;
import xyz.zhouxy.plusone.system.application.query.result.RoleOverview; import xyz.zhouxy.plusone.system.application.query.result.RoleOverview;
@@ -53,7 +55,7 @@ public class RoleManagementService {
Role roleToCreate = Role.newInstance( Role roleToCreate = Role.newInstance(
command.getName(), command.getName(),
command.getIdentifier(), command.getIdentifier(),
command.getStatus(), EntityStatus.of(command.getStatus()),
command.getRemarks(), command.getRemarks(),
menuRefs, menuRefs,
permissionRefs); permissionRefs);
@@ -62,11 +64,11 @@ public class RoleManagementService {
public void updateRole(@Valid UpdateRoleCommand command) { public void updateRole(@Valid UpdateRoleCommand command) {
Long roleId = command.getId(); Long roleId = command.getId();
Role roleToUpdate = _roleRepository.find(roleId); Role roleToUpdate = _roleRepository.find(roleId).orElseThrow(DataNotExistException::new);
roleToUpdate.update( roleToUpdate.update(
command.getName(), command.getName(),
command.getIdentifier(), command.getIdentifier(),
command.getStatus(), EntityStatus.of(command.getStatus()),
command.getRemarks(), command.getRemarks(),
Set.copyOf(_menuRepository.findByIdIn(command.getMenus())), Set.copyOf(_menuRepository.findByIdIn(command.getMenus())),
Set.copyOf(_menuRepository.findPermissionsByIdIn(command.getPermissions()))); Set.copyOf(_menuRepository.findPermissionsByIdIn(command.getPermissions())));
@@ -74,7 +76,7 @@ public class RoleManagementService {
} }
public void delete(Long id) { public void delete(Long id) {
Role role = _roleRepository.find(id); Role role = _roleRepository.find(id).orElseThrow(DataNotExistException::new);
_roleRepository.delete(role); _roleRepository.delete(role);
} }
@@ -85,7 +87,7 @@ public class RoleManagementService {
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public Role findById(Long id) { public Role findById(Long id) {
return _roleRepository.find(id); return _roleRepository.find(id).orElseThrow(DataNotExistException::new);
} }
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)

View File

@@ -10,10 +10,8 @@ import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import lombok.Data; import lombok.Data;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.RegexConsts;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
import xyz.zhouxy.plusone.system.domain.model.account.AccountStatus;
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
/** /**
* 创建账号命令 * 创建账号命令
@@ -41,7 +39,7 @@ public class CreateAccountCommand implements ICommand {
String passwordConfirmation; String passwordConfirmation;
@NotNull @NotNull
AccountStatus status; Integer status;
Set<Long> roleRefs; Set<Long> roleRefs;
@@ -52,5 +50,5 @@ public class CreateAccountCommand implements ICommand {
@URL @URL
String avatar; String avatar;
Sex sex; Integer sex;
} }

View File

@@ -5,7 +5,6 @@ import javax.validation.constraints.NotNull;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType; import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
@@ -42,7 +41,7 @@ public class CreateMenuCommand implements ICommand {
private Integer orderNumber; private Integer orderNumber;
@NotNull @NotNull
private EntityStatus status; private Integer status;
private String component; private String component;

View File

@@ -6,7 +6,6 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
/** /**
@@ -23,7 +22,7 @@ public class CreateRoleCommand implements ICommand {
String identifier; String identifier;
@NotNull @NotNull
EntityStatus status; Integer status;
String remarks; String remarks;
Set<Long> menus; Set<Long> menus;

View File

@@ -4,7 +4,7 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern; import javax.validation.constraints.Pattern;
import lombok.Data; import lombok.Data;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.RegexConsts;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
/** /**

View File

@@ -6,9 +6,8 @@ import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.URL; import org.hibernate.validator.constraints.URL;
import lombok.Data; import lombok.Data;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.RegexConsts;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
/** /**
* 更新账号信息命令 * 更新账号信息命令
@@ -27,5 +26,5 @@ public class UpdateAccountCommand implements ICommand {
@URL @URL
String avatar; String avatar;
Sex sex; Integer sex;
} }

View File

@@ -5,7 +5,6 @@ import javax.validation.constraints.NotNull;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType; import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
@@ -46,7 +45,7 @@ public class UpdateMenuCommand implements ICommand {
private Integer orderNumber; private Integer orderNumber;
@NotNull @NotNull
private EntityStatus status; private Integer status;
private String component; private String component;

View File

@@ -6,7 +6,6 @@ import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.ICommand; import xyz.zhouxy.plusone.domain.ICommand;
/** /**
@@ -27,7 +26,7 @@ public class UpdateRoleCommand implements ICommand {
String identifier; String identifier;
@NotNull @NotNull
EntityStatus status; Integer status;
@NotBlank @NotBlank
String remarks; String remarks;

View File

@@ -4,7 +4,7 @@ import java.util.List;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand; import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;
import xyz.zhouxy.plusone.validator.BaseValidator; import xyz.zhouxy.plusone.validator.BaseValidator;
import xyz.zhouxy.plusone.validator.DtoValidator; import xyz.zhouxy.plusone.validator.DtoValidator;
@@ -16,10 +16,10 @@ public class LoginByOtpCommandValidator extends BaseValidator<LoginByOtpCommand>
ruleForString(LoginByOtpCommand::getPrincipal) ruleForString(LoginByOtpCommand::getPrincipal)
.notNull("输入邮箱地址或手机号") .notNull("输入邮箱地址或手机号")
.notEmpty("输入邮箱地址或手机号") .notEmpty("输入邮箱地址或手机号")
.matchesOr(List.of(RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE), "输入用户名、邮箱地址或手机号"); .matchesOr(List.of(PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), "输入用户名、邮箱地址或手机号");
ruleForString(LoginByOtpCommand::getOtp) ruleForString(LoginByOtpCommand::getOtp)
.notNull("验证码不能为空") .notNull("验证码不能为空")
.notEmpty("验证码不能为空") .notEmpty("验证码不能为空")
.matches(RegexConsts.CAPTCHA, "验证码格式不正确"); .matches(PatternConsts.CAPTCHA, "验证码格式不正确");
} }
} }

View File

@@ -2,7 +2,8 @@ package xyz.zhouxy.plusone.system.application.service.command.validator;
import java.util.List; import java.util.List;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import xyz.zhouxy.plusone.constant.RegexConsts;
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand; import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand;
import xyz.zhouxy.plusone.validator.BaseValidator; import xyz.zhouxy.plusone.validator.BaseValidator;
import xyz.zhouxy.plusone.validator.DtoValidator; import xyz.zhouxy.plusone.validator.DtoValidator;
@@ -14,11 +15,11 @@ public class LoginByPasswordCommandValidator extends BaseValidator<LoginByPasswo
ruleForString(LoginByPasswordCommand::getPrincipal) ruleForString(LoginByPasswordCommand::getPrincipal)
.notNull("输入用户名、邮箱地址或手机号") .notNull("输入用户名、邮箱地址或手机号")
.notEmpty("输入用户名、邮箱地址或手机号") .notEmpty("输入用户名、邮箱地址或手机号")
.matchesOr(List.of(RegexConsts.USERNAME, RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE), .matchesOr(List.of(PatternConsts.USERNAME, PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE),
"输入用户名、邮箱地址或手机号"); "输入用户名、邮箱地址或手机号");
ruleForString(LoginByPasswordCommand::getPassword) ruleForString(LoginByPasswordCommand::getPassword)
.notNull("密码不能为空") .notNull("密码不能为空")
.notEmpty("密码不能为空") .notEmpty("密码不能为空")
.matches(RegexConsts.PASSWORD, "密码格式不正确"); .matches(PatternConsts.PASSWORD, "密码格式不正确");
} }
} }

View File

@@ -14,10 +14,6 @@
<groupId>xyz.zhouxy</groupId> <groupId>xyz.zhouxy</groupId>
<artifactId>plusone-basic-common</artifactId> <artifactId>plusone-basic-common</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -1,19 +1,26 @@
package xyz.zhouxy.plusone.system.util; package xyz.zhouxy.plusone.system.util;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import cn.hutool.core.util.RandomUtil; import lombok.extern.slf4j.Slf4j;
import cn.hutool.crypto.digest.DigestUtil;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts; import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.util.RandomUtil;
/** /**
* 密码工具类 * 密码工具类
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@Slf4j
public final class PasswordUtil { public final class PasswordUtil {
private static final String SALT_BASE_STRING = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]|\\:;\"',.<>?/"; private static final char[] SALT_BASE_CHAR_ARRAY = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]|\\:;\"',.<>?/"
.toCharArray();
/** /**
* 将密码和随机盐混合,并进行哈希加密。 * 将密码和随机盐混合,并进行哈希加密。
@@ -29,9 +36,9 @@ public final class PasswordUtil {
var passwordWithSalt = salt.substring(0, i) var passwordWithSalt = salt.substring(0, i)
+ password + password
+ salt.substring(1); + salt.substring(1);
String sha512Hex = DigestUtil.sha512Hex(passwordWithSalt); String sha512Hex = sha512Hex(passwordWithSalt);
if (sha512Hex == null) { if (sha512Hex == null) {
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:哈希加密失败!"); throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:哈希加密失败!");
} }
return sha512Hex; return sha512Hex;
} }
@@ -42,11 +49,23 @@ public final class PasswordUtil {
* @return 生成的随机盐 * @return 生成的随机盐
*/ */
public static String generateRandomSalt() { public static String generateRandomSalt() {
return RandomUtil.randomString(SALT_BASE_STRING, 24); return RandomUtil.randomStr(SALT_BASE_CHAR_ARRAY, 24);
} }
private PasswordUtil() { private PasswordUtil() {
// 不允许实例化 // 不允许实例化
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
private static String sha512Hex(String data) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
messageDigest.update(data.getBytes(StandardCharsets.UTF_8));
byte[] result = messageDigest.digest();
return new BigInteger(1, result).toString(16);
} catch (NoSuchAlgorithmException e) {
log.error("{}", e);
}
return null;
}
} }

View File

@@ -27,7 +27,7 @@ public class AccountCreated extends DomainEvent {
public AccountCreated(Account account) { public AccountCreated(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.email = account.getEmail(); this.email = account.getEmail().orElse(null);
this.mobilePhone = account.getMobilePhone(); this.mobilePhone = account.getMobilePhone().orElse(null);
} }
} }

View File

@@ -27,7 +27,7 @@ public class AccountLocked extends DomainEvent {
public AccountLocked(Account account) { public AccountLocked(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.email = account.getEmail(); this.email = account.getEmail().orElse(null);
this.mobilePhone = account.getMobilePhone(); this.mobilePhone = account.getMobilePhone().orElse(null);
} }
} }

View File

@@ -27,8 +27,8 @@ public class AccountPasswordChanged extends DomainEvent {
public AccountPasswordChanged(Account account) { public AccountPasswordChanged(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.email = account.getEmail(); this.email = account.getEmail().orElse(null);
this.mobilePhone = account.getMobilePhone(); this.mobilePhone = account.getMobilePhone().orElse(null);
} }
} }

View File

@@ -25,6 +25,6 @@ public class EmailChanged extends DomainEvent {
public EmailChanged(Account account) { public EmailChanged(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.email = account.getEmail(); this.email = account.getEmail().orElse(null);
} }
} }

View File

@@ -25,6 +25,6 @@ public class MobilePhoneChanged extends DomainEvent {
public MobilePhoneChanged(Account account) { public MobilePhoneChanged(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.mobilePhone = account.getMobilePhone(); this.mobilePhone = account.getMobilePhone().orElse(null);
} }
} }

View File

@@ -27,7 +27,7 @@ public class UsernameChanged extends DomainEvent {
public UsernameChanged(Account account) { public UsernameChanged(Account account) {
this.username = account.getUsername(); this.username = account.getUsername();
this.email = account.getEmail(); this.email = account.getEmail().orElse(null);
this.mobilePhone = account.getMobilePhone(); this.mobilePhone = account.getMobilePhone().orElse(null);
} }
} }

View File

@@ -5,8 +5,6 @@ import java.util.HashSet;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IWithVersion; import xyz.zhouxy.plusone.domain.IWithVersion;
@@ -30,17 +28,17 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
// ===================== 字段 ==================== // ===================== 字段 ====================
private Long id; private Long id;
private @Getter Username username; private Username username;
private @Getter Email email; private Email email;
private @Getter MobilePhone mobilePhone; private MobilePhone mobilePhone;
private Password password; private Password password;
private @Getter AccountStatus status; private AccountStatus status;
private @Getter AccountInfo accountInfo; private AccountInfo accountInfo;
private Set<Long> roleRefs = new HashSet<>(); private Set<Long> roleRefs = new HashSet<>();
private @Getter Long createdBy; private Long createdBy;
private @Getter @Setter Long updatedBy; private Long updatedBy;
private @Getter long version; private long version;
public void setUsername(Username username) { public void setUsername(Username username) {
this.username = username; this.username = username;
@@ -95,11 +93,19 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
} }
public void setAccountInfo(Nickname nickname, URL avatar, Sex sex) { public void setAccountInfo(Nickname nickname, URL avatar, Sex sex) {
this.accountInfo = AccountInfo.of(nickname, avatar, sex); this.accountInfo = AccountInfo.builder()
.nickname(nickname)
.avatar(avatar)
.sex(sex)
.build();
} }
public void setAccountInfo(String nickname, String avatar, Sex sex) { public void setAccountInfo(String nickname, String avatar, Sex sex) {
this.accountInfo = AccountInfo.of(nickname, avatar, sex); this.accountInfo = AccountInfo.builder()
.nickname(nickname)
.avatar(avatar)
.sex(sex)
.build();
} }
/** /**
@@ -223,11 +229,48 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
return Optional.ofNullable(id); return Optional.ofNullable(id);
} }
public Set<Long> getRoleIds() { public Username getUsername() {
return Set.copyOf(this.roleRefs); return username;
}
public Optional<Email> getEmail() {
return Optional.ofNullable(email);
}
public Optional<MobilePhone> getMobilePhone() {
return Optional.ofNullable(mobilePhone);
} }
Password getPassword() { Password getPassword() {
return password; return password;
} }
public AccountStatus getStatus() {
return status;
}
public AccountInfo getAccountInfo() {
return accountInfo;
}
public Set<Long> getRoleIds() {
return Set.copyOf(roleRefs);
}
public Optional<Long> getCreatedBy() {
return Optional.ofNullable(createdBy);
}
public Optional<Long> getUpdatedBy() {
return Optional.ofNullable(updatedBy);
}
public void setUpdatedBy(long updatedBy) {
this.updatedBy = updatedBy;
}
@Override
public long getVersion() {
return this.version;
}
} }

View File

@@ -3,8 +3,11 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
@@ -13,31 +16,77 @@ import xyz.zhouxy.plusone.domain.IValueObject;
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@Getter
@ToString @ToString
public class AccountInfo implements IValueObject { public class AccountInfo implements IValueObject {
@Nullable
private final Nickname nickname; private final Nickname nickname;
@Nullable
private final URL avatar; private final URL avatar;
@Nonnull
private final Sex sex; private final Sex sex;
private AccountInfo(Nickname nickname, URL avatar, Sex sex) { private AccountInfo(@Nullable Nickname nickname, @Nullable URL avatar, @Nullable Sex sex) {
this.nickname = nickname; this.nickname = nickname;
this.avatar = avatar; this.avatar = avatar;
this.sex = Objects.nonNull(sex) ? sex : Sex.UNSET; this.sex = Objects.nonNull(sex) ? sex : Sex.UNSET;
} }
public static AccountInfo of(Nickname nickname, URL avatar, Sex sex) { public Optional<Nickname> getNickname() {
return new AccountInfo(nickname, avatar, sex); return Optional.ofNullable(nickname);
} }
public static AccountInfo of(String nickname, String avatar, Sex sex) { public Optional<URL> getAvatar() {
return Optional.ofNullable(avatar);
}
@Nonnull
public Sex getSex() {
return this.sex;
}
// Builder
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Nickname nickname;
private URL avatar;
private Sex sex;
public Builder nickname(@Nullable Nickname nickname) {
this.nickname = nickname;
return this;
}
public Builder nickname(@Nullable String nickname) {
return nickname(Nickname.ofNullable(nickname));
}
public Builder avatar(@Nullable URL avatar) {
this.avatar = avatar;
return this;
}
public Builder avatar(@Nullable String avatar) {
URL avatarURL; URL avatarURL;
try { try {
avatarURL = Objects.nonNull(avatar) ? new URL(avatar) : null; avatarURL = Objects.nonNull(avatar) ? new URL(avatar) : null;
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
throw new IllegalArgumentException(e); throw new IllegalArgumentException(e);
} }
return new AccountInfo(Nickname.ofNullable(nickname), avatarURL, sex); return avatar(avatarURL);
}
public Builder sex(@Nullable Sex sex) {
this.sex = sex;
return this;
}
public AccountInfo build() {
return new AccountInfo(this.nickname, this.avatar, this.sex);
}
} }
} }

View File

@@ -1,6 +1,7 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Collection; import java.util.Collection;
import java.util.Optional;
import xyz.zhouxy.plusone.domain.IRepository; import xyz.zhouxy.plusone.domain.IRepository;
@@ -14,11 +15,11 @@ public interface AccountRepository extends IRepository<Account, Long> {
Collection<Account> findByRoleId(Long roleId); Collection<Account> findByRoleId(Long roleId);
Account findByEmail(Email email); Optional<Account> findByEmail(Email email);
Account findByMobilePhone(MobilePhone mobilePhone); Optional<Account> findByMobilePhone(MobilePhone mobilePhone);
Account findByUsername(Username username); Optional<Account> findByUsername(Username username);
boolean existsUsername(Username username); boolean existsUsername(Username username);

View File

@@ -1,9 +1,12 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Collection;
import javax.annotation.Nonnull;
import lombok.Getter; import lombok.Getter;
import xyz.zhouxy.plusone.commons.util.Enumeration;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
import xyz.zhouxy.plusone.util.Enumeration;
import xyz.zhouxy.plusone.util.EnumerationValuesHolder;
/** /**
* 账号状态 * 账号状态
@@ -11,19 +14,24 @@ import xyz.zhouxy.plusone.util.EnumerationValuesHolder;
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@Getter @Getter
public class AccountStatus extends Enumeration<AccountStatus> implements IValueObject { public final class AccountStatus extends Enumeration<AccountStatus> implements IValueObject {
private AccountStatus(int value, String name) { private AccountStatus(int id, @Nonnull String name) {
super(value, name); super(id, name);
} }
public static final AccountStatus AVAILABLE = new AccountStatus(0, "账号正常"); public static final AccountStatus AVAILABLE = new AccountStatus(0, "账号正常");
public static final AccountStatus LOCKED = new AccountStatus(1, "账号被锁定"); public static final AccountStatus LOCKED = new AccountStatus(1, "账号被锁定");
private static final EnumerationValuesHolder<AccountStatus> ENUMERATION_VALUES = new EnumerationValuesHolder<>( private static final ValueSet<AccountStatus> VALUE_SET = new ValueSet<>(
new AccountStatus[] { AVAILABLE, LOCKED }); AVAILABLE,
LOCKED);
public static AccountStatus of(int value) { public static AccountStatus of(int id) {
return ENUMERATION_VALUES.get(value); return VALUE_SET.get(id);
}
public static Collection<AccountStatus> constants() {
return VALUE_SET.getValues();
} }
} }

View File

@@ -1,9 +1,10 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern;
import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.DesensitizedUtil;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
* 值对象:电子邮箱地址 * 值对象:电子邮箱地址
@@ -12,7 +13,7 @@ import xyz.zhouxy.plusone.constant.RegexConsts;
*/ */
public class Email extends Principal { public class Email extends Principal {
public static final String REGEX = RegexConsts.EMAIL; public static final Pattern REGEX = PatternConsts.EMAIL;
private Email(String email) { private Email(String email) {
super(REGEX); super(REGEX);

View File

@@ -1,9 +1,10 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern;
import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.DesensitizedUtil;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
* 值对象:手机号码 * 值对象:手机号码
@@ -12,7 +13,7 @@ import xyz.zhouxy.plusone.constant.RegexConsts;
*/ */
public class MobilePhone extends Principal { public class MobilePhone extends Principal {
public static final String REGEX = RegexConsts.MOBILE_PHONE; public static final Pattern REGEX = PatternConsts.MOBILE_PHONE;
private MobilePhone(String mobilePhone) { private MobilePhone(String mobilePhone) {
super(REGEX); super(REGEX);

View File

@@ -1,8 +1,9 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern;
import xyz.zhouxy.plusone.constant.RegexConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.domain.ValidatableStringRecord; import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
/** /**
@@ -12,7 +13,7 @@ import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
*/ */
public class Nickname extends ValidatableStringRecord { public class Nickname extends ValidatableStringRecord {
public static final String REGEX = RegexConsts.NICKNAME; public static final Pattern REGEX = PatternConsts.NICKNAME;
private Nickname(String value) { private Nickname(String value) {
super(REGEX); super(REGEX);

View File

@@ -7,10 +7,10 @@ import javax.annotation.Nonnull;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts; import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.constant.RegexConsts;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
import xyz.zhouxy.plusone.exception.PlusoneException; import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.system.util.PasswordUtil; import xyz.zhouxy.plusone.system.util.PasswordUtil;
/** /**
@@ -20,7 +20,7 @@ import xyz.zhouxy.plusone.system.util.PasswordUtil;
*/ */
public class Password implements IValueObject { public class Password implements IValueObject {
private static final Pattern PATTERN = Pattern.compile(RegexConsts.PASSWORD); private static final Pattern PATTERN = PatternConsts.PASSWORD;
private static final String DEFAULT_PASSWORD = "A1b2C3d4"; private static final String DEFAULT_PASSWORD = "A1b2C3d4";
@Nonnull @Nonnull
@@ -37,7 +37,7 @@ public class Password implements IValueObject {
} }
var salt = PasswordUtil.generateRandomSalt(); var salt = PasswordUtil.generateRandomSalt();
if (salt == null) { if (salt == null) {
throw new PlusoneException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:生成随机盐失败"); throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:生成随机盐失败");
} }
this.saltVal = salt; this.saltVal = salt;
this.passwordVal = PasswordUtil.hashPassword(password, salt); this.passwordVal = PasswordUtil.hashPassword(password, salt);

View File

@@ -1,5 +1,7 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.regex.Pattern;
import xyz.zhouxy.plusone.domain.ValidatableStringRecord; import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
/** /**
@@ -8,7 +10,7 @@ import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
public abstract class Principal extends ValidatableStringRecord { public abstract class Principal extends ValidatableStringRecord {
protected Principal(String format) { protected Principal(Pattern format) {
super(format); super(format);
} }
} }

View File

@@ -1,30 +1,36 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Collection;
import javax.annotation.Nonnull;
import xyz.zhouxy.plusone.commons.util.Enumeration;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
import xyz.zhouxy.plusone.util.Enumeration;
import xyz.zhouxy.plusone.util.EnumerationValuesHolder;
/** /**
* 值对象:性别 * 值对象:性别
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
public class Sex extends Enumeration<Sex> implements IValueObject { public final class Sex extends Enumeration<Sex> implements IValueObject {
@Nonnull
public static final Sex UNSET = new Sex(0, "未设置"); public static final Sex UNSET = new Sex(0, "未设置");
@Nonnull
public static final Sex MALE = new Sex(1, "男性"); public static final Sex MALE = new Sex(1, "男性");
@Nonnull
public static final Sex FEMALE = new Sex(2, "女性"); public static final Sex FEMALE = new Sex(2, "女性");
private Sex(int value, String name) { private Sex(int id, @Nonnull String name) {
super(value, name); super(id, name);
} }
private static EnumerationValuesHolder<Sex> values = new EnumerationValuesHolder<>(new Sex[] { private static final ValueSet<Sex> VALUE_SET = new ValueSet<>(UNSET, MALE, FEMALE);
UNSET,
MALE,
FEMALE
});
public static Sex of(int value) { public static Sex of(int value) {
return values.get(value); return VALUE_SET.get(value);
}
public static Collection<Sex> constants() {
return VALUE_SET.getValues();
} }
} }

View File

@@ -1,6 +1,8 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import xyz.zhouxy.plusone.constant.RegexConsts; import java.util.regex.Pattern;
import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
* 值对象:用户名 * 值对象:用户名
@@ -9,7 +11,7 @@ import xyz.zhouxy.plusone.constant.RegexConsts;
*/ */
public class Username extends Principal { public class Username extends Principal {
public static final String REGEX = RegexConsts.USERNAME; public static final Pattern REGEX = PatternConsts.USERNAME;
private Username(String username) { private Username(String username) {
super(REGEX); super(REGEX);

View File

@@ -6,7 +6,6 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
@@ -115,7 +114,7 @@ public class Dict extends AggregateRoot<Long> implements IWithLabel, IWithVersio
} }
public Set<DictValue> getValues() { public Set<DictValue> getValues() {
return this.values.values().stream().collect(Collectors.toSet()); return Set.copyOf(this.values.values());
} }
@Override @Override

View File

@@ -4,7 +4,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.Objects; import java.util.Optional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@@ -14,8 +14,8 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import static xyz.zhouxy.plusone.domain.ValidatableStringRecord.getValueOrNull;
import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport; import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport;
import xyz.zhouxy.plusone.util.AssertResult;
/** /**
* AccountRepository 实现类 * AccountRepository 实现类
@@ -41,11 +41,11 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
new MapSqlParameterSource() new MapSqlParameterSource()
.addValue("id", entity.getId().orElseThrow()) .addValue("id", entity.getId().orElseThrow())
.addValue("version", entity.getVersion())); .addValue("version", entity.getVersion()));
AssertResult.updateOneRow(i); assertUpdateOneRow(i);
} }
@Override @Override
protected final Account doFindById(@Nonnull Long id) { protected final Optional<Account> doFindById(@Nonnull Long id) {
return queryForObject(""" return queryForObject("""
SELECT SELECT
id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status, id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status,
@@ -57,7 +57,7 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
} }
@Override @Override
public Account findByEmail(Email email) { public Optional<Account> findByEmail(Email email) {
return queryForObject(""" return queryForObject("""
SELECT SELECT
id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status, id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status,
@@ -69,7 +69,7 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
} }
@Override @Override
public Account findByMobilePhone(MobilePhone mobilePhone) { public Optional<Account> findByMobilePhone(MobilePhone mobilePhone) {
return queryForObject(""" return queryForObject("""
SELECT SELECT
id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status, id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status,
@@ -81,7 +81,7 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
} }
@Override @Override
public Account findByUsername(Username username) { public Optional<Account> findByUsername(Username username) {
return queryForObject(""" return queryForObject("""
SELECT SELECT
id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status, id, email, mobile_phone, username, "password", salt, avatar, sex, nickname, status,
@@ -94,25 +94,27 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
@Override @Override
public boolean exists(Long id) { public boolean exists(Long id) {
return queryExists("SELECT 1 FROM sys_account WHERE id = :id AND deleted = 0 LIMIT 1", return queryForBool("SELECT EXISTS (SELECT 1 FROM sys_account WHERE id = :id AND deleted = 0 LIMIT 1)",
"id", id); "id", id);
} }
@Override @Override
public boolean existsUsername(Username username) { public boolean existsUsername(Username username) {
return queryExists("SELECT 1 FROM sys_account WHERE username = :username AND deleted = 0 LIMIT 1", return queryForBool(
"SELECT EXISTS (SELECT 1 FROM sys_account WHERE username = :username AND deleted = 0 LIMIT 1)",
"username", username.value()); "username", username.value());
} }
@Override @Override
public boolean existsEmail(Email email) { public boolean existsEmail(Email email) {
return queryExists("SELECT 1 FROM sys_account WHERE email = :email AND deleted = 0 LIMIT 1", return queryForBool("SELECT EXISTS (SELECT 1 FROM sys_account WHERE email = :email AND deleted = 0 LIMIT 1)",
"email", email.value()); "email", email.value());
} }
@Override @Override
public boolean existsMobilePhone(MobilePhone mobilePhone) { public boolean existsMobilePhone(MobilePhone mobilePhone) {
return queryExists("SELECT 1 FROM sys_account WHERE mobile_phone = :mobile_phone AND deleted = 0 LIMIT 1", return queryForBool(
"SELECT EXISTS (SELECT 1 FROM sys_account WHERE mobile_phone = :mobile_phone AND deleted = 0 LIMIT 1)",
"mobile_phone", mobilePhone.value()); "mobile_phone", mobilePhone.value());
} }
@@ -142,9 +144,9 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
:createdBy, :createTime) :createdBy, :createTime)
""", """,
generateParamSource(id, entity)); generateParamSource(id, entity));
AssertResult.updateOneRow(i); assertUpdateOneRow(i);
this.accountRoleDAO.insertAccountRoleRefs(id, entity.getRoleIds()); this.accountRoleDAO.insertAccountRoleRefs(id, entity.getRoleIds());
return entity; return find(id).orElseThrow();
} }
@Override @Override
@@ -166,18 +168,14 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
WHERE id = :id AND deleted = 0 AND "version" = :version WHERE id = :id AND deleted = 0 AND "version" = :version
""", """,
generateParamSource(entity)); generateParamSource(entity));
AssertResult.updateOneRow(i); assertUpdateOneRow(i);
this.accountRoleDAO.saveAccountRoleRefs(entity); this.accountRoleDAO.saveAccountRoleRefs(entity);
return entity; return find(entity.getId().orElseThrow()).orElseThrow();
} }
@Override @Override
protected final Account mapRow(ResultSet rs) throws SQLException { protected final Account mapRow(ResultSet rs) throws SQLException {
long accountId = rs.getLong("id"); long accountId = rs.getLong("id");
AccountInfo accountInfo = AccountInfo.of(
rs.getString("nickname"),
rs.getString("avatar"),
Sex.of(rs.getInt("sex")));
return new Account( return new Account(
accountId, accountId,
rs.getString("username"), rs.getString("username"),
@@ -185,7 +183,11 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
rs.getString("mobile_phone"), rs.getString("mobile_phone"),
Password.of(rs.getString("password"), rs.getString("salt")), Password.of(rs.getString("password"), rs.getString("salt")),
AccountStatus.of(rs.getInt("status")), AccountStatus.of(rs.getInt("status")),
accountInfo, AccountInfo.builder()
.nickname(rs.getString("nickname"))
.avatar(rs.getString("avatar"))
.sex(Sex.of(rs.getInt("sex")))
.build(),
this.accountRoleDAO.selectRoleIdsByAccountId(accountId), this.accountRoleDAO.selectRoleIdsByAccountId(accountId),
rs.getLong("created_by"), rs.getLong("created_by"),
rs.getLong("updated_by"), rs.getLong("updated_by"),
@@ -198,17 +200,15 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
AccountInfo accountInfo = entity.getAccountInfo(); AccountInfo accountInfo = entity.getAccountInfo();
return new MapSqlParameterSource() return new MapSqlParameterSource()
.addValue("id", id) .addValue("id", id)
.addValue("email", Objects.nonNull(entity.getEmail()) ? entity.getEmail().value() : null) .addValue("email", getValueOrNull(entity.getEmail()))
.addValue("mobilePhone", .addValue("mobilePhone", getValueOrNull(entity.getMobilePhone()))
Objects.nonNull(entity.getMobilePhone()) ? entity.getMobilePhone().value() : null)
.addValue("username", entity.getUsername().value()) .addValue("username", entity.getUsername().value())
.addValue("password", entity.getPassword().value()) .addValue("password", entity.getPassword().value())
.addValue("salt", entity.getPassword().getSalt()) .addValue("salt", entity.getPassword().getSalt())
.addValue("avatar", accountInfo.getAvatar().toString()) .addValue("avatar", accountInfo.getAvatar().toString())
.addValue("sex", accountInfo.getSex().getValue()) .addValue("sex", accountInfo.getSex().getId())
.addValue("nickname", .addValue("nickname", getValueOrNull(accountInfo.getNickname()))
Objects.nonNull(accountInfo.getNickname()) ? accountInfo.getNickname().value() : null) .addValue("status", entity.getStatus().getId())
.addValue("status", entity.getStatus().getValue())
.addValue("createdBy", entity.getCreatedBy()) .addValue("createdBy", entity.getCreatedBy())
.addValue("createTime", now) .addValue("createTime", now)
.addValue("updatedBy", entity.getUpdatedBy()) .addValue("updatedBy", entity.getUpdatedBy())

View File

@@ -1,47 +1,43 @@
package xyz.zhouxy.plusone.system.domain.model.account; package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import xyz.zhouxy.plusone.util.AssertResult; import xyz.zhouxy.plusone.jdbc.PlusoneJdbcDaoSupport;
import xyz.zhouxy.plusone.util.NumberUtil;
class AccountRoleRefDAO { class AccountRoleRefDAO extends PlusoneJdbcDaoSupport {
private final NamedParameterJdbcTemplate jdbc;
AccountRoleRefDAO(NamedParameterJdbcTemplate jdbc) { AccountRoleRefDAO(@Nonnull NamedParameterJdbcTemplate jdbc) {
this.jdbc = jdbc; super(jdbc);
} }
Set<Long> selectRoleIdsByAccountId(Long accountId) { Set<Long> selectRoleIdsByAccountId(Long accountId) {
List<Long> roleRefs = this.jdbc.queryForList(""" return queryForStream("""
SELECT r.id FROM sys_role r RIGHT JOIN sys_account_role ar ON r.id = ar.role_id SELECT r.id FROM sys_role r RIGHT JOIN sys_account_role ar ON r.id = ar.role_id
WHERE r.deleted = 0 AND ar.account_id = :accountId; WHERE r.deleted = 0 AND ar.account_id = :accountId;
""", """,
new MapSqlParameterSource("accountId", accountId), "accountId", accountId,
Long.TYPE); Long.TYPE)
return new HashSet<>(roleRefs); .collect(Collectors.toSet());
} }
void clearAccountRoleRefs(Account entity) { void clearAccountRoleRefs(Account entity) {
var param = new MapSqlParameterSource("accountId", entity.getId().orElseThrow()); update("DELETE FROM sys_account_role WHERE account_id = :accountId", "accountId", entity.getId().orElseThrow());
this.jdbc.update("DELETE FROM sys_account_role WHERE account_id = :accountId", param);
} }
void insertAccountRoleRefs(Long accountId, Set<Long> roleRefs) { void insertAccountRoleRefs(Long accountId, Set<Long> roleRefs) {
String sql = "INSERT INTO sys_account_role (account_id, role_id) VALUES (:accountId, :roleId)"; long i = batchUpdate(
MapSqlParameterSource[] batchArgs = roleRefs "INSERT INTO sys_account_role (account_id, role_id) VALUES (:accountId, :roleId)",
.stream() roleRefs,
.map((Long roleId) -> new MapSqlParameterSource() (Long roleId) -> new MapSqlParameterSource()
.addValue("accountId", accountId) .addValue("accountId", accountId)
.addValue("roleId", roleId)) .addValue("roleId", roleId));
.toArray(MapSqlParameterSource[]::new); assertResultEquals(i, roleRefs.size());
int[] i = this.jdbc.batchUpdate(sql, batchArgs);
AssertResult.update(roleRefs.size(), NumberUtil.sum(i));
} }
void saveAccountRoleRefs(Account entity) { void saveAccountRoleRefs(Account entity) {

Some files were not shown because too many files have changed in this diff Show More