Compare commits

..

No commits in common. "dev" and "main" have entirely different histories.
dev ... main

93 changed files with 551 additions and 851 deletions

View File

@ -18,11 +18,4 @@
目前项目还没完成,开发中…… 目前项目还没完成,开发中……
相关的文档和介绍完善中…… 相关的文档和介绍完善中……
## 编码规约
### 关于 null
1. 方法默认参数不为 `null`**可以**在 Javadoc 中对参数进行说明,如“...(must not be {@code null}[ or empty string])”。方法内部**必须**做参数校验,如使用 Assert 等工具类。
2. 如果参数允许为空,**必须**为参数添加 `@Nullable` 注解,并在 Javadoc 中对参数进行说明,如“...(may be {@code null})”。
3. 除极特殊的情况,方法默认**不返回 `null`**,如可能返回一个对象表示值的缺失,则**必须**使用 `Optional`**绝不在返回类型为 Optional 的方法中返回 `null`**。
4. 在极其特殊的情况下,方法需要返回 `null`**必须**给方法加上 `@Nullable` 注解,并在 Javadoc 中详细说明。

View File

@ -222,10 +222,6 @@
{ {
"code": 4040201, "code": 4040201,
"description": "不支持的 PrincipalType" "description": "不支持的 PrincipalType"
},
{
"code": 4040209,
"description": "不支持的菜单类型"
} }
] ]
}, },

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone-basic</artifactId> <artifactId>plusone-basic</artifactId>

View File

@ -14,7 +14,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
/** /**
* *
@ -62,7 +62,7 @@ public class DefaultExceptionHandler extends BaseExceptionHandler {
DataAccessException.class, DataAccessException.class,
MethodArgumentNotValidException.class MethodArgumentNotValidException.class
}) })
public ResponseEntity<UnifiedResponse> handleException(Exception e) { public ResponseEntity<RestfulResult> handleException(Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return buildExceptionResponse(e); return buildExceptionResponse(e);
} }

View File

@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.exception.SysException; import xyz.zhouxy.plusone.exception.SysException;
@RestControllerAdvice @RestControllerAdvice
@ -21,9 +21,9 @@ public class SysExceptionHandler extends BaseExceptionHandler {
} }
@ExceptionHandler({ SysException.class }) @ExceptionHandler({ SysException.class })
public ResponseEntity<UnifiedResponse> handleException(@Nonnull Exception e) { public ResponseEntity<RestfulResult> handleException(@Nonnull Exception e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
HttpStatus httpStatus = getHttpStatus(e); HttpStatus httpStatus = getHttpStatus(e);
return new ResponseEntity<>(UnifiedResponse.error(getErrorCode(e), "系统错误"), httpStatus); return new ResponseEntity<>(RestfulResult.error(getErrorCode(e), "系统错误"), httpStatus);
} }
} }

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone-basic</artifactId> <artifactId>plusone-basic</artifactId>

View File

@ -2,8 +2,6 @@ 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;
public static final int DEFAULT_SYS_ERROR_CODE = 5000000;
public static final int DEFAULT_BIZ_ERROR_CODE = 4000000;
private ErrorCodeConsts() { private ErrorCodeConsts() {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");

View File

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

View File

@ -14,7 +14,7 @@ public class DataNotExistException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 6536955800679703111L; private static final long serialVersionUID = 6536955800679703111L;
public static final String ERROR_CODE = "4110100"; public static final int ERROR_CODE = 4110100;
public DataNotExistException() { public DataNotExistException() {
super(ERROR_CODE, "数据不存在"); super(ERROR_CODE, "数据不存在");

View File

@ -18,7 +18,7 @@ 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 String ERROR_CODE = "4110200"; public static final int ERROR_CODE = 4110200;
public DataOperationResultException() { public DataOperationResultException() {
super(ERROR_CODE, "数据操作结果不符合预期"); super(ERROR_CODE, "数据操作结果不符合预期");

View File

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

View File

@ -14,28 +14,28 @@ public class UserOperationException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = 4371055414421991940L; private static final long serialVersionUID = 4371055414421991940L;
public static final String DEFAULT_ERROR_CODE = "4040600"; public static final int DEFAULT_ERROR_CODE = 4040600;
public UserOperationException(String code, String msg) { public UserOperationException(String msg) {
super(DEFAULT_ERROR_CODE, msg);
}
public UserOperationException(String msg, Throwable cause) {
super(DEFAULT_ERROR_CODE, msg, cause);
}
public UserOperationException(int code, String msg) {
super(code, msg); super(code, msg);
} }
public UserOperationException(String code, Throwable cause) { public UserOperationException(int code, Throwable cause) {
super(code, cause); super(code, cause);
} }
public UserOperationException(String code, String msg, Throwable cause) { public UserOperationException(int code, String msg, Throwable cause) {
super(code, msg, cause); super(code, msg, cause);
} }
public static UserOperationException of(String msg) {
return new UserOperationException(DEFAULT_ERROR_CODE, msg);
}
public static UserOperationException of(String msg, Throwable cause) {
return new UserOperationException(DEFAULT_ERROR_CODE, msg, cause);
}
/** /**
* *
* *
@ -52,7 +52,7 @@ public class UserOperationException extends BizException {
* @return * @return
*/ */
public static UserOperationException invalidOperation(String msg) { public static UserOperationException invalidOperation(String msg) {
return new UserOperationException("4040604", msg); return new UserOperationException(4040604, msg);
} }
} }

View File

@ -1,5 +1,9 @@
package xyz.zhouxy.plusone.util; package xyz.zhouxy.plusone.util;
import java.util.Objects;
import java.util.regex.Pattern;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -23,4 +27,17 @@ public class PlusoneStrUtil {
return StringUtils.hasLength(value) ? value : EMPTY_STR; return StringUtils.hasLength(value) ? value : EMPTY_STR;
} }
public static String checkString(String value, String regex, String message) {
Assert.notNull(value, message);
Assert.isTrue(Pattern.matches(regex, value), message);
return value;
}
public static String checkStringNullable(String value, String regex, String message) {
return Objects.nonNull(value) ? checkString(value, regex, message) : null;
}
public static String checkStringOrDefault(String value, String regex, String message) {
return StringUtils.hasText(value) ? checkString(value, regex, message) : "";
}
} }

View File

