11 Commits

75 changed files with 374 additions and 672 deletions

View File

@@ -19,10 +19,3 @@
目前项目还没完成,开发中…… 目前项目还没完成,开发中……
相关的文档和介绍完善中…… 相关的文档和介绍完善中……
## 编码规约
### 关于 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

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

View File

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

View File

@@ -8,7 +8,6 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import xyz.zhouxy.plusone.commons.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.commons.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.exception.SysException; import xyz.zhouxy.plusone.exception.SysException;
@@ -16,7 +15,7 @@ import xyz.zhouxy.plusone.exception.SysException;
@Slf4j @Slf4j
public class SysExceptionHandler extends BaseExceptionHandler { public class SysExceptionHandler extends BaseExceptionHandler {
public SysExceptionHandler(@Nonnull ExceptionInfoHolder exceptionInfoHolder) { public SysExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) {
super(exceptionInfoHolder); super(exceptionInfoHolder);
} }

View File

@@ -49,7 +49,7 @@
<dependency> <dependency>
<groupId>xyz.zhouxy.plusone</groupId> <groupId>xyz.zhouxy.plusone</groupId>
<artifactId>plusone-exception-handler</artifactId> <artifactId>plusone-exception-handler</artifactId>
<version>0.0.9-SNAPSHOT</version> <version>0.0.8-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

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,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

@@ -21,12 +21,15 @@ 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);
@Nonnull
public static EntityStatus of(int id) { public static EntityStatus of(int id) {
return VALUE_SET.get(id); return VALUE_SET.get(id);
} }
@Nonnull
public static Collection<EntityStatus> constants() { public static Collection<EntityStatus> constants() {
return VALUE_SET.getValues(); return VALUE_SET.getValues();
} }

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

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

View File

