first commit.
This commit is contained in:
39
plusone-basic/plusone-basic-domain/pom.xml
Normal file
39
plusone-basic/plusone-basic-domain/pom.xml
Normal 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>
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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");
|
||||
}
|
||||
}
|
@@ -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> {
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package xyz.zhouxy.plusone.domain;
|
||||
|
||||
/**
|
||||
* 命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see ICommandHandler
|
||||
*/
|
||||
public interface ICommand {
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
}
|
@@ -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);
|
||||
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
package xyz.zhouxy.plusone.domain;
|
||||
|
||||
/**
|
||||
* 值对象
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IValueObject {
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package xyz.zhouxy.plusone.domain;
|
||||
|
||||
/**
|
||||
* 带可读的 label 属性
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IWithLabel {
|
||||
String getLabel();
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
package xyz.zhouxy.plusone.domain;
|
||||
|
||||
/**
|
||||
* 带版本号
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface IWithVersion {
|
||||
long getVersion();
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user