@ -1,6 +1,6 @@
package xyz.zhouxy.plusone.util; package xyz.zhouxy.plusone.util;
import java.security.SecureRandom; import java.util.concurrent.ThreadLocalRandom;
public final class RandomUtil { public final class RandomUtil {
private RandomUtil() { private RandomUtil() {
@ -8,7 +8,7 @@ public final class RandomUtil {
} }
public static String randomStr(char[] sourceCharacters, int length) { public static String randomStr(char[] sourceCharacters, int length) {
SecureRandom random = new SecureRandom(); ThreadLocalRandom random = ThreadLocalRandom.current();
char[] result = new char[length]; char[] result = new char[length];
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
result[i] = sourceCharacters[random.nextInt(sourceCharacters.length)]; result[i] = sourceCharacters[random.nextInt(sourceCharacters.length)];

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>xyz.zhouxy</groupId> <groupId>xyz.zhouxy</groupId>

View File

@ -21,7 +21,8 @@ public final class EntityStatus extends Enumeration<EntityStatus> {
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 ValueSet<EntityStatus> VALUE_SET = ValueSet.of(AVAILABLE, DISABLED); private static final ValueSet<EntityStatus> VALUE_SET = new ValueSet<>(
AVAILABLE, DISABLED);
public static EntityStatus of(int id) { public static EntityStatus of(int id) {
return VALUE_SET.get(id); return VALUE_SET.get(id);

View File

@ -17,8 +17,8 @@ import lombok.Getter;
*/ */
@Getter @Getter
public abstract class DomainEvent { public abstract class DomainEvent {
private final String identifier; private String identifier;
private final long happenedAt; private long happenedAt;
protected DomainEvent() { protected DomainEvent() {
this.identifier = UUID.randomUUID().toString(); this.identifier = UUID.randomUUID().toString();

View File

@ -5,8 +5,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import xyz.zhouxy.plusone.commons.annotation.Overridable;
/** /**
* *
* *
@ -28,29 +26,7 @@ public abstract class Entity<ID extends Serializable> {
public abstract Optional<ID> getId(); public abstract Optional<ID> getId();
protected final void addDomainEvent(DomainEvent domainEvent) { protected void addDomainEvent(DomainEvent domainEvent) {
domainEvents.add(domainEvent); domainEvents.add(domainEvent);
} }
public final List<DomainEvent> getDomainEvents() {
return List.copyOf(domainEvents);
}
@Override
@Overridable
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
@Overridable
public int hashCode() {
return super.hashCode();
}
@Override
@Overridable
public String toString() {
return super.toString();
}
} }

View File

@ -1,8 +0,0 @@
package xyz.zhouxy.plusone.domain;
public interface IDomainEventPublisher {
void publish(DomainEvent domainEvent);
<T extends DomainEvent> void subsrcibe(IDomainEventSubscriber<T> subscriber);
}

View File

@ -1,11 +0,0 @@
package xyz.zhouxy.plusone.domain;
/**
*
*/
public interface IDomainEventSubscriber<T extends DomainEvent> {
void handleEvent(final T event);
Class<T> subscribedToEventType();
}

View File

@ -0,0 +1,41 @@
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.JsonValue;
/**
*
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public abstract class ValidatableStringRecord implements IValueObject {
protected String value;
protected final Pattern format;
protected ValidatableStringRecord(Pattern format) {
this.format = format;
}
@JsonIgnore
protected boolean isValid() {
return format.matcher(value).matches();
}
@JsonValue
public String value() {
return value;
}
@Override
public String toString() {
return value;
}
public static String getValueOrNull(Optional<? extends ValidatableStringRecord> s) {
return s.isPresent() ? s.get().value() : null;
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>xyz.zhouxy</groupId> <groupId>xyz.zhouxy</groupId>

View File

@ -1,12 +1,8 @@
package xyz.zhouxy.plusone.jdbc; package xyz.zhouxy.plusone.jdbc;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import xyz.zhouxy.plusone.commons.base.IWithCode;
import xyz.zhouxy.plusone.commons.base.IWithIntCode;
/** /**
* {@link BeanPropertySqlParameterSource} POJO * {@link BeanPropertySqlParameterSource} POJO
* {@link org.springframework.jdbc.core.namedparam.SqlParameterSource} * {@link org.springframework.jdbc.core.namedparam.SqlParameterSource}
@ -21,23 +17,17 @@ import xyz.zhouxy.plusone.commons.base.IWithIntCode;
*/ */
public class BeanPropertyParamSource extends BeanPropertySqlParameterSource { public class BeanPropertyParamSource extends BeanPropertySqlParameterSource {
public BeanPropertyParamSource(Object object) { public BeanPropertyParamSource(Object object) {
super(object); super(object);
} }
@Override @Override
@Nullable @Nullable
public Object getValue(String paramName) throws IllegalArgumentException { public Object getValue(String paramName) throws IllegalArgumentException {
Object value = super.getValue(paramName); Object value = super.getValue(paramName);
if (value instanceof Enum<?> e) { if (value instanceof Enum) {
if (value instanceof IWithCode<?> c) { return ((Enum<?>) value).ordinal();
return c.getCode(); }
} return value;
if (value instanceof IWithIntCode c) { }
return c.getCode();
}
return e.ordinal();
}
return value;
}
} }

View File

@ -63,12 +63,10 @@ public abstract class JdbcEntityDaoSupport<T extends Entity<ID>, ID extends Seri
protected abstract T mapRow(ResultSet rs) throws SQLException; protected abstract T mapRow(ResultSet rs) throws SQLException;
@Deprecated
protected void setRowMapper(@Nonnull RowMapper<T> rowMapper) { protected void setRowMapper(@Nonnull RowMapper<T> rowMapper) {
this.rowMapper = rowMapper; this.rowMapper = rowMapper;
} }
@Deprecated
protected void setResultSetExtractor(@Nonnull ResultSetExtractor<Optional<T>> resultSetExtractor) { protected void setResultSetExtractor(@Nonnull ResultSetExtractor<Optional<T>> resultSetExtractor) {
this.resultSetExtractor = resultSetExtractor; this.resultSetExtractor = resultSetExtractor;
} }

View File

@ -7,7 +7,8 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import xyz.zhouxy.plusone.spring.SpringContextHolder; import xyz.zhouxy.plusone.spring.SpringContextHolder;
/** /**
* Spring {@link JdbcTemplate} * Spring
* Spring {@link JdbcTemplate}
* {@link NamedParameterJdbcTemplate} * {@link NamedParameterJdbcTemplate}
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
@ -16,19 +17,17 @@ import xyz.zhouxy.plusone.spring.SpringContextHolder;
*/ */
public final class JdbcFactory { public final class JdbcFactory {
private static final ApplicationContext SPRING_APPLICATION_CONTEXT = SpringContextHolder.getContext(); private static final ApplicationContext CONTEXT = SpringContextHolder.getContext();
private static final JdbcTemplate JDBC_TEMPLATE = SPRING_APPLICATION_CONTEXT.getBean(JdbcTemplate.class);
private static final NamedParameterJdbcTemplate NAMED_PARAMETER_JDBC_TEMPLATE = SPRING_APPLICATION_CONTEXT.getBean(NamedParameterJdbcTemplate.class);
private JdbcFactory() { private JdbcFactory() {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
public static JdbcTemplate getJdbcTemplate() { public static JdbcTemplate getJdbcTemplate() {
return JDBC_TEMPLATE; return CONTEXT.getBean(JdbcTemplate.class);
} }
public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() { public static NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return NAMED_PARAMETER_JDBC_TEMPLATE; return CONTEXT.getBean(NamedParameterJdbcTemplate.class);
} }
} }

View File

@ -8,9 +8,6 @@ import javax.annotation.Nonnull;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import com.google.common.base.Preconditions;
import xyz.zhouxy.plusone.commons.annotation.Overridable;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IRepository; import xyz.zhouxy.plusone.domain.IRepository;
@ -22,33 +19,35 @@ public abstract class JdbcRepositorySupport<T extends AggregateRoot<ID>, ID exte
super(namedParameterJdbcTemplate); super(namedParameterJdbcTemplate);
} }
@Overridable
protected abstract void doDelete(@Nonnull T entity); protected abstract void doDelete(@Nonnull T entity);
@Overridable
protected abstract Optional<T> doFindById(@Nonnull ID id); protected abstract Optional<T> doFindById(@Nonnull ID id);
@Overridable
protected abstract T doInsert(@Nonnull T entity); protected abstract T doInsert(@Nonnull T entity);
@Overridable
protected abstract T doUpdate(@Nonnull T entity); protected abstract T doUpdate(@Nonnull T entity);
@Override @Override
public final void delete(T entity) { public final void delete(T entity) {
Preconditions.checkArgument(entity != null, "Cannot delete null."); if (entity == null) {
throw new IllegalArgumentException("Cannot delete null.");
}
doDelete(entity); doDelete(entity);
} }
@Override @Override
public final Optional<T> find(ID id) { public final Optional<T> find(ID id) {
Preconditions.checkArgument(id != null, "Id cannot be null."); if (id == null) {
throw new IllegalArgumentException("Id cannot be null.");
}
return doFindById(id); return doFindById(id);
} }
@Override @Override
public final T save(T entity) { public final T save(T entity) {
Preconditions.checkArgument(entity != null, "Cannot save null."); if (entity == null) {
throw new IllegalArgumentException("Cannot save null.");
}
return entity.getId().isPresent() ? doUpdate(entity) : doInsert(entity); return entity.getId().isPresent() ? doUpdate(entity) : doInsert(entity);
} }

View File

@ -16,7 +16,7 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import xyz.zhouxy.plusone.commons.util.Numbers; import xyz.zhouxy.plusone.commons.util.NumberUtil;
import xyz.zhouxy.plusone.exception.DataOperationResultException; import xyz.zhouxy.plusone.exception.DataOperationResultException;
public abstract class PlusoneJdbcDaoSupport { public abstract class PlusoneJdbcDaoSupport {
@ -88,64 +88,64 @@ public abstract class PlusoneJdbcDaoSupport {
protected final long batchUpdate(String sql, SqlParameterSource[] batchArgs) { protected final long batchUpdate(String sql, SqlParameterSource[] batchArgs) {
int[] i = this.jdbc.batchUpdate(sql, batchArgs); int[] i = this.jdbc.batchUpdate(sql, batchArgs);
return Numbers.sum(i); return NumberUtil.sum(i);
} }
protected final <T> long batchUpdate(String sql, Stream<T> c, protected final <T> long batchUpdate(String sql, Stream<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) { @Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder)); int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder));
return Numbers.sum(i); return NumberUtil.sum(i);
} }
protected final <T> long batchUpdate(String sql, Collection<T> c, protected final <T> long batchUpdate(String sql, Collection<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) { @Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder)); int[] i = this.jdbc.batchUpdate(sql, buildSqlParameterSourceArray(c, paramSourceBuilder));
return Numbers.sum(i); return NumberUtil.sum(i);
} }
protected static <T> void assertResultEquals(T result, T expectedValue) { protected static final <T> void assertResultEquals(T result, T expectedValue) {
if (!Objects.equals(result, expectedValue)) { if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException(); throw new DataOperationResultException();
} }
} }
protected static <T> void assertResultEquals(T result, T expectedValue, Function<T, String> errMsg) { protected static final <T> void assertResultEquals(T result, T expectedValue, Function<T, String> errMsg) {
if (!Objects.equals(result, expectedValue)) { if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException(errMsg.apply(result)); throw new DataOperationResultException(errMsg.apply(result));
} }
} }
protected static <T> void assertResultEquals(T result, T expectedValue, String msgTemplate, Object... args) { protected static final <T> void assertResultEquals(T result, T expectedValue, String msgTemplate, Object... args) {
if (!Objects.equals(result, expectedValue)) { if (!Objects.equals(result, expectedValue)) {
throw new DataOperationResultException(String.format(msgTemplate, args)); throw new DataOperationResultException(String.format(msgTemplate, args));
} }
} }
protected static <T, E extends Throwable> void assertResultEqualsOrThrow(T result, T expectedValue, protected static final <T, E extends Throwable> void assertResultEqualsOrThrow(T result, T expectedValue,
Function<T, E> e) throws E { Function<T, E> e) throws E {
if (!Objects.equals(result, expectedValue)) { if (!Objects.equals(result, expectedValue)) {
throw e.apply(result); throw e.apply(result);
} }
} }
protected static void assertUpdateOneRow(int result) { protected static final void assertUpdateOneRow(int result) {
assertResultEquals(result, 1); assertResultEquals(result, 1);
} }
protected static void assertUpdateOneRow(int result, Function<Integer, String> errMsg) { protected static final void assertUpdateOneRow(int result, Function<Integer, String> errMsg) {
assertResultEquals(result, 1, errMsg); assertResultEquals(result, 1, errMsg);
} }
protected static void assertUpdateOneRow(int result, String msgTemplate, Object... args) { protected static final void assertUpdateOneRow(int result, String msgTemplate, Object... args) {
assertResultEquals(result, 1, msgTemplate, args); assertResultEquals(result, 1, msgTemplate, args);
} }
protected static <E extends Throwable> void assertUpdateOneRowOrThrow(int result, Function<Integer, E> e) protected static final <E extends Throwable> void assertUpdateOneRowOrThrow(int result, Function<Integer, E> e)
throws E { throws E {
assertResultEqualsOrThrow(result, 1, e); assertResultEqualsOrThrow(result, 1, e);
} }
protected static <T> SqlParameterSource[] buildSqlParameterSourceArray( protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
T[] c, T[] c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) { @Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
if (c == null || c.length == 0) { if (c == null || c.length == 0) {
@ -154,7 +154,7 @@ public abstract class PlusoneJdbcDaoSupport {
return buildSqlParameterSourceArray(Arrays.stream(c), paramSourceBuilder); return buildSqlParameterSourceArray(Arrays.stream(c), paramSourceBuilder);
} }
protected static <T> SqlParameterSource[] buildSqlParameterSourceArray( protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
Collection<T> c, Collection<T> c,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) { @Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
if (CollectionUtils.isEmpty(c)) { if (CollectionUtils.isEmpty(c)) {
@ -163,7 +163,7 @@ public abstract class PlusoneJdbcDaoSupport {
return buildSqlParameterSourceArray(c.stream(), paramSourceBuilder); return buildSqlParameterSourceArray(c.stream(), paramSourceBuilder);
} }
protected static <T> SqlParameterSource[] buildSqlParameterSourceArray( protected static final <T> SqlParameterSource[] buildSqlParameterSourceArray(
Stream<T> stream, Stream<T> stream,
@Nonnull Function<T, SqlParameterSource> paramSourceBuilder) { @Nonnull Function<T, SqlParameterSource> paramSourceBuilder) {
Objects.requireNonNull(stream); Objects.requireNonNull(stream);

View File

@ -8,7 +8,7 @@ import java.sql.SQLException;
* *
* <p> * <p>
* {@link #map(ResultSet)} {@link ResultSet} * {@link #map(ResultSet)} {@link ResultSet}
* {@link #rowMapper(ResultSet, int)} * {@link #rowMapper(ResultSet, int)}
* {@link org.springframework.jdbc.core.RowMapper} * {@link org.springframework.jdbc.core.RowMapper}
* {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate} * {@link org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate}
* *

View File

@ -1,17 +1,8 @@
package xyz.zhouxy.plusone.oss; package xyz.zhouxy.plusone.oss;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.csource.common.MyException; import org.csource.common.MyException;
import org.csource.common.NameValuePair; import org.csource.common.NameValuePair;
@ -23,11 +14,7 @@ import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.google.common.io.Files;
import lombok.Getter; import lombok.Getter;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.exception.SysException;
public class FastDFSUtil { public class FastDFSUtil {
@ -57,7 +44,7 @@ public class FastDFSUtil {
* @throws FastDFSException * @throws FastDFSException
*/ */
public String[] upload(FastDFSFile file) throws FastDFSException { public String[] upload(FastDFSFile file) throws FastDFSException {
logger.info("File Name: {}, File Length: {}", file.getFileName(), file.getContent().length); logger.info("File Name: {}, File Length: {}", file.getName(), file.getContent().length);
NameValuePair[] metaList = new NameValuePair[1]; NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("author", file.getAuthor()); metaList[0] = new NameValuePair("author", file.getAuthor());
@ -76,7 +63,7 @@ public class FastDFSUtil {
uploadResults[0], uploadResults[1], System.currentTimeMillis() - startTime); uploadResults[0], uploadResults[1], System.currentTimeMillis() - startTime);
} catch (IOException e) { } catch (IOException e) {
throw new FastDFSException("IO Exception when uploadind the file:" + file.getFileName(), e); throw new FastDFSException("IO Exception when uploadind the file:" + file.getName(), e);
} catch (MyException e) { } catch (MyException e) {
throw new FastDFSException(e); throw new FastDFSException(e);
} }
@ -122,72 +109,18 @@ public class FastDFSUtil {
} }
} }
@Getter
public static final class FastDFSFile { public static final class FastDFSFile {
@Getter private String name;
private final String fileName; private byte[] content;
private final byte[] content; private String ext;
@Getter private String md5;
private final String ext; private String author;
@Getter
private final String md5;
@Getter
private final String author;
private FastDFSFile(@Nonnull File file, @Nullable String author) throws IOException { public FastDFSFile(String name, byte[] content, String ext) {
this.fileName = file.getName(); this.name = name;
this.content = Files.toByteArray(file);
this.ext = Files.getFileExtension(fileName);
this.md5 = md5Hex(content);
this.author = author;
}
private FastDFSFile(@Nonnull String fileName, @Nonnull byte[] content, @Nullable String author) {
this.fileName = fileName;
this.content = content; this.content = content;
this.ext = Files.getFileExtension(fileName); this.ext = ext;
this.md5 = md5Hex(content);
this.author = author;
}
@Nonnull
@StaticFactoryMethod(FastDFSFile.class)
public static FastDFSFile of(@Nonnull File file) throws IOException {
return new FastDFSFile(file, null);
}
@Nonnull
@StaticFactoryMethod(FastDFSFile.class)
public static FastDFSFile of(@Nonnull File file, @Nullable String author) throws IOException {
return new FastDFSFile(file, author);
}
@Nonnull
@StaticFactoryMethod(FastDFSFile.class)
public static FastDFSFile of(@Nonnull String fileName, @Nonnull byte[] content) {
return new FastDFSFile(fileName, content, null);
}
@Nonnull
@StaticFactoryMethod(FastDFSFile.class)
public static FastDFSFile of(@Nonnull String fileName, @Nonnull byte[] content, @Nullable String author) {
return new FastDFSFile(fileName, content, author);
}
public byte[] getContent() {
return Arrays.copyOf(content, content.length);
}
@Nonnull
private static String md5Hex(byte[] data) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(data);
byte[] result = messageDigest.digest();
var sha512Hex = new BigInteger(1, result).toString(16);
return Objects.requireNonNull(sha512Hex);
} catch (NoSuchAlgorithmException e) {
throw SysException.of(e);
}
} }
} }
} }

View File

@ -1,7 +1,5 @@
package xyz.zhouxy.plusone.sms; package xyz.zhouxy.plusone.sms;
import org.springframework.stereotype.Service;
import com.tencentcloudapi.common.Credential; import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile; import com.tencentcloudapi.common.profile.ClientProfile;
@ -10,8 +8,11 @@ import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest; import com.tencentcloudapi.sms.v20210111.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse; import com.tencentcloudapi.sms.v20210111.models.SendSmsResponse;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.exception.SysException; import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsCredentialProperties; import xyz.zhouxy.plusone.sms.SmsProperties.SmsCredentialProperties;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsHttpProperties; import xyz.zhouxy.plusone.sms.SmsProperties.SmsHttpProperties;
import xyz.zhouxy.plusone.sms.SmsProperties.SmsProxyProperties; import xyz.zhouxy.plusone.sms.SmsProperties.SmsProxyProperties;
@ -68,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 SysException.of(e); throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, e);
} }
} }

View File

@ -4,13 +4,15 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
public enum SpringContextHolder { public class SpringContextHolder {
INSTANCE
;
private ApplicationContext context; private ApplicationContext context;
private static final SpringContextHolder INSTANCE = new SpringContextHolder();
private SpringContextHolder() {
}
public static ApplicationContext getContext() { public static ApplicationContext getContext() {
return INSTANCE.context; return INSTANCE.context;
} }

View File

@ -12,7 +12,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration @Configuration
public class WebCorsConfig implements WebMvcConfigurer { public class WebCorsConfig implements WebMvcConfigurer {
// TODO 不放行全部,通过配置文件配置允许访问的域名
@Override @Override
public void addCorsMappings(CorsRegistry registry) { public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") registry.addMapping("/**")

View File

@ -36,7 +36,7 @@ class LoginCommandValidator extends BaseValidator<LoginCommand> {
private LoginCommandValidator() { private LoginCommandValidator() {
ruleForString(LoginCommand::getAccount) ruleForString(LoginCommand::getAccount)
.notNull("邮箱地址不能为空") .notNull("邮箱地址不能为空")
.matchesOne(new Pattern[] { PatternConsts.EMAIL, PatternConsts.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("密码不能为空")

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone</artifactId> <artifactId>plusone</artifactId>

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone</artifactId> <artifactId>plusone</artifactId>

View File

@ -3,10 +3,14 @@ package xyz.zhouxy.plusone;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import lombok.extern.slf4j.Slf4j;
@SpringBootApplication @SpringBootApplication
@Slf4j
public class PlusoneApplication { public class PlusoneApplication {
public static void main(String[] args) { public static void main(String[] args) {
log.debug("Plusone started!");
SpringApplication.run(PlusoneApplication.class, args); SpringApplication.run(PlusoneApplication.class, args);
} }

View File

@ -1,33 +0,0 @@
package xyz.zhouxy.plusone;
import java.util.Collections;
import java.util.List;
import javax.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.system.application.query.AccountQueries;
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
import xyz.zhouxy.plusone.system.application.query.result.AccountOverview;
@Slf4j
@SpringBootTest(classes = PlusoneApplication.class)
class AccountQueriesTests {
@Resource
AccountQueries accountQueries;
@Test
void testQueryPage() {
AccountQueryParams queryParams = new AccountQueryParams();
// queryParams.setOrderBy(List.of("email", "mobile_phone", "id"));
queryParams.setSize(20);
queryParams.setPageNum(1L);
queryParams.setOrderBy(Collections.emptyList());
List<AccountOverview> l = accountQueries.queryAccountOverview(queryParams);
log.info("l: {}", l);
}
}

View File

@ -1,11 +1,12 @@
package xyz.zhouxy.plusone; package xyz.zhouxy.plusone;
import java.io.File; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.commons.io.IOUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
@ -23,7 +24,10 @@ class FastDFSTests {
@Test @Test
void testOSS() throws FileNotFoundException, IOException, FastDFSException { void testOSS() throws FileNotFoundException, IOException, FastDFSException {
String[] upload = fastDFSUtil.upload(FastDFSFile.of(new File("D:\\ZhouXY\\Desktop\\666.png"))); try (FileInputStream in = new FileInputStream("D:\\ZhouXY\\Desktop\\666.png");) {
log.info(String.join("/", upload)); byte[] content = IOUtils.toByteArray(in);
String[] upload = fastDFSUtil.upload(new FastDFSFile("666.png", content, "png"));
log.info(String.join("/", upload));
}
} }
} }

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone-system</artifactId> <artifactId>plusone-system</artifactId>

View File

@ -11,7 +11,7 @@ public class UnsupportedPrincipalTypeException extends BizException {
private static final long serialVersionUID = 5207757290868470762L; private static final long serialVersionUID = 5207757290868470762L;
public static final String ERR_CODE = "4040201"; public static final int ERR_CODE = 4040201;
private static final String DEFAULT_ERROR_MSG = "不支持的 PrincipalType"; private static final String DEFAULT_ERROR_MSG = "不支持的 PrincipalType";
public UnsupportedPrincipalTypeException() { public UnsupportedPrincipalTypeException() {

View File

@ -1,138 +0,0 @@
package xyz.zhouxy.plusone.system.application.common.model;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.OptionalLong;
import java.util.OptionalDouble;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import xyz.zhouxy.plusone.exception.BizException;
public class AuthenticationInfo<T> {
/** token 值 */
private final String token;
/** 此 token 对应的LoginId未登录时不会构建此类的实例 */
private final T loginId;
/** 账号类型 */
private final String loginType;
/** 登录设备类型 */
private final String deviceType;
/** 自定义数据 */
@Nonnull
private final Map<String, Object> metadata;
private AuthenticationInfo(String token, T loginId, String loginType, String deviceType,
@Nonnull Map<String, Object> metadata) {
this.token = token;
this.loginId = loginId;
this.loginType = loginType;
this.deviceType = deviceType;
this.metadata = metadata;
}
public String getToken() {
return token;
}
public T getLoginId() {
return loginId;
}
public String getLoginType() {
return loginType;
}
public String getDeviceType() {
return deviceType;
}
private Object getObjFromMetadata(String key) {
if (this.metadata.containsKey(key)) {
return this.metadata.get(key);
}
throw BizException.of(String.format("不存在 key 为 \"%s\"的元数据。", key));
}
public OptionalDouble getMetadataAsDouble(String key) {
Object valObj = getObjFromMetadata(key);
if (valObj instanceof Double val) {
return OptionalDouble.of(val.doubleValue());
}
return OptionalDouble.empty();
}
public OptionalLong getMetadataAsLong(String key) {
Object valObj = getObjFromMetadata(key);
if (valObj instanceof Long val) {
return OptionalLong.of(val.longValue());
}
return OptionalLong.empty();
}
public OptionalInt getMetadataAsInt(String key) {
Object valObj = getObjFromMetadata(key);
if (valObj instanceof Integer val) {
return OptionalInt.of(val.intValue());
}
return OptionalInt.empty();
}
public Optional<String> getMetadataAsString(String key) {
Object valObj = getObjFromMetadata(key);
if (valObj instanceof String val) {
return Optional.of(val);
}
return Optional.empty();
}
@SuppressWarnings("unchecked")
public <C> Optional<C> getMetadata(String key, Class<C> type) {
Object valObj = getObjFromMetadata(key);
if (valObj == null || !type.isAssignableFrom(valObj.getClass())) {
return Optional.empty();
}
return Optional.of((C) valObj);
}
// ==========================================
// builder
public static <T> Builder<T> builder(String token, T loginId, String loginType, String deviceType) {
return new Builder<>(token, loginId, loginType, deviceType);
}
public static final class Builder<T> {
private final String token;
private final T loginId;
private final String loginType;
private final String deviceType;
@Nonnull
private final Map<String, Object> meta = new ConcurrentHashMap<>();
private Builder(String token, T loginId, String loginType, String deviceType) {
this.token = token;
this.loginId = loginId;
this.loginType = loginType;
this.deviceType = deviceType;
}
public <C> Builder<T> putMetadata(String key, @Nullable C value) {
this.meta.put(key, value);
return this;
}
public AuthenticationInfo<T> build() {
return new AuthenticationInfo<>(token, loginId, loginType, deviceType, meta);
}
}
}

View File

@ -1,21 +0,0 @@
package xyz.zhouxy.plusone.system.application.common.model;
public class PlusoneContext {
private static final ThreadLocal<AuthenticationInfo<Long>> context = new ThreadLocal<>();
public static void setContext(AuthenticationInfo<Long> value) {
context.set(value);
}
public static AuthenticationInfo<Long> getContext() {
return context.get();
}
public static void remove() {
context.remove();
}
private PlusoneContext() {
throw new IllegalStateException("Utility class");
}
}

View File

@ -0,0 +1,61 @@
package xyz.zhouxy.plusone.system.application.common.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import xyz.zhouxy.plusone.domain.IWithOrderNumber;
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
/**
*
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public class MenuUtil {
private MenuUtil() {
throw new IllegalStateException("Utility class");
}
/**
*
*
* @param allMenus
* @return
*/
public static List<MenuViewObject> buildMenuTree(Collection<MenuViewObject> allMenus) {
// 先排序,保证添加到 rootMenus 中的顺序,以及 addChild 添加的子菜单的顺序
allMenus = allMenus.stream()
.sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
.toList();
// 一级菜单
List<MenuViewObject> rootMenus = new ArrayList<>();
// key: 菜单 id; value: 菜单对象. 方便根据 id 查找相应对象。
Map<Long, MenuViewObject> menuListMap = new HashMap<>();
for (var menu : allMenus) {
// 添加 MENU_LIST 到 map 中,方便后面调用对象的方法
if (menu.getType() == MenuType.MENU_LIST.ordinal()) {
menuListMap.put(menu.getId(), menu);
}
// 一级菜单
if (menu.getParentId() == 0) {
rootMenus.add(menu);
}
}
for (var menu : allMenus) {
var parent = menuListMap.getOrDefault(menu.getParentId(), null);
// 父菜单存在于 map 中,调用父菜单的 addChild 方法将当前菜单添加为父菜单的子菜单。
if (parent != null) {
parent.addChild(menu);
}
}
return rootMenus;
}
}

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.web.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;
@ -7,7 +7,7 @@ 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.UnifiedResponse; 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;
@ -28,34 +28,34 @@ public class AccountContextController {
} }
@GetMapping("info") @GetMapping("info")
public UnifiedResponse getAccountInfo() { public RestfulResult getAccountInfo() {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
var result = service.getAccountInfo(); var result = service.getAccountInfo();
return UnifiedResponse.success("查询成功", result); return RestfulResult.success("查询成功", result);
} }
@GetMapping("logout") @GetMapping("logout")
public UnifiedResponse logout() { public RestfulResult logout() {
service.logout(); service.logout();
return UnifiedResponse.success("注销成功"); return RestfulResult.success("注销成功");
} }
@GetMapping("menus") @GetMapping("menus")
public UnifiedResponse getMenuTree() { public RestfulResult getMenuTree() {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
var result = service.getMenuTree(); var result = service.getMenuTree();
return UnifiedResponse.success("查询成功", result); return RestfulResult.success("查询成功", result);
} }
@PostMapping("changePassword") @PostMapping("changePassword")
public UnifiedResponse changePassword(ChangePasswordCommand command) { public RestfulResult changePassword(ChangePasswordCommand command) {
service.changePassword(command); service.changePassword(command);
return UnifiedResponse.success("修改成功,请重新登录。"); return RestfulResult.success("修改成功,请重新登录。");
} }
@PostMapping("changePasswordWithoutLogin") @PostMapping("changePasswordWithoutLogin")
public UnifiedResponse changePasswordWithoutLogin(ChangePasswordWithoutLoginCommand command) { public RestfulResult changePasswordWithoutLogin(ChangePasswordWithoutLoginCommand command) {
service.changePasswordWithoutLogin(command); service.changePasswordWithoutLogin(command);
return UnifiedResponse.success("修改成功,请重新登录。"); return RestfulResult.success("修改成功,请重新登录。");
} }
} }

View File

@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.web.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.commons.util.UnifiedResponse.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
import java.util.List; import java.util.List;
@ -16,7 +16,7 @@ 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.UnifiedResponse; 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;
@ -38,7 +38,7 @@ public class AccountManagementController {
} }
@PostMapping @PostMapping
public UnifiedResponse createAccount(@RequestBody @Valid CreateAccountCommand command) { public RestfulResult createAccount(@RequestBody @Valid CreateAccountCommand command) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
adminAuthLogic.checkPermission("sys-account-create"); adminAuthLogic.checkPermission("sys-account-create");
service.createAccount(command); service.createAccount(command);
@ -46,7 +46,7 @@ public class AccountManagementController {
} }
@DeleteMapping @DeleteMapping
public UnifiedResponse deleteAccounts(@RequestBody List<Long> ids) { public RestfulResult deleteAccounts(@RequestBody List<Long> ids) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
adminAuthLogic.checkPermission("sys-account-delete"); adminAuthLogic.checkPermission("sys-account-delete");
service.deleteAccounts(ids); service.deleteAccounts(ids);
@ -54,7 +54,7 @@ public class AccountManagementController {
} }
@PatchMapping("{id}") @PatchMapping("{id}")
public UnifiedResponse updateAccountInfo( public RestfulResult updateAccountInfo(
@PathVariable("id") Long id, @PathVariable("id") Long id,
@RequestBody @Valid UpdateAccountCommand command) { @RequestBody @Valid UpdateAccountCommand command) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
@ -64,7 +64,7 @@ public class AccountManagementController {
} }
@GetMapping("query") @GetMapping("query")
public UnifiedResponse queryAccountOverviewList(AccountQueryParams queryParams) { public RestfulResult queryAccountOverviewList(AccountQueryParams queryParams) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
adminAuthLogic.checkPermission("sys-account-list"); adminAuthLogic.checkPermission("sys-account-list");
var accountOverviewList = service.queryAccountOverviewList(queryParams); var accountOverviewList = service.queryAccountOverviewList(queryParams);
@ -72,7 +72,7 @@ public class AccountManagementController {
} }
@GetMapping("{accountId}") @GetMapping("{accountId}")
public UnifiedResponse queryAccountDetails(@PathVariable("accountId") Long accountId) { public RestfulResult queryAccountDetails(@PathVariable("accountId") Long accountId) {
adminAuthLogic.checkLogin(); adminAuthLogic.checkLogin();
adminAuthLogic.checkPermission("sys-account-details"); adminAuthLogic.checkPermission("sys-account-details");
var accountDetails = service.queryAccountDetails(accountId); var accountDetails = service.queryAccountDetails(accountId);

View File

@ -1,6 +1,6 @@
package xyz.zhouxy.plusone.system.application.web.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.commons.util.UnifiedResponse.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.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* Admin * Admin
@ -30,19 +30,19 @@ public class AdminLoginController {
} }
@PostMapping("byPassword") @PostMapping("byPassword")
public UnifiedResponse loginByPassword(@RequestBody LoginByPasswordCommand command) { public RestfulResult loginByPassword(@RequestBody LoginByPasswordCommand command) {
var loginInfo = service.loginByPassword(command); var loginInfo = service.loginByPassword(command);
return success("登录成功", loginInfo); return success("登录成功", loginInfo);
} }
@PostMapping("byOtp") @PostMapping("byOtp")
public UnifiedResponse loginByOtp(@RequestBody LoginByOtpCommand command) { public RestfulResult loginByOtp(@RequestBody LoginByOtpCommand command) {
var loginInfo = service.loginByOtp(command); var loginInfo = service.loginByOtp(command);
return success("登录成功", loginInfo); return success("登录成功", loginInfo);
} }
@GetMapping("sendOtp") @GetMapping("sendOtp")
public UnifiedResponse sendOtp(@RequestParam String principal) { public RestfulResult sendOtp(@RequestParam String principal) {
service.sendOtp(principal); service.sendOtp(principal);
return success("发送成功"); return success("发送成功");
} }

View File

@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.web.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.commons.util.UnifiedResponse.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.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* *
@ -38,21 +38,21 @@ public class DictManagementController {
} }
@PostMapping @PostMapping
public UnifiedResponse createDict(@RequestBody @Valid CreateDictCommand command) { public RestfulResult createDict(@RequestBody @Valid CreateDictCommand command) {
adminAuthLogic.checkPermission("sys-dict-create"); adminAuthLogic.checkPermission("sys-dict-create");
service.createDict(command); service.createDict(command);
return success(); return success();
} }
@DeleteMapping @DeleteMapping
public UnifiedResponse deleteDicts(@RequestBody List<Long> ids) { public RestfulResult deleteDicts(@RequestBody List<Long> ids) {
adminAuthLogic.checkPermission("sys-dict-delete"); adminAuthLogic.checkPermission("sys-dict-delete");
service.deleteDicts(ids); service.deleteDicts(ids);
return success(); return success();
} }
@PatchMapping("{id}") @PatchMapping("{id}")
public UnifiedResponse updateDict( public RestfulResult updateDict(
@PathVariable("id") Long id, @PathVariable("id") Long id,
@RequestBody @Valid UpdateDictCommand command) { @RequestBody @Valid UpdateDictCommand command) {
adminAuthLogic.checkPermission("sys-dict-update"); adminAuthLogic.checkPermission("sys-dict-update");
@ -61,21 +61,21 @@ public class DictManagementController {
} }
@GetMapping("{dictId}") @GetMapping("{dictId}")
public UnifiedResponse findDictDetails(@PathVariable("dictId") Long dictId) { public RestfulResult findDictDetails(@PathVariable("dictId") Long dictId) {
adminAuthLogic.checkPermission("sys-dict-details"); adminAuthLogic.checkPermission("sys-dict-details");
var dictDetails = service.findDictDetails(dictId); var dictDetails = service.findDictDetails(dictId);
return success("查询成功", dictDetails); return success("查询成功", dictDetails);
} }
@GetMapping("all") @GetMapping("all")
public UnifiedResponse loadAllDicts() { public RestfulResult loadAllDicts() {
adminAuthLogic.checkPermissionAnd("sys-dict-list", "sys-dict-details"); adminAuthLogic.checkPermissionAnd("sys-dict-list", "sys-dict-details");
var dicts = service.loadAllDicts(); var dicts = service.loadAllDicts();
return success("查询成功", dicts); return success("查询成功", dicts);
} }
@GetMapping("query") @GetMapping("query")
public UnifiedResponse queryDictOverviewList(@Valid DictQueryParams queryParams) { public RestfulResult queryDictOverviewList(@Valid DictQueryParams queryParams) {
adminAuthLogic.checkPermission("sys-dict-list"); adminAuthLogic.checkPermission("sys-dict-list");
var dicts = service.queryDictOverviewList(queryParams); var dicts = service.queryDictOverviewList(queryParams);
return success("查询成功", dicts); return success("查询成功", dicts);

View File

@ -1,7 +1,7 @@
package xyz.zhouxy.plusone.system.application.web.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.commons.util.UnifiedResponse.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.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* *
@ -37,7 +37,7 @@ public class MenuManagementController {
// ==================== create ==================== // ==================== create ====================
@PostMapping @PostMapping
public UnifiedResponse createMenu(@RequestBody @Valid CreateMenuCommand command) { public RestfulResult createMenu(@RequestBody @Valid CreateMenuCommand command) {
adminAuthLogic.checkPermission("sys-menu-create"); adminAuthLogic.checkPermission("sys-menu-create");
service.createMenu(command); service.createMenu(command);
return success(); return success();
@ -45,7 +45,7 @@ public class MenuManagementController {
// ==================== delete ==================== // ==================== delete ====================
@DeleteMapping("{id}") @DeleteMapping("{id}")
public UnifiedResponse deleteMenu(@PathVariable("id") Long id) { public RestfulResult deleteMenu(@PathVariable("id") Long id) {
adminAuthLogic.checkPermission("sys-menu-delete"); adminAuthLogic.checkPermission("sys-menu-delete");
service.deleteMenu(id); service.deleteMenu(id);
return success(); return success();
@ -53,7 +53,7 @@ public class MenuManagementController {
// ==================== update ==================== // ==================== update ====================
@PatchMapping("{id}") @PatchMapping("{id}")
public UnifiedResponse updateMenu( public RestfulResult updateMenu(
@PathVariable("id") Long id, @PathVariable("id") Long id,
@RequestBody @Valid UpdateMenuCommand command) { @RequestBody @Valid UpdateMenuCommand command) {
adminAuthLogic.checkPermission("sys-menu-update"); adminAuthLogic.checkPermission("sys-menu-update");
@ -63,21 +63,21 @@ public class MenuManagementController {
// ==================== query ==================== // ==================== query ====================
@GetMapping("{id}") @GetMapping("{id}")
public UnifiedResponse findById(@PathVariable("id") Long id) { public RestfulResult findById(@PathVariable("id") Long id) {
adminAuthLogic.checkPermission("sys-menu-details"); adminAuthLogic.checkPermission("sys-menu-details");
var result = service.findById(id); var result = service.findById(id);
return UnifiedResponse.success("查询成功", result); return RestfulResult.success("查询成功", result);
} }
@GetMapping("queryByAccountId") @GetMapping("queryByAccountId")
public UnifiedResponse queryByAccountId(@RequestParam Long accountId) { public RestfulResult queryByAccountId(@RequestParam Long accountId) {
adminAuthLogic.checkPermission("sys-menu-details"); adminAuthLogic.checkPermission("sys-menu-details");
var result = service.queryByAccountId(accountId); var result = service.queryByAccountId(accountId);
return success("查询成功", result); return success("查询成功", result);
} }
@GetMapping("queryByRoleId") @GetMapping("queryByRoleId")
public UnifiedResponse queryByRoleId(@RequestParam Long roleId) { public RestfulResult queryByRoleId(@RequestParam Long roleId) {
adminAuthLogic.checkPermission("sys-menu-details"); adminAuthLogic.checkPermission("sys-menu-details");
var result = service.queryByRoleId(roleId); var result = service.queryByRoleId(roleId);
return success("查询成功", result); return success("查询成功", result);

View File

@ -1,6 +1,6 @@
package xyz.zhouxy.plusone.system.application.web.controller; package xyz.zhouxy.plusone.system.application.controller;
import static xyz.zhouxy.plusone.commons.util.UnifiedResponse.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.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* *
@ -29,13 +29,13 @@ public class RegisterAccountController {
} }
@PostMapping @PostMapping
public UnifiedResponse registerAccount(@RequestBody RegisterAccountCommand command) { public RestfulResult registerAccount(@RequestBody RegisterAccountCommand command) {
service.registerAccount(command); service.registerAccount(command);
return success("注册成功"); return success("注册成功");
} }
@GetMapping("sendCode") @GetMapping("sendCode")
public UnifiedResponse sendCode(@RequestParam String principal) { public RestfulResult sendCode(@RequestParam String principal) {
service.sendCode(principal); service.sendCode(principal);
return success("发送成功"); return success("发送成功");
} }

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.web.controller; package xyz.zhouxy.plusone.system.application.controller;
import javax.validation.Valid; import javax.validation.Valid;
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic; import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
@ -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.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.util.RestfulResult;
/** /**
* *
@ -35,44 +35,44 @@ public class RoleManagementController {
} }
@PostMapping @PostMapping
public UnifiedResponse createRole(@RequestBody @Valid CreateRoleCommand command) { public RestfulResult createRole(@RequestBody @Valid CreateRoleCommand command) {
adminAuthLogic.checkPermission("sys-role-create"); adminAuthLogic.checkPermission("sys-role-create");
service.createRole(command); service.createRole(command);
return UnifiedResponse.success(); return RestfulResult.success();
} }
@PatchMapping @PatchMapping
public UnifiedResponse updateRole(@RequestBody @Valid UpdateRoleCommand command) { public RestfulResult updateRole(@RequestBody @Valid UpdateRoleCommand command) {
adminAuthLogic.checkPermission("sys-role-update"); adminAuthLogic.checkPermission("sys-role-update");
service.updateRole(command); service.updateRole(command);
return UnifiedResponse.success(); return RestfulResult.success();
} }
@DeleteMapping("{id}") @DeleteMapping("{id}")
public UnifiedResponse delete(@PathVariable("id") Long id) { public RestfulResult delete(@PathVariable("id") Long id) {
adminAuthLogic.checkPermission("sys-role-delete"); adminAuthLogic.checkPermission("sys-role-delete");
service.delete(id); service.delete(id);
return UnifiedResponse.success(); return RestfulResult.success();
} }
@GetMapping("exists") @GetMapping("exists")
public UnifiedResponse exists(@RequestParam("id") Long id) { public RestfulResult exists(@RequestParam("id") Long id) {
adminAuthLogic.checkPermissionOr("sys-role-list", "sys-role-details"); adminAuthLogic.checkPermissionOr("sys-role-list", "sys-role-details");
var isExists = service.exists(id); var isExists = service.exists(id);
return UnifiedResponse.success(isExists ? "存在" : "不存在", isExists); return RestfulResult.success(isExists ? "存在" : "不存在", isExists);
} }
@GetMapping("{id}") @GetMapping("{id}")
public UnifiedResponse findById(@PathVariable("id") Long id) { public RestfulResult findById(@PathVariable("id") Long id) {
adminAuthLogic.checkPermission("sys-role-details"); adminAuthLogic.checkPermission("sys-role-details");
var result = service.findById(id); var result = service.findById(id);
return UnifiedResponse.success("查询成功", result); return RestfulResult.success("查询成功", result);
} }
@GetMapping("query") @GetMapping("query")
public UnifiedResponse query(RoleQueryParams params) { public RestfulResult query(RoleQueryParams params) {
adminAuthLogic.checkPermission("sys-role-list"); adminAuthLogic.checkPermission("sys-role-list");
var result = service.query(params); var result = service.query(params);
return UnifiedResponse.success("查询成功", result); return RestfulResult.success("查询成功", result);
} }
} }

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.common.exception; 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;
@ -10,13 +10,13 @@ public class AccountLoginException extends BizException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = -3040996790739138556L; private static final long serialVersionUID = -3040996790739138556L;
private static final String DEFAULT_ERR_CODE = "4030000"; private static final int DEFAULT_ERR_CODE = 4030000;
private AccountLoginException() { private AccountLoginException() {
super(DEFAULT_ERR_CODE, "用户登录异常"); super(DEFAULT_ERR_CODE, "用户登录异常");
} }
private AccountLoginException(String code, String message) { private AccountLoginException(int code, String message) {
super(code, message); super(code, message);
} }
@ -25,7 +25,7 @@ public class AccountLoginException extends BizException {
} }
public static AccountLoginException accountNotExistException(String msg) { public static AccountLoginException accountNotExistException(String msg) {
return new AccountLoginException("4030101", msg); return new AccountLoginException(4030101, msg);
} }
public static AccountLoginException otpErrorException() { public static AccountLoginException otpErrorException() {
@ -33,7 +33,7 @@ public class AccountLoginException extends BizException {
} }
public static AccountLoginException otpErrorException(String msg) { public static AccountLoginException otpErrorException(String msg) {
return new AccountLoginException("4030501", msg); return new AccountLoginException(4030501, msg);
} }
public static AccountLoginException otpNotExistsException() { public static AccountLoginException otpNotExistsException() {
@ -41,7 +41,7 @@ public class AccountLoginException extends BizException {
} }
public static AccountLoginException otpNotExistsException(String msg) { public static AccountLoginException otpNotExistsException(String msg) {
return new AccountLoginException("4030502", msg); return new AccountLoginException(4030502, msg);
} }
public static AccountLoginException passwordErrorException() { public static AccountLoginException passwordErrorException() {
@ -49,6 +49,6 @@ public class AccountLoginException extends BizException {
} }
public static AccountLoginException passwordErrorException(String msg) { public static AccountLoginException passwordErrorException(String msg) {
return new AccountLoginException("4030200", msg); return new AccountLoginException(4030200, msg);
} }
} }

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.common.exception; 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;
@ -12,46 +12,46 @@ public class AccountRegisterException extends BizException {
private static final long serialVersionUID = 7580245181633370195L; private static final long serialVersionUID = 7580245181633370195L;
public AccountRegisterException() { public AccountRegisterException() {
this("4020000", "用户注册错误"); this(4020000, "用户注册错误");
} }
public AccountRegisterException(String message) { public AccountRegisterException(String message) {
this("4020000", message); this(4020000, message);
} }
public AccountRegisterException(Throwable cause) { public AccountRegisterException(Throwable cause) {
super("4020000", cause); super(4020000, cause);
} }
public AccountRegisterException(String code, String message) { public AccountRegisterException(int code, String message) {
super(code, message); super(code, message);
} }
public AccountRegisterException(String code, Throwable cause) { public AccountRegisterException(int code, Throwable cause) {
super(code, cause); super(code, cause);
} }
public static AccountRegisterException emailOrMobilePhoneRequiredException() { public static AccountRegisterException emailOrMobilePhoneRequiredException() {
return new AccountRegisterException("4020300", "邮箱和手机号应至少绑定一个"); return new AccountRegisterException(4020300, "邮箱和手机号应至少绑定一个");
} }
public static AccountRegisterException usernameAlreadyExists(String username) { public static AccountRegisterException usernameAlreadyExists(String username) {
return new AccountRegisterException("4020400", String.format("用户名 %s 已存在", username)); return new AccountRegisterException(4020400, String.format("用户名 %s 已存在", username));
} }
public static AccountRegisterException emailAlreadyExists(String value) { public static AccountRegisterException emailAlreadyExists(String value) {
return new AccountRegisterException("4020500", String.format("邮箱 %s 已存在", value)); return new AccountRegisterException(4020500, String.format("邮箱 %s 已存在", value));
} }
public static AccountRegisterException mobilePhoneAlreadyExists(String value) { public static AccountRegisterException mobilePhoneAlreadyExists(String value) {
return new AccountRegisterException("4020600", String.format("手机号 %s 已存在", value)); return new AccountRegisterException(4020600, String.format("手机号 %s 已存在", value));
} }
public static AccountRegisterException codeErrorException() { public static AccountRegisterException codeErrorException() {
return new AccountRegisterException("4020701", "校验码错误"); return new AccountRegisterException(4020701, "校验码错误");
} }
public static AccountRegisterException codeNotExistsException() { public static AccountRegisterException codeNotExistsException() {
return new AccountRegisterException("4020702", "校验码不存在或已过期"); return new AccountRegisterException(4020702, "校验码不存在或已过期");
} }
} }

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.common.exception; package xyz.zhouxy.plusone.system.application.exception;
import xyz.zhouxy.plusone.validator.InvalidInputException; import xyz.zhouxy.plusone.validator.InvalidInputException;
@ -7,13 +7,11 @@ public class UnsupportedMenuTypeException extends InvalidInputException {
@java.io.Serial @java.io.Serial
private static final long serialVersionUID = -769169844015637730L; private static final long serialVersionUID = -769169844015637730L;
public static final String ERROR_CODE = "4040209";
public UnsupportedMenuTypeException() { public UnsupportedMenuTypeException() {
this("不支持的菜单类型"); this("不支持的菜单类型");
} }
public UnsupportedMenuTypeException(String message) { public UnsupportedMenuTypeException(String message) {
super(ERROR_CODE, message); super(message);
} }
} }

View File

@ -1,6 +1,4 @@
package xyz.zhouxy.plusone.system.application.common.exception.handler; package xyz.zhouxy.plusone.system.application.exception.handler;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -8,9 +6,9 @@ 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.system.application.exception.AccountLoginException;
import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
import xyz.zhouxy.plusone.system.application.common.exception.AccountLoginException;
@RestControllerAdvice @RestControllerAdvice
public class AccountLoginExceptionHandler extends BaseExceptionHandler { public class AccountLoginExceptionHandler extends BaseExceptionHandler {
@ -20,7 +18,7 @@ public class AccountLoginExceptionHandler extends BaseExceptionHandler {
} }
@ExceptionHandler({ AccountLoginException.class }) @ExceptionHandler({ AccountLoginException.class })
public ResponseEntity<UnifiedResponse> handleException(Exception e) { public ResponseEntity<RestfulResult> handleException(@Nonnull Exception e) {
return buildExceptionResponse(Objects.requireNonNull(e)); return buildExceptionResponse(e);
} }
} }

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.system.application.common.exception.handler; package xyz.zhouxy.plusone.system.application.exception.handler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -17,7 +17,7 @@ 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.commons.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.UnifiedResponse; import xyz.zhouxy.plusone.commons.exception.handler.RestfulResult;
/** /**
* Sa-Token * Sa-Token
@ -52,7 +52,7 @@ public class SaTokenExceptionHandler extends BaseExceptionHandler {
} }
@ExceptionHandler(SaTokenException.class) @ExceptionHandler(SaTokenException.class)
public ResponseEntity<UnifiedResponse> handleSaTokenException(SaTokenException e) { public ResponseEntity<RestfulResult> handleSaTokenException(SaTokenException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return buildExceptionResponse(e); return buildExceptionResponse(e);
} }

View File

@ -12,7 +12,7 @@ import xyz.zhouxy.plusone.commons.util.PagingAndSortingQueryParams;
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@ToString(callSuper = true) @ToString
public class AccountQueryParams extends PagingAndSortingQueryParams { public class AccountQueryParams extends PagingAndSortingQueryParams {
public AccountQueryParams() { public AccountQueryParams() {
@ -29,6 +29,7 @@ public class AccountQueryParams extends PagingAndSortingQueryParams {
"update_time"); "update_time");
} }
// TODO【添加】 注解参数校验
private @Getter @Setter Long id; private @Getter @Setter Long id;
private @Getter @Setter String username; private @Getter @Setter String username;
private @Getter @Setter String email; private @Getter @Setter String email;

View File

@ -2,10 +2,9 @@ package xyz.zhouxy.plusone.system.application.query.result;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.SortedSet; import java.util.Objects;
import java.util.TreeSet;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
@ -82,18 +81,18 @@ public class MenuViewObject implements IWithOrderNumber {
List<Action> actions; List<Action> actions;
// MENU_LIST // MENU_LIST
SortedSet<MenuViewObject> children; List<MenuViewObject> children;
public void addChild(MenuViewObject child) { public void addChild(MenuViewObject child) {
if (this.children == null) { if (this.children == null) {
this.children = new TreeSet<>(); this.children = new ArrayList<>();
} }
this.children.add(child); this.children.add(child);
} }
public void addChildren(Collection<MenuViewObject> children) { public void addChildren(Collection<MenuViewObject> children) {
if (this.children == null) { if (this.children == null) {
this.children = new TreeSet<>(); this.children = new ArrayList<>();
} }
this.children.addAll(children); this.children.addAll(children);
} }
@ -122,33 +121,11 @@ public class MenuViewObject implements IWithOrderNumber {
} }
public List<MenuViewObject> getChildren() { public List<MenuViewObject> getChildren() {
return this.children == null || this.children.isEmpty() return Objects.nonNull(this.children)
? Collections.emptyList() ? this.children
: new ArrayList<>(this.children); .stream()
} .sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
.toList()
@Override : null;
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MenuViewObject other = (MenuViewObject) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
} }
} }

View File

@ -8,9 +8,9 @@ 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 xyz.zhouxy.plusone.system.application.common.exception.AccountLoginException;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException; 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.query.AccountQueries; import xyz.zhouxy.plusone.system.application.query.AccountQueries;
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails; import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject; import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;

View File

@ -16,7 +16,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import xyz.zhouxy.plusone.commons.util.PageDTO; import xyz.zhouxy.plusone.commons.util.PageDTO;
import xyz.zhouxy.plusone.exception.DataNotExistException; import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.common.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;
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails; import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
@ -94,6 +94,7 @@ public class AccountManagementService {
Account account = accountRepository.find(id) Account account = accountRepository.find(id)
.orElseThrow(() -> new DataNotExistException("该账号不存在")); .orElseThrow(() -> new DataNotExistException("该账号不存在"));
account.setAccountInfo(command.getNickname(), command.getAvatar(), Sex.of(command.getSex())); account.setAccountInfo(command.getNickname(), command.getAvatar(), Sex.of(command.getSex()));
account.setUpdatedBy(adminAuthLogic.getLoginIdAsLong());
accountRepository.save(account); accountRepository.save(account);
} }

View File

@ -6,10 +6,10 @@ 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.AccountLoginException;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException; 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.query.AccountQueries; import xyz.zhouxy.plusone.system.application.query.AccountQueries;
import xyz.zhouxy.plusone.system.application.query.result.LoginInfoViewObject; import xyz.zhouxy.plusone.system.application.query.result.LoginInfoViewObject;
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand; import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;

View File

@ -9,8 +9,8 @@ import org.springframework.util.Assert;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import xyz.zhouxy.plusone.mail.MailService; import xyz.zhouxy.plusone.mail.MailService;
import xyz.zhouxy.plusone.sms.SmsService; import xyz.zhouxy.plusone.sms.SmsService;
import xyz.zhouxy.plusone.system.application.common.exception.AccountLoginException; import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
import xyz.zhouxy.plusone.system.application.common.exception.AccountRegisterException; import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
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;

View File

@ -1,6 +1,7 @@
package xyz.zhouxy.plusone.system.application.service; package xyz.zhouxy.plusone.system.application.service;
import java.util.Collection; import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -12,10 +13,10 @@ 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.commons.util.MoreCollections;
import xyz.zhouxy.plusone.constant.EntityStatus; import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.IWithOrderNumber;
import xyz.zhouxy.plusone.exception.DataNotExistException; import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.system.application.common.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;
import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand; import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand;
@ -107,7 +108,7 @@ public class MenuManagementService {
command.getIcon(), command.getIcon(),
command.getHidden(), command.getHidden(),
command.getOrderNumber(), command.getOrderNumber(),
EntityStatus.of(command.getStatus()), EntityStatus.of(command.getStatus()),
command.getComponent(), command.getComponent(),
command.getResource(), command.getResource(),
command.getCache(), command.getCache(),
@ -138,33 +139,38 @@ public class MenuManagementService {
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public List<MenuViewObject> buildMenuTree(List<MenuViewObject> menus) { public List<MenuViewObject> buildMenuTree(List<MenuViewObject> menus) {
// 创建并填充 Map List<MenuViewObject> rootMenus = menus
final Map<Long, MenuViewObject> menuMap = MoreCollections.toHashMap(menus, MenuViewObject::getId); .stream()
.filter(menu -> Objects.equals(menu.getParentId(), 0L))
.toList();
Map<Long, MenuViewObject> allMenus = new HashMap<>();
for (var item : menus) {
allMenus.put(item.getId(), item);
}
for (MenuViewObject menu : menus) { for (MenuViewObject menu : menus) {
long parentId = menu.getParentId(); long parentId = menu.getParentId();
if (parentId != 0L) { while (parentId != 0 && !allMenus.containsKey(parentId)) {
while (!menuMap.containsKey(parentId)) { MenuViewObject parent = findById(parentId);
MenuViewObject parent = findById(parentId); if (parent == null) {
if (parent == null) { break;
break;
}
menuMap.put(parent.getId(), parent);
parentId = parent.getParentId();
} }
allMenus.put(parent.getId(), parent);
parentId = parent.getParentId();
} }
} }
Collection<MenuViewObject> allMenus = menuMap.values(); for (var menu : allMenus.values()) {
for (var menu : allMenus) { var parent = allMenus.getOrDefault(menu.getParentId(), null);
var parent = menuMap.get(menu.getParentId());
if (parent != null) { if (parent != null) {
parent.addChild(menu); parent.addChild(menu);
} }
} }
return allMenus.stream() return rootMenus
.filter(menu -> (menu != null) && Objects.equals(menu.getParentId(), 0L)) .stream()
.sorted() .sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
.toList(); .toList();
} }
} }

View File

@ -5,10 +5,10 @@ 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.AccountRegisterException;
import xyz.zhouxy.plusone.system.application.common.exception.UnsupportedPrincipalTypeException; 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.service.command.RegisterAccountCommand; import xyz.zhouxy.plusone.system.application.service.command.RegisterAccountCommand;
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;

View File

@ -16,7 +16,7 @@ public class LoginByOtpCommandValidator extends BaseValidator<LoginByOtpCommand>
ruleForString(LoginByOtpCommand::getPrincipal) ruleForString(LoginByOtpCommand::getPrincipal)
.notNull("输入邮箱地址或手机号") .notNull("输入邮箱地址或手机号")
.notEmpty("输入邮箱地址或手机号") .notEmpty("输入邮箱地址或手机号")
.matchesOne(List.of(PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), "输入用户名、邮箱地址或手机号"); .matchesOr(List.of(PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), "输入用户名、邮箱地址或手机号");
ruleForString(LoginByOtpCommand::getOtp) ruleForString(LoginByOtpCommand::getOtp)
.notNull("验证码不能为空") .notNull("验证码不能为空")
.notEmpty("验证码不能为空") .notEmpty("验证码不能为空")

View File

@ -15,7 +15,7 @@ public class LoginByPasswordCommandValidator extends BaseValidator<LoginByPasswo
ruleForString(LoginByPasswordCommand::getPrincipal) ruleForString(LoginByPasswordCommand::getPrincipal)
.notNull("输入用户名、邮箱地址或手机号") .notNull("输入用户名、邮箱地址或手机号")
.notEmpty("输入用户名、邮箱地址或手机号") .notEmpty("输入用户名、邮箱地址或手机号")
.matchesOne(List.of(PatternConsts.USERNAME, PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), .matchesOr(List.of(PatternConsts.USERNAME, PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE),
"输入用户名、邮箱地址或手机号"); "输入用户名、邮箱地址或手机号");
ruleForString(LoginByPasswordCommand::getPassword) ruleForString(LoginByPasswordCommand::getPassword)
.notNull("密码不能为空") .notNull("密码不能为空")

View File

@ -1,20 +0,0 @@
package xyz.zhouxy.plusone.system.application.web.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
HandlerInterceptor[] interceptors;
@Override
public void addInterceptors(InterceptorRegistry registry) {
for (var interceptor : interceptors) {
registry.addInterceptor(interceptor);
}
}
}

View File

@ -1,32 +0,0 @@
package xyz.zhouxy.plusone.system.application.web.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.system.application.common.model.PlusoneContext;
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;;
@Slf4j
@Order(1)
@Component
public class HttpContextInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("" + adminAuthLogic.isLogin());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
PlusoneContext.remove();
log.info("拦截器清理 ThreadLocal防止内存泄漏");
}
}

View File

@ -1,7 +0,0 @@
/**
*
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @since 1.0
*/
package xyz.zhouxy.plusone.system.application.web.interceptor;

View File

@ -87,13 +87,10 @@
AND sar.role_id = #{roleId} AND sar.role_id = #{roleId}
AND sr.deleted = 0 AND sr.deleted = 0
</if> </if>
<if test="orderBy != null and !orderBy.isEmpty()"> <if test="orderBy != null">
ORDER BY ORDER BY sa.${orderBy}, sa.id
<foreach item="col" index="index" collection="orderBy" open="" separator="," close="">
sa.${col}
</foreach>
</if> </if>
<if test="orderBy == null or orderBy.isEmpty()"> <if test="orderBy == null">
ORDER BY sa.id ORDER BY sa.id
</if> </if>
LIMIT #{size} OFFSET #{offset} LIMIT #{size} OFFSET #{offset}
@ -102,7 +99,7 @@
</select> </select>
<!-- <!--
long count(AccountQueryParams queryParams); long count(SysAccountQuery queryParams);
--> -->
<select id="count" resultType="long"> <select id="count" resultType="long">
SELECT COUNT(*) SELECT COUNT(*)

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone-system</artifactId> <artifactId>plusone-system</artifactId>

View File

@ -1,12 +1,15 @@
package xyz.zhouxy.plusone.system.util; package xyz.zhouxy.plusone.system.util;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.springframework.util.Assert; import javax.annotation.Nonnull;
import com.google.common.hash.Hashing;
import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.util.RandomUtil; import xyz.zhouxy.plusone.util.RandomUtil;
/** /**
@ -14,6 +17,7 @@ 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 char[] SALT_BASE_CHAR_ARRAY = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]|\\:;\"',.<>?/" private static final char[] SALT_BASE_CHAR_ARRAY = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]|\\:;\"',.<>?/"
.toCharArray(); .toCharArray();
@ -25,18 +29,18 @@ public final class PasswordUtil {
* @param salt * @param salt
* @return * @return
*/ */
public static String hashPassword(String password, String salt) { @Nonnull
Assert.notNull(password, "Password must not be null"); public static String hashPassword(@Nonnull String password, @Nonnull String salt) {
Assert.notNull(salt, "Salt must not be null"); int length = salt.length();
return Hashing.sha512().newHasher() int i = length > 0 ? length / 2 : 0;
.putInt(Arrays.hashCode(salt.toCharArray())) var passwordWithSalt = salt.substring(0, i)
.putString(password, StandardCharsets.UTF_8) + password
.putInt(password.length()) + salt.substring(1);
.putBoolean(password.length() % 2 == 0) String sha512Hex = sha512Hex(passwordWithSalt);
.putString(salt, StandardCharsets.UTF_8) if (sha512Hex == null) {
.putInt(Arrays.hashCode(password.toCharArray())) throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, "未知错误:哈希加密失败!");
.hash() }
.toString(); return sha512Hex;
} }
/** /**
@ -52,4 +56,16 @@ public final class 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

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>xyz.zhouxy</groupId> <groupId>xyz.zhouxy</groupId>

View File

@ -6,7 +6,6 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IWithVersion; import xyz.zhouxy.plusone.domain.IWithVersion;
import xyz.zhouxy.plusone.exception.UserOperationException; import xyz.zhouxy.plusone.exception.UserOperationException;
@ -165,7 +164,6 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
return newInstance; return newInstance;
} }
@StaticFactoryMethod(Account.class)
public static Account register( public static Account register(
Username username, Username username,
Email email, Email email,
@ -195,7 +193,6 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
password, status, accountInfo, roleRefs, createdBy, updatedBy, version); password, status, accountInfo, roleRefs, createdBy, updatedBy, version);
} }
@StaticFactoryMethod(Account.class)
public static Account newInstance( public static Account newInstance(
String username, String username,
String email, String email,
@ -213,7 +210,6 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
return newInstance; return newInstance;
} }
@StaticFactoryMethod(Account.class)
public static Account register( public static Account register(
String username, String username,
String email, String email,
@ -269,6 +265,10 @@ public class Account extends AggregateRoot<Long> implements IWithVersion {
return Optional.ofNullable(updatedBy); return Optional.ofNullable(updatedBy);
} }
public void setUpdatedBy(long updatedBy) {
this.updatedBy = updatedBy;
}
@Override @Override
public long getVersion() { public long getVersion() {
return this.version; return this.version;

View File

@ -23,7 +23,7 @@ public final class AccountStatus extends Enumeration<AccountStatus> implements I
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 ValueSet<AccountStatus> VALUE_SET = ValueSet.of( private static final ValueSet<AccountStatus> VALUE_SET = new ValueSet<>(
AVAILABLE, AVAILABLE,
LOCKED); LOCKED);

View File

@ -3,11 +3,7 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nullable;
import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.DesensitizedUtil;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
@ -15,28 +11,38 @@ import xyz.zhouxy.plusone.commons.constant.PatternConsts;
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@ValueObject public class Email extends Principal {
public final class Email extends Principal {
public static final Pattern REGEX = PatternConsts.EMAIL; public static final Pattern REGEX = PatternConsts.EMAIL;
private Email(String email) { private Email(String email) {
super(email, REGEX); super(REGEX);
if (email == null) {
throw new IllegalArgumentException("邮箱地址不能为空");
}
this.value = email;
if (!isValid()) {
throw new IllegalArgumentException("邮箱地址格式错误");
}
} }
@StaticFactoryMethod(Email.class)
public static Email of(String email) { public static Email of(String email) {
return new Email(email); return new Email(email);
} }
@StaticFactoryMethod(Email.class)
@Nullable
public static Email ofNullable(String email) { public static Email ofNullable(String email) {
return Objects.nonNull(email) ? new Email(email) : null; return Objects.nonNull(email) ? new Email(email) : null;
} }
@Override /**
*
*/
public String safeValue() { public String safeValue() {
return DesensitizedUtil.email(value()); return DesensitizedUtil.email(this.value);
}
@Override
public String toString() {
return this.safeValue();
} }
} }

View File

@ -3,11 +3,7 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nullable;
import cn.hutool.core.util.DesensitizedUtil; import cn.hutool.core.util.DesensitizedUtil;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
@ -15,28 +11,35 @@ import xyz.zhouxy.plusone.commons.constant.PatternConsts;
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@ValueObject
public class MobilePhone extends Principal { public class MobilePhone extends Principal {
public static final Pattern REGEX = PatternConsts.MOBILE_PHONE; public static final Pattern REGEX = PatternConsts.MOBILE_PHONE;
private MobilePhone(String mobilePhone) { private MobilePhone(String mobilePhone) {
super(mobilePhone, REGEX); super(REGEX);
if (mobilePhone == null) {
throw new IllegalArgumentException("手机号不能为空");
}
this.value = mobilePhone;
if (!isValid()) {
throw new IllegalArgumentException("手机号格式错误");
}
} }
@StaticFactoryMethod(MobilePhone.class)
public static MobilePhone of(String mobilePhone) { public static MobilePhone of(String mobilePhone) {
return new MobilePhone(mobilePhone); return new MobilePhone(mobilePhone);
} }
@StaticFactoryMethod(MobilePhone.class)
@Nullable
public static MobilePhone ofNullable(String mobilePhone) { public static MobilePhone ofNullable(String mobilePhone) {
return Objects.nonNull(mobilePhone) ? new MobilePhone(mobilePhone) : null; return Objects.nonNull(mobilePhone) ? new MobilePhone(mobilePhone) : null;
} }
@Override
public String safeValue() { public String safeValue() {
return DesensitizedUtil.mobilePhone(this.value()); return DesensitizedUtil.mobilePhone(this.value);
}
@Override
public String toString() {
return this.safeValue();
} }
} }

View File

@ -3,31 +3,33 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.commons.domain.ValidatableStringRecord; import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
/** /**
* *
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@ValueObject
public class Nickname extends ValidatableStringRecord { public class Nickname extends ValidatableStringRecord {
public static final Pattern REGEX = PatternConsts.NICKNAME; public static final Pattern REGEX = PatternConsts.NICKNAME;
private Nickname(String value) { private Nickname(String value) {
super(value, REGEX); super(REGEX);
if (value == null) {
throw new IllegalArgumentException("昵称不能为空");
}
this.value = value;
if (!isValid()) {
throw new IllegalArgumentException("昵称格式错误");
}
} }
@StaticFactoryMethod(Nickname.class)
public static Nickname of(String nickname) { public static Nickname of(String nickname) {
return new Nickname(nickname); return new Nickname(nickname);
} }
@StaticFactoryMethod(Nickname.class)
public static Nickname ofNullable(String nickname) { public static Nickname ofNullable(String nickname) {
return Objects.nonNull(nickname) ? new Nickname(nickname) : null; return Objects.nonNull(nickname) ? new Nickname(nickname) : null;
} }

View File

@ -3,11 +3,14 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.constant.ErrorCodeConsts;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
import xyz.zhouxy.plusone.exception.BizException;
import xyz.zhouxy.plusone.system.util.PasswordUtil; import xyz.zhouxy.plusone.system.util.PasswordUtil;
/** /**
@ -20,35 +23,43 @@ public class Password implements IValueObject {
private static final Pattern PATTERN = PatternConsts.PASSWORD; private static final Pattern PATTERN = PatternConsts.PASSWORD;
private static final String DEFAULT_PASSWORD = "A1b2C3d4"; private static final String DEFAULT_PASSWORD = "A1b2C3d4";
@Nonnull
private final String passwordVal; private final String passwordVal;
@Nonnull
private final String saltVal; private final String saltVal;
private Password(String password) { private Password(String password) {
Assert.notNull(password, "密码不能为空"); if (password == null) {
Assert.isTrue(PATTERN.matcher(password).matches(), "密码格式不符合要求"); throw new IllegalArgumentException("密码不能为空");
String salt = PasswordUtil.generateRandomSalt(); }
if (!PATTERN.matcher(password).matches()) {
throw new IllegalArgumentException("密码格式不符合要求");
}
var salt = PasswordUtil.generateRandomSalt();
if (salt == null) {
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);
} }
private Password(String password, String salt) { private Password(String password, String salt) {
Assert.isTrue(password != null && salt != null, "password 和 salt 不能为空"); if (password == null || salt == null) {
throw new IllegalArgumentException("password 和 salt 不能为空");
}
this.passwordVal = password; this.passwordVal = password;
this.saltVal = salt; this.saltVal = salt;
} }
@StaticFactoryMethod(Password.class)
public static Password of(String password, String salt) { public static Password of(String password, String salt) {
return new Password(password, salt); return new Password(password, salt);
} }
@StaticFactoryMethod(Password.class)
public static Password newPassword(String newPassword, String passwordConfirmation) { public static Password newPassword(String newPassword, String passwordConfirmation) {
Assert.isTrue(Objects.equals(newPassword, passwordConfirmation), "两次输入的密码不一致"); Assert.isTrue(Objects.equals(newPassword, passwordConfirmation), "两次输入的密码不一致");
return newPassword(newPassword); return newPassword(newPassword);
} }
@StaticFactoryMethod(Password.class)
public static Password newPassword(String newPassword) { public static Password newPassword(String newPassword) {
return new Password(newPassword); return new Password(newPassword);
} }
@ -69,7 +80,6 @@ public class Password implements IValueObject {
return saltVal; return saltVal;
} }
@StaticFactoryMethod(Nickname.class)
public static Password newDefaultPassword() { public static Password newDefaultPassword() {
return newPassword(DEFAULT_PASSWORD); return newPassword(DEFAULT_PASSWORD);
} }

View File

@ -2,23 +2,15 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import xyz.zhouxy.plusone.commons.domain.ValidatableStringRecord; import xyz.zhouxy.plusone.domain.ValidatableStringRecord;
import xyz.zhouxy.plusone.domain.IValueObject;
/** /**
* *
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
public abstract class Principal extends ValidatableStringRecord implements IValueObject { public abstract class Principal extends ValidatableStringRecord {
protected Principal(String principal, Pattern pattern) { protected Principal(Pattern format) {
super(principal, pattern); super(format);
}
protected abstract String safeValue();
@Override
public final String toString() {
return this.safeValue();
} }
} }

View File

@ -4,7 +4,6 @@ import java.util.Collection;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.util.Enumeration; import xyz.zhouxy.plusone.commons.util.Enumeration;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
@ -25,9 +24,8 @@ public final class Sex extends Enumeration<Sex> implements IValueObject {
super(id, name); super(id, name);
} }
private static final ValueSet<Sex> VALUE_SET = ValueSet.of(UNSET, MALE, FEMALE); private static final ValueSet<Sex> VALUE_SET = new ValueSet<>(UNSET, MALE, FEMALE);
@StaticFactoryMethod(Sex.class)
public static Sex of(int value) { public static Sex of(int value) {
return VALUE_SET.get(value); return VALUE_SET.get(value);
} }

View File

@ -2,8 +2,6 @@ package xyz.zhouxy.plusone.system.domain.model.account;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.commons.annotation.ValueObject;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
/** /**
@ -11,23 +9,22 @@ import xyz.zhouxy.plusone.commons.constant.PatternConsts;
* *
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a> * @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/ */
@ValueObject
public class Username extends Principal { public class Username extends Principal {
public static final Pattern REGEX = PatternConsts.USERNAME; public static final Pattern REGEX = PatternConsts.USERNAME;
private Username(String username) { private Username(String username) {
super(username, REGEX); super(REGEX);
if (username == null) {
throw new IllegalArgumentException("用户名不能为空");
}
this.value = username;
if (!isValid()) {
throw new IllegalArgumentException("用户名格式错误");
}
} }
@StaticFactoryMethod(Username.class)
public static Username of(String username) { public static Username of(String username) {
return new Username(username); return new Username(username);
} }
@Override
protected String safeValue() {
// 不需要脱敏。
return value();
}
} }

View File

@ -8,7 +8,6 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IWithLabel; import xyz.zhouxy.plusone.domain.IWithLabel;
import xyz.zhouxy.plusone.domain.IWithVersion; import xyz.zhouxy.plusone.domain.IWithVersion;
@ -71,14 +70,12 @@ public class Dict extends AggregateRoot<Long> implements IWithLabel, IWithVersio
this.version = version; this.version = version;
} }
@StaticFactoryMethod(Dict.class)
public static Dict newInstance( public static Dict newInstance(
String dictType, String dictType,
String dictLabel) { String dictLabel) {
return new Dict(null, dictType, dictLabel, Collections.emptySet(), 0); return new Dict(null, dictType, dictLabel, Collections.emptySet(), 0);
} }
@StaticFactoryMethod(Dict.class)
public static Dict newInstance( public static Dict newInstance(
String dictType, String dictType,
String dictLabel, String dictLabel,
@ -86,7 +83,6 @@ public class Dict extends AggregateRoot<Long> implements IWithLabel, IWithVersio
return new Dict(null, dictType, dictLabel, values, 0); return new Dict(null, dictType, dictLabel, values, 0);
} }
@StaticFactoryMethod(Dict.class)
public static Dict newInstance( public static Dict newInstance(
String dictType, String dictType,
String dictLabel, String dictLabel,

View File

@ -4,7 +4,6 @@ import java.util.Objects;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
/** /**
@ -26,7 +25,6 @@ public class DictValue implements IValueObject {
this.label = label; this.label = label;
} }
@StaticFactoryMethod(DictValue.class)
public static DictValue of(int key, String label) { public static DictValue of(int key, String label) {
return new DictValue(key, label); return new DictValue(key, label);
} }

View File

@ -9,7 +9,6 @@ import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import xyz.zhouxy.plusone.commons.base.IWithIntCode;
import xyz.zhouxy.plusone.constant.EntityStatus; import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IWithOrderNumber; import xyz.zhouxy.plusone.domain.IWithOrderNumber;
@ -130,28 +129,12 @@ public class Menu extends AggregateRoot<Long> implements IWithOrderNumber, IWith
this.version = version; this.version = version;
} }
public enum MenuType implements IWithIntCode { public enum MenuType {
MENU_LIST(0), MENU_ITEM(1); MENU_LIST, MENU_ITEM;
private final int code;
private MenuType(int code) {
this.code = code;
}
@JsonValue @JsonValue
@Override public int value() {
public int getCode() { return ordinal();
return code;
}
public static MenuType valueOf(int code) {
for (MenuType value : values()) {
if (value.code == code) {
return value;
}
}
throw new EnumConstantNotPresentException(MenuType.class, Integer.toString(code));
} }
} }
} }

View File

@ -2,7 +2,6 @@ package xyz.zhouxy.plusone.system.domain.model.menu;
import java.util.List; import java.util.List;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.constant.EntityStatus; import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType; import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
@ -17,7 +16,6 @@ public class MenuConstructor {
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
@StaticFactoryMethod(Menu.class)
public static Menu newMenuItem( public static Menu newMenuItem(
long parentId, long parentId,
String path, String path,
@ -41,7 +39,6 @@ public class MenuConstructor {
remarks, component, cache, resource, actions, 0L); remarks, component, cache, resource, actions, 0L);
} }
@StaticFactoryMethod(Menu.class)
public static Menu newMenuList( public static Menu newMenuList(
long parentId, long parentId,
String path, String path,

View File

@ -3,7 +3,6 @@ package xyz.zhouxy.plusone.system.domain.model.permission;
import java.util.Optional; import java.util.Optional;
import lombok.Getter; import lombok.Getter;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.domain.Entity; import xyz.zhouxy.plusone.domain.Entity;
import xyz.zhouxy.plusone.domain.IWithLabel; import xyz.zhouxy.plusone.domain.IWithLabel;
import xyz.zhouxy.plusone.domain.IWithVersion; import xyz.zhouxy.plusone.domain.IWithVersion;
@ -21,7 +20,7 @@ public class Action extends Entity<Long> implements IWithLabel, IWithVersion {
@Getter String label; @Getter String label;
@Getter long version; @Getter long version;
private Action(Long id, String resource, String identifier, String label, long version) { public Action(Long id, String resource, String identifier, String label, long version) {
this.id = id; this.id = id;
this.resource = resource; this.resource = resource;
this.identifier = identifier; this.identifier = identifier;
@ -29,12 +28,10 @@ public class Action extends Entity<Long> implements IWithLabel, IWithVersion {
this.version = version; this.version = version;
} }
@StaticFactoryMethod(Action.class)
static Action newInstance(String resource, String identifier, String label) { static Action newInstance(String resource, String identifier, String label) {
return new Action(null, resource, identifier, label, 0L); return new Action(null, resource, identifier, label, 0L);
} }
@StaticFactoryMethod(Action.class)
static Action existingInstance(Long id, String resource, String action, String label, Long version) { static Action existingInstance(Long id, String resource, String action, String label, Long version) {
return new Action(id, resource, action, label, version); return new Action(id, resource, action, label, version);
} }

View File

@ -6,7 +6,6 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import lombok.Getter; import lombok.Getter;
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
import xyz.zhouxy.plusone.domain.AggregateRoot; import xyz.zhouxy.plusone.domain.AggregateRoot;
import xyz.zhouxy.plusone.domain.IWithVersion; import xyz.zhouxy.plusone.domain.IWithVersion;
@ -38,7 +37,6 @@ public class Permission extends AggregateRoot<Long> implements IWithVersion {
// ==================== 实例化 ==================== // ==================== 实例化 ====================
@StaticFactoryMethod(Permission.class)
public static Permission newInstance(String resource) { public static Permission newInstance(String resource) {
return new Permission( return new Permission(
null, resource, null, resource,

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone-system</artifactId> <artifactId>plusone-system</artifactId>

View File

@ -14,8 +14,7 @@ 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 xyz.zhouxy.plusone.commons.domain.ValidatableStringRecord; import static xyz.zhouxy.plusone.domain.ValidatableStringRecord.getValueOrNull;
import xyz.zhouxy.plusone.commons.util.OptionalUtil;
import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport; import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport;
/** /**
@ -197,35 +196,23 @@ public class AccountRepositoryImpl extends JdbcRepositorySupport<Account, Long>
@Override @Override
protected final SqlParameterSource generateParamSource(Long id, @Nonnull Account entity) { protected final SqlParameterSource generateParamSource(Long id, @Nonnull Account entity) {
final LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
final AccountInfo accountInfo = entity.getAccountInfo(); AccountInfo accountInfo = entity.getAccountInfo();
final Optional<String> email = entity.getEmail().map(ValidatableStringRecord::value);
final Optional<String> mobilePhone = entity.getMobilePhone().map(ValidatableStringRecord::value);
final String username = entity.getUsername().value();
final String password = entity.getPassword().value();
final String salt = entity.getPassword().getSalt();
final Optional<String> avatar = accountInfo.getAvatar().map(Object::toString);
final int sex = accountInfo.getSex().getId();
final Optional<String> nickname = accountInfo.getNickname().map(ValidatableStringRecord::value);
final int status = entity.getStatus().getId();
final Optional<Long> createdBy = entity.getCreatedBy();
final Optional<Long> updatedBy = entity.getUpdatedBy();
final long version = entity.getVersion();
return new MapSqlParameterSource() return new MapSqlParameterSource()
.addValue("id", id) .addValue("id", id)
.addValue("email", OptionalUtil.orElseNull(email)) .addValue("email", getValueOrNull(entity.getEmail()))
.addValue("mobilePhone", OptionalUtil.orElseNull(mobilePhone)) .addValue("mobilePhone", getValueOrNull(entity.getMobilePhone()))
.addValue("username", username) .addValue("username", entity.getUsername().value())
.addValue("password", password) .addValue("password", entity.getPassword().value())
.addValue("salt", salt) .addValue("salt", entity.getPassword().getSalt())
.addValue("avatar", OptionalUtil.orElseNull(avatar)) .addValue("avatar", accountInfo.getAvatar().toString())
.addValue("sex", sex) .addValue("sex", accountInfo.getSex().getId())
.addValue("nickname", OptionalUtil.orElseNull(nickname)) .addValue("nickname", getValueOrNull(accountInfo.getNickname()))
.addValue("status", status) .addValue("status", entity.getStatus().getId())
.addValue("createdBy", OptionalUtil.orElseNull(createdBy)) .addValue("createdBy", entity.getCreatedBy())
.addValue("createTime", now) .addValue("createTime", now)
.addValue("updatedBy", OptionalUtil.orElseNull(updatedBy)) .addValue("updatedBy", entity.getUpdatedBy())
.addValue("updateTime", now) .addValue("updateTime", now)
.addValue("version", version); .addValue("version", entity.getVersion());
} }
} }

View File

@ -7,7 +7,6 @@ import java.sql.SQLException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -95,12 +94,13 @@ public class DictRepositoryImpl extends JdbcRepositorySupport<Dict, Long> implem
@Override @Override
protected final Dict mapRow(ResultSet rs) throws SQLException { protected final Dict mapRow(ResultSet rs) throws SQLException {
final long id = rs.getLong("id"); long id = rs.getLong("id");
final String dictType = rs.getString("dict_type"); return new Dict(
final String dictLabel = rs.getString("dict_label"); id,
final Set<DictValue> values = this.dictValueDAO.selectDictValuesByDictId(id); rs.getString("dict_type"),
final long version = rs.getLong("version"); rs.getString("dict_label"),
return new Dict(id, dictType, dictLabel, values, version); this.dictValueDAO.selectDictValuesByDictId(id),
rs.getLong("version"));
} }
@Override @Override

View File

@ -17,6 +17,7 @@ import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import xyz.zhouxy.plusone.commons.util.EnumUtil;
import xyz.zhouxy.plusone.constant.EntityStatus; import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.exception.DataNotExistException; import xyz.zhouxy.plusone.exception.DataNotExistException;
import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport; import xyz.zhouxy.plusone.jdbc.JdbcRepositorySupport;
@ -155,7 +156,7 @@ public class MenuRepositoryImpl extends JdbcRepositorySupport<Menu, Long> implem
protected final Menu mapRow(ResultSet rs) throws SQLException { protected final Menu mapRow(ResultSet rs) throws SQLException {
long menuId = rs.getLong("id"); long menuId = rs.getLong("id");
return new Menu( return new Menu(
MenuType.valueOf(rs.getInt("type")), EnumUtil.valueOf(MenuType.class, rs.getInt("type")),
menuId, menuId,
rs.getLong("parent_id"), rs.getLong("parent_id"),
rs.getString("name"), rs.getString("name"),
@ -180,7 +181,7 @@ public class MenuRepositoryImpl extends JdbcRepositorySupport<Menu, Long> implem
return new MapSqlParameterSource() return new MapSqlParameterSource()
.addValue("id", id) .addValue("id", id)
.addValue("parentId", entity.getParentId()) .addValue("parentId", entity.getParentId())
.addValue("type", entity.getType().getCode()) .addValue("type", entity.getType().value())
.addValue("name", entity.getName()) .addValue("name", entity.getName())
.addValue("path", entity.getPath()) .addValue("path", entity.getPath())
.addValue("title", entity.getTitle()) .addValue("title", entity.getTitle())

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<artifactId>plusone</artifactId> <artifactId>plusone</artifactId>

10
pom.xml
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -25,9 +25,9 @@
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<spring-boot.version>2.7.18</spring-boot.version> <spring-boot.version>2.7.10</spring-boot.version>
<sa-token.version>1.34.0</sa-token.version> <sa-token.version>1.34.0</sa-token.version>
<hutool.version>5.8.20</hutool.version> <hutool.version>5.8.16</hutool.version>
<mybatis-starter.version>3.0.1</mybatis-starter.version> <mybatis-starter.version>3.0.1</mybatis-starter.version>
<mybatis-plus.version>3.5.3.1</mybatis-plus.version> <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
<commons-io.version>2.11.0</commons-io.version> <commons-io.version>2.11.0</commons-io.version>
@ -40,7 +40,7 @@
<commons-pool2.version>2.11.1</commons-pool2.version> <commons-pool2.version>2.11.1</commons-pool2.version>
<tencentcloud-sdk.version>3.1.681</tencentcloud-sdk.version> <tencentcloud-sdk.version>3.1.681</tencentcloud-sdk.version>
<fastdfs.version>1.30-SNAPSHOT</fastdfs.version> <fastdfs.version>1.30-SNAPSHOT</fastdfs.version>
<okio.version>3.5.0</okio.version> <okio.version>3.0.0</okio.version>
<okhttp.version>4.10.0</okhttp.version> <okhttp.version>4.10.0</okhttp.version>
<plusone-basic.version>1.0.0-SNAPSHOT</plusone-basic.version> <plusone-basic.version>1.0.0-SNAPSHOT</plusone-basic.version>