@@ -3,9 +3,6 @@ package xyz.zhouxy.plusone.jdbc;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource; import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import xyz.zhouxy.plusone.commons.exception.IWithCode;
import xyz.zhouxy.plusone.commons.exception.IWithIntCode;
/** /**
* 扩展了 {@link BeanPropertySqlParameterSource},在将 POJO 转换为 * 扩展了 {@link BeanPropertySqlParameterSource},在将 POJO 转换为
* {@link org.springframework.jdbc.core.namedparam.SqlParameterSource} 时, * {@link org.springframework.jdbc.core.namedparam.SqlParameterSource} 时,
@@ -20,23 +17,17 @@ import xyz.zhouxy.plusone.commons.exception.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>

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,19 +88,19 @@ 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 final <T> void assertResultEquals(T result, T expectedValue) { protected static final <T> void assertResultEquals(T result, T expectedValue) {

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 new SysException(e);
}
} }
} }
} }

View File

@@ -1,5 +1,7 @@
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;
@@ -8,11 +10,8 @@ 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.constant.ErrorCodeConsts; import xyz.zhouxy.plusone.exception.SysException;
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;
@@ -62,14 +61,13 @@ public class TencentSmsServiceImpl implements SmsService {
var res = client.SendSms(req); var res = client.SendSms(req);
// 输出json格式的字符串回包 // 输出json格式的字符串回包
System.out.println(SendSmsResponse.toJsonString(res)); log.info(SendSmsResponse.toJsonString(res));
// 也可以取出单个值你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义 // 也可以取出单个值你可以通过官网接口文档或跳转到response对象的定义处查看返回字段的定义
// System.out.println(res.getRequestId()); // System.out.println(res.getRequestId());
} catch (TencentCloudSDKException e) { } catch (TencentCloudSDKException e) {
log.error(e.getMessage(), e); throw new SysException(e);
throw new BizException(ErrorCodeConsts.DEFAULT_ERROR_CODE, e);
} }
} }

View File

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

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,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,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 new BizException(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

@@ -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;

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;
import static xyz.zhouxy.plusone.commons.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;

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.commons.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;

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;
import static xyz.zhouxy.plusone.commons.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;

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;
import static xyz.zhouxy.plusone.commons.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.success;
@@ -15,6 +15,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import xyz.zhouxy.plusone.system.application.query.params.MenuQueryParams;
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;
@@ -66,7 +67,14 @@ public class MenuManagementController {
public RestfulResult 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 RestfulResult.success("查询成功", result); return success("查询成功", result);
}
@GetMapping
public RestfulResult queryMenuTree(MenuQueryParams queryParams) {
adminAuthLogic.checkPermission("sys-menu-query");
var result = service.queryMenuTree(queryParams);
return success("查询成功", result);
} }
@GetMapping("queryByAccountId") @GetMapping("queryByAccountId")

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.commons.util.RestfulResult.success; import static xyz.zhouxy.plusone.commons.util.RestfulResult.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;

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;

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;

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;

View File

@@ -1,12 +1,14 @@
package xyz.zhouxy.plusone.system.application.common.exception.handler; package xyz.zhouxy.plusone.system.application.exception.handler;
import javax.annotation.Nonnull;
import org.springframework.http.ResponseEntity; 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.commons.exception.handler.BaseExceptionHandler; import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler;
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
import xyz.zhouxy.plusone.commons.util.RestfulResult; import xyz.zhouxy.plusone.commons.util.RestfulResult;
import xyz.zhouxy.plusone.system.application.common.exception.AccountLoginException;
@RestControllerAdvice @RestControllerAdvice
public class AccountLoginExceptionHandler extends BaseExceptionHandler { public class AccountLoginExceptionHandler extends BaseExceptionHandler {
@@ -16,7 +18,7 @@ public class AccountLoginExceptionHandler extends BaseExceptionHandler {
} }
@ExceptionHandler({ AccountLoginException.class }) @ExceptionHandler({ AccountLoginException.class })
public ResponseEntity<RestfulResult> handleException(Exception e) { public ResponseEntity<RestfulResult> handleException(@Nonnull Exception e) {
return buildExceptionResponse(e); return buildExceptionResponse(e);
} }
} }

View File

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

View File

@@ -2,8 +2,6 @@ package xyz.zhouxy.plusone.system.application.query;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import xyz.zhouxy.plusone.commons.util.PageDTO; import xyz.zhouxy.plusone.commons.util.PageDTO;
@@ -25,7 +23,6 @@ public interface AccountQueries {
return PageDTO.of(content, total); return PageDTO.of(content, total);
} }
@Nonnull
List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams); List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams);
long count(AccountQueryParams queryParams); long count(AccountQueryParams queryParams);

View File

@@ -0,0 +1,23 @@
package xyz.zhouxy.plusone.system.application.query;
import java.util.List;
import org.springframework.stereotype.Component;
import xyz.zhouxy.plusone.system.application.query.params.MenuQueryParams;
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
/**
*
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
@Component
public class MenuQueries {
public List<MenuViewObject> queryMenuTree(MenuQueryParams queryParams) {
// TODO【添加】 实现该查询
return null;
}
}

View File

@@ -1,10 +0,0 @@
package xyz.zhouxy.plusone.system.application.query;
/**
*
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public interface PermissionQueries {
// TODO【添加】 权限信息查询器
}

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

@@ -0,0 +1,18 @@
package xyz.zhouxy.plusone.system.application.query.params;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import xyz.zhouxy.plusone.constant.EntityStatus;
@ToString
public class MenuQueryParams {
private @Getter @Setter String name;
private @Getter @Setter String path;
private @Getter @Setter String title;
private @Getter @Setter Boolean hidden;
private @Getter @Setter EntityStatus status;
private @Getter @Setter String component;
private @Getter @Setter Boolean cache;
private @Getter @Setter String resource;
}

View File

@@ -25,60 +25,28 @@ import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
public class MenuViewObject implements IWithOrderNumber { public class MenuViewObject implements IWithOrderNumber {
@Getter private @Getter @Setter Integer type;
@Setter
Integer type;
@Getter private @Getter @Setter String typeName;
@Setter
String typeName;
@Getter private @Getter @Setter Long id;
@Setter private @Getter @Setter Long parentId;
Long id;
@Getter
@Setter
Long parentId;
@Getter private @Getter @Setter String name;
@Setter
String name;
// 若 type 为 MENU_ITEM 且 path 以 http:// 或 https:// 开头则被识别为外链 // 若 type 为 MENU_ITEM 且 path 以 http:// 或 https:// 开头则被识别为外链
@Getter private @Getter @Setter String path;
@Setter private @Getter @Setter String title;
String path; private @Getter @Setter String icon;
@Getter private @Getter @Setter boolean hidden;
@Setter private @Getter @Setter int orderNumber;
String title; private @Getter @Setter Integer status;
@Getter private @Getter @Setter String remarks;
@Setter
String icon;
@Getter
@Setter
boolean hidden;
@Getter
@Setter
int orderNumber;
@Getter
@Setter
Integer status;
@Getter
@Setter
String remarks;
// MENU_ITEM // MENU_ITEM
@Getter private @Getter @Setter String component;
@Setter private @Getter @Setter Boolean cache;
String component; private @Getter @Setter String resource;
@Getter private @Getter @Setter List<Action> actions;
@Setter
Boolean cache;
@Getter
@Setter
String resource;
@Getter
@Setter
List<Action> actions;
// MENU_LIST // MENU_LIST
List<MenuViewObject> children; List<MenuViewObject> children;

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

@@ -16,7 +16,9 @@ import org.springframework.util.Assert;
import xyz.zhouxy.plusone.constant.EntityStatus; import xyz.zhouxy.plusone.constant.EntityStatus;
import xyz.zhouxy.plusone.domain.IWithOrderNumber; import xyz.zhouxy.plusone.domain.IWithOrderNumber;
import xyz.zhouxy.plusone.exception.DataNotExistException; import xyz.zhouxy.plusone.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.MenuQueries;
import xyz.zhouxy.plusone.system.application.query.params.MenuQueryParams;
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;
@@ -36,10 +38,12 @@ public class MenuManagementService {
private final MenuService menuService; private final MenuService menuService;
private final MenuRepository menuRepository; private final MenuRepository menuRepository;
private final MenuQueries menuQueries;
MenuManagementService(MenuService roleRepository, MenuRepository menuRepository) { MenuManagementService(MenuService menuService, MenuRepository menuRepository, MenuQueries menuQueries) {
this.menuService = roleRepository; this.menuService = menuService;
this.menuRepository = menuRepository; this.menuRepository = menuRepository;
this.menuQueries = menuQueries;
} }
// ==================== create ==================== // ==================== create ====================
@@ -123,6 +127,11 @@ public class MenuManagementService {
return MenuViewObject.of(menu.orElseThrow(DataNotExistException::new)); return MenuViewObject.of(menu.orElseThrow(DataNotExistException::new));
} }
@Transactional(propagation = Propagation.SUPPORTS)
public List<MenuViewObject> queryMenuTree(MenuQueryParams queryParams) {
return menuQueries.queryMenuTree(queryParams);
}
@Transactional(propagation = Propagation.SUPPORTS) @Transactional(propagation = Propagation.SUPPORTS)
public List<MenuViewObject> queryByAccountId(Long accountId) { public List<MenuViewObject> queryByAccountId(Long accountId) {
var menus = menuService.queryAllMenuListByAccountId(accountId); var menus = menuService.queryAllMenuListByAccountId(accountId);

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

@@ -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

@@ -1,12 +1,13 @@
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 xyz.zhouxy.plusone.exception.SysException;
import xyz.zhouxy.plusone.util.RandomUtil; import xyz.zhouxy.plusone.util.RandomUtil;
/** /**
@@ -25,18 +26,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(i);
.putBoolean(password.length() % 2 == 0) try {
.putString(salt, StandardCharsets.UTF_8) return sha512Hex(passwordWithSalt);
.putInt(Arrays.hashCode(password.toCharArray())) } catch (NoSuchAlgorithmException e) {
.hash() throw new SysException(e);
.toString(); }
} }
/** /**
@@ -52,4 +53,13 @@ public final class PasswordUtil {
// 不允许实例化 // 不允许实例化
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
@Nonnull
@SuppressWarnings("null")
private static String sha512Hex(String data) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
messageDigest.update(data.getBytes(StandardCharsets.UTF_8));
byte[] result = messageDigest.digest();
return new BigInteger(1, result).toString(16);
}
} }

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);
@@ -31,6 +31,7 @@ public final class AccountStatus extends Enumeration<AccountStatus> implements I
return VALUE_SET.get(id); return VALUE_SET.get(id);
} }
@Nonnull
public static Collection<AccountStatus> constants() { public static Collection<AccountStatus> constants() {
return VALUE_SET.getValues(); return VALUE_SET.getValues();
} }

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,13 @@ 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.domain.IValueObject; import xyz.zhouxy.plusone.domain.IValueObject;
import xyz.zhouxy.plusone.exception.SysException;
import xyz.zhouxy.plusone.system.util.PasswordUtil; import xyz.zhouxy.plusone.system.util.PasswordUtil;
/** /**
@@ -20,35 +22,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 SysException("未知错误:生成随机盐失败");
}
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 +79,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,13 +24,14 @@ 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) @Nonnull
public static Sex of(int value) { public static Sex of(int value) {
return VALUE_SET.get(value); return VALUE_SET.get(value);
} }
@Nonnull
public static Collection<Sex> constants() { public static Collection<Sex> constants() {
return VALUE_SET.getValues(); return VALUE_SET.getValues();
} }

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.exception.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

@@ -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

@@ -25,7 +25,7 @@
<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.13</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.16</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>