first commit.

This commit is contained in:
2022-12-07 18:14:38 +08:00
commit e916d067f3
183 changed files with 9649 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>xyz.zhouxy</groupId>
<artifactId>plusone-basic</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>plusone-basic-domain</artifactId>
<dependencies>
<dependency>
<artifactId>plusone-basic-common</artifactId>
<groupId>xyz.zhouxy</groupId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.4</version>
</dependency>
</dependencies>
</project>

View File

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

View File

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

View File

@@ -0,0 +1,17 @@
package xyz.zhouxy.plusone.domain;
import java.io.Serializable;
/**
* 聚合根
*
* <p>
* 由 Repository 负责整个聚合根的查询、保存、删除。
* </p>
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see Entity
* @see IRepository
*/
public abstract class AggregateRoot<ID extends Serializable> extends Entity<ID> {
}

View File

@@ -0,0 +1,26 @@
package xyz.zhouxy.plusone.domain;
import cn.hutool.core.lang.UUID;
import lombok.Getter;
/**
* 领域事件
*
* <p>
* <b>根据所使用的消息机制的不同,可能需要继承其它类,或实现 {@link java.io.Serializable} 接口</b>
* </p>
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see Entity
* @see IEventHandler
*/
@Getter
public abstract class DomainEvent {
private String identifier;
private long happenedAt;
protected DomainEvent() {
this.identifier = UUID.randomUUID().toString(true);
this.happenedAt = System.currentTimeMillis();
}
}

View File

@@ -0,0 +1,32 @@
package xyz.zhouxy.plusone.domain;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
/**
* 实体
*
* <p>
* DDD 中的实体,带有 ID。
* </p>
*
* <p>
* 维护一个 {@link DomainEvent} 的列表,持久化时可将其中的领域事件进行发布。
* </p>
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see IValueObject
* @see AggregateRoot
*/
public abstract class Entity<ID extends Serializable> {
private final List<DomainEvent> domainEvents = new ArrayList<>();
public abstract Optional<ID> getId();
protected void addDomainEvent(DomainEvent domainEvent) {
domainEvents.add(domainEvent);
}
}

View File

@@ -0,0 +1,10 @@
package xyz.zhouxy.plusone.domain;
/**
* 命令
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see ICommandHandler
*/
public interface ICommand {
}

View File

@@ -0,0 +1,12 @@
package xyz.zhouxy.plusone.domain;
/**
* 命令处理器
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see ICommand
*/
@FunctionalInterface
public interface ICommandHandler<T extends ICommand> {
void handle(T command);
}

View File

@@ -0,0 +1,12 @@
package xyz.zhouxy.plusone.domain;
/**
* 事件处理器
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see DomainEvent
*/
@FunctionalInterface
public interface IEventHandler<E extends DomainEvent> {
void handle(E command);
}

View File

@@ -0,0 +1,21 @@
package xyz.zhouxy.plusone.domain;
import java.io.Serializable;
/**
* Repository 基础接口
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
* @see AggregateRoot
*/
public interface IRepository<T extends AggregateRoot<ID>, ID extends Serializable> {
T find(ID id);
T save(T entity);
void delete(T entity);
boolean exists(ID id);
}

View File

@@ -0,0 +1,9 @@
package xyz.zhouxy.plusone.domain;
/**
* 值对象
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public interface IValueObject {
}

View File

@@ -0,0 +1,10 @@
package xyz.zhouxy.plusone.domain;
/**
* 带可读的 label 属性
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public interface IWithLabel {
String getLabel();
}

View File

@@ -0,0 +1,33 @@
package xyz.zhouxy.plusone.domain;
import java.util.Comparator;
import java.util.Objects;
/**
* 带 orderNumber 字段,可用来排序
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public interface IWithOrderNumber extends Comparable<IWithOrderNumber> {
int getOrderNumber();
@Override
default int compareTo(IWithOrderNumber that) {
return new OrderNumberComparator<IWithOrderNumber>().compare(this, that);
}
class OrderNumberComparator<T extends Comparable<T>>
implements Comparator<IWithOrderNumber> {
@Override
public int compare(IWithOrderNumber a, IWithOrderNumber b) {
if (Objects.equals(a, b)) {
return 0;
}
if (a == null) {
return -1;
}
return (b == null) ? 1 : Integer.compare(a.getOrderNumber(), b.getOrderNumber());
}
}
}

View File

@@ -0,0 +1,10 @@
package xyz.zhouxy.plusone.domain;
/**
* 带版本号
*
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
*/
public interface IWithVersion {
long getVersion();
}

View File

@@ -0,0 +1,34 @@
package xyz.zhouxy.plusone.domain;
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 String format;
protected ValidatableStringRecord(String format) {
this.format = format;
}
@JsonIgnore
protected boolean isValid() {
return value.matches(format);
}
@JsonValue
public String value() {
return value;
}
@Override
public String toString() {
return value;
}
}

View File

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