迁移实体类,并增加了领域模型(尝试使用event)
This commit is contained in:
parent
ee1e20daff
commit
b49a64724c
@ -3,7 +3,6 @@ package com.qqchen.deploy.backend.api;
|
||||
import com.qqchen.deploy.backend.common.controller.BaseController;
|
||||
import com.qqchen.deploy.backend.common.api.Response;
|
||||
import com.qqchen.deploy.backend.common.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.common.utils.MessageUtils;
|
||||
import com.qqchen.deploy.backend.converter.UserConverter;
|
||||
import com.qqchen.deploy.backend.entity.User;
|
||||
import com.qqchen.deploy.backend.dto.query.UserQuery;
|
||||
@ -39,7 +38,7 @@ public class UserApiController extends BaseController<User, Long, UserQuery, Use
|
||||
|
||||
User user = converter.toEntity(request);
|
||||
User savedUser = userService.register(user);
|
||||
return Response.success(converter.toVO(savedUser));
|
||||
return Response.success(converter.toResponse(savedUser));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
|
||||
@ -5,8 +5,15 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标记实体是否支持逻辑删除
|
||||
* 被标记的实体在删除时不会物理删除数据,而是标记删除状态
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface SoftDelete {
|
||||
boolean value() default true; // 默认启用软删除
|
||||
public @interface LogicDelete {
|
||||
/**
|
||||
* 是否启用逻辑删除,默认启用
|
||||
*/
|
||||
boolean value() default true;
|
||||
}
|
||||
@ -28,7 +28,7 @@ public abstract class BaseController<T extends Entity<ID>, ID extends Serializab
|
||||
public Response<V> create(@RequestBody R request) {
|
||||
T entity = converter.toEntity(request);
|
||||
T savedEntity = service.create(entity);
|
||||
return Response.success(converter.toVO(savedEntity));
|
||||
return Response.success(converter.toResponse(savedEntity));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ -36,7 +36,7 @@ public abstract class BaseController<T extends Entity<ID>, ID extends Serializab
|
||||
T entity = service.findById(id);
|
||||
converter.updateEntity(entity, request);
|
||||
T updatedEntity = service.update(entity);
|
||||
return Response.success(converter.toVO(updatedEntity));
|
||||
return Response.success(converter.toResponse(updatedEntity));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
@ -48,18 +48,18 @@ public abstract class BaseController<T extends Entity<ID>, ID extends Serializab
|
||||
@GetMapping("/{id}")
|
||||
public Response<V> findById(@PathVariable ID id) {
|
||||
T entity = service.findById(id);
|
||||
return Response.success(converter.toVO(entity));
|
||||
return Response.success(converter.toResponse(entity));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Response<List<V>> findAll() {
|
||||
List<T> entities = service.findAll();
|
||||
return Response.success(converter.toVOList(entities));
|
||||
return Response.success(converter.toResponseList(entities));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
public Response<Page<V>> page(Q query) {
|
||||
Page<T> page = service.page(query);
|
||||
return Response.success(page.map(entity -> converter.toVO(entity)));
|
||||
return Response.success(page.map(entity -> converter.toResponse(entity)));
|
||||
}
|
||||
}
|
||||
@ -12,16 +12,16 @@ public interface BaseConverter<D extends Entity<?>, R extends BaseRequest, V> {
|
||||
D toEntity(R request);
|
||||
|
||||
// Domain -> VO
|
||||
V toVO(D entity);
|
||||
V toResponse(D entity);
|
||||
|
||||
// Domain List -> VO List
|
||||
List<V> toVOList(List<D> entityList);
|
||||
List<V> toResponseList(List<D> entityList);
|
||||
|
||||
// 更新实体
|
||||
void updateEntity(@MappingTarget D entity, R request);
|
||||
|
||||
// 转换分页结果
|
||||
default Page<V> toVOPage(Page<D> page) {
|
||||
return page.map(this::toVO);
|
||||
default Page<V> toResponsePage(Page<D> page) {
|
||||
return page.map(this::toResponse);
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,72 @@
|
||||
package com.qqchen.deploy.backend.common.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import com.qqchen.deploy.backend.common.event.DomainEvent;
|
||||
import org.springframework.data.domain.AfterDomainEventPublication;
|
||||
import org.springframework.data.domain.DomainEvents;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 聚合根基类
|
||||
*/
|
||||
public abstract class AggregateRoot<ID extends Serializable> extends Entity<ID> {
|
||||
// 聚合根特定的行为可以在这里添加
|
||||
|
||||
private transient final List<DomainEvent> domainEvents = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 注册领域事件
|
||||
*/
|
||||
protected void registerDomainEvent(DomainEvent event) {
|
||||
if (event != null) {
|
||||
domainEvents.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并清除所有事件
|
||||
*/
|
||||
@DomainEvents
|
||||
protected Collection<DomainEvent> domainEvents() {
|
||||
List<DomainEvent> events = new ArrayList<>(this.domainEvents);
|
||||
this.domainEvents.clear();
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring Data JPA会在事件发布后调用此方法
|
||||
*/
|
||||
@AfterDomainEventPublication
|
||||
protected void clearDomainEvents() {
|
||||
this.domainEvents.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证聚合根状态
|
||||
* 子类可以重写此方法实现具体的验证逻辑
|
||||
*/
|
||||
protected void validateState() {
|
||||
// 默认实现为空,由子类根据需要重写
|
||||
}
|
||||
|
||||
/**
|
||||
* 在保存前验证状态
|
||||
*/
|
||||
public void validateBeforeSave() {
|
||||
validateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在更新前验证状态
|
||||
*/
|
||||
public void validateBeforeUpdate() {
|
||||
validateState();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在删除前验证状态
|
||||
*/
|
||||
public void validateBeforeDelete() {
|
||||
// 子类可以重写此方法添加删除前的验证
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.qqchen.deploy.backend.common.event;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
public abstract class DomainEvent {
|
||||
private final String eventId;
|
||||
private final LocalDateTime occurredOn;
|
||||
|
||||
protected DomainEvent() {
|
||||
this.eventId = java.util.UUID.randomUUID().toString();
|
||||
this.occurredOn = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.SoftDelete;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import com.qqchen.deploy.backend.common.enums.QueryType;
|
||||
import com.qqchen.deploy.backend.common.query.BaseQuery;
|
||||
@ -73,7 +73,7 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializa
|
||||
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(getClass(), BaseServiceImpl.class);
|
||||
if (genericTypes != null && genericTypes.length > 0) {
|
||||
Class<T> entityClass = (Class<T>) genericTypes[0];
|
||||
SoftDelete softDelete = entityClass.getAnnotation(SoftDelete.class);
|
||||
LogicDelete softDelete = entityClass.getAnnotation(LogicDelete.class);
|
||||
|
||||
if (softDelete != null && softDelete.value()) {
|
||||
Path<?> deletedPath = EntityPathResolver.getPath(entityPath, "deleted");
|
||||
|
||||
@ -19,7 +19,7 @@ public interface UserConverter extends BaseConverter<User, UserRequest, UserResp
|
||||
|
||||
@Override
|
||||
@Mapping(target = "password", ignore = true)
|
||||
UserResponse toVO(User user);
|
||||
UserResponse toResponse(User user);
|
||||
|
||||
@Override
|
||||
@Mapping(target = "id", ignore = true)
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
package com.qqchen.deploy.backend.dto.query;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.QueryField;
|
||||
import com.qqchen.deploy.backend.common.enums.QueryType;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserAddressQuery {
|
||||
@QueryField(type = QueryType.LIKE)
|
||||
private String city;
|
||||
|
||||
@QueryField(type = QueryType.EQUAL)
|
||||
private String postcode;
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_department")
|
||||
@LogicDelete
|
||||
public class Department extends Entity<Long> {
|
||||
|
||||
@NotBlank(message = "部门名称不能为空")
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "部门编码不能为空")
|
||||
@Column(nullable = false, unique = true)
|
||||
private String code;
|
||||
|
||||
private String description;
|
||||
|
||||
@Column(name = "parent_id")
|
||||
private Long parentId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer sort = 0;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
|
||||
@Column(name = "leader_id")
|
||||
private Long leaderId;
|
||||
|
||||
@Column(name = "leader_name")
|
||||
private String leaderName;
|
||||
|
||||
@Transient // 不映射到数据库
|
||||
private List<Department> children = new ArrayList<>();
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_jenkins_build")
|
||||
@LogicDelete
|
||||
public class JenkinsBuild extends Entity<Long> {
|
||||
|
||||
@Column(name = "jenkins_id", nullable = false)
|
||||
private Long jenkinsId;
|
||||
|
||||
@Column(name = "job_id", nullable = false)
|
||||
private Long jobId;
|
||||
|
||||
@Column(name = "build_number", nullable = false)
|
||||
private Integer buildNumber;
|
||||
|
||||
@Column(name = "build_url", nullable = false)
|
||||
private String buildUrl;
|
||||
|
||||
@Column(name = "build_status", nullable = false)
|
||||
private String buildStatus;
|
||||
|
||||
@Column(name = "start_time", nullable = false)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
private Long duration;
|
||||
|
||||
@Column(name = "trigger_cause", columnDefinition = "TEXT")
|
||||
private String triggerCause;
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_jenkins_config")
|
||||
@LogicDelete
|
||||
public class JenkinsConfig extends Entity<Long> {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String username;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private String remark;
|
||||
|
||||
@Column(name = "last_all_sync_time")
|
||||
private LocalDateTime lastAllSyncTime;
|
||||
|
||||
@Column(name = "last_view_sync_time")
|
||||
private LocalDateTime lastViewSyncTime;
|
||||
|
||||
@Column(name = "last_job_sync_time")
|
||||
private LocalDateTime lastJobSyncTime;
|
||||
|
||||
@Column(name = "last_build_sync_time")
|
||||
private LocalDateTime lastBuildSyncTime;
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_jenkins_job")
|
||||
@LogicDelete
|
||||
public class JenkinsJob extends Entity<Long> {
|
||||
|
||||
@Column(name = "jenkins_id", nullable = false)
|
||||
private Long jenkinsId;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "view_id")
|
||||
private JenkinsView view;
|
||||
|
||||
@Column(name = "job_name", nullable = false)
|
||||
private String jobName;
|
||||
|
||||
@Column(name = "job_url", nullable = false)
|
||||
private String jobUrl;
|
||||
|
||||
private String description;
|
||||
|
||||
private Boolean buildable;
|
||||
|
||||
@Column(name = "last_build_number")
|
||||
private Integer lastBuildNumber;
|
||||
|
||||
@Column(name = "last_build_time")
|
||||
private LocalDateTime lastBuildTime;
|
||||
|
||||
@Column(name = "last_build_status")
|
||||
private String lastBuildStatus;
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_jenkins_sync_history")
|
||||
@LogicDelete
|
||||
public class JenkinsSyncHistory extends Entity<Long> {
|
||||
|
||||
@Column(name = "jenkins_id", nullable = false)
|
||||
private Long jenkinsId;
|
||||
|
||||
@Column(name = "sync_type", nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SyncType syncType;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SyncStatus status;
|
||||
|
||||
@Column(name = "start_time", nullable = false)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Column(name = "end_time")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
||||
private String errorMessage;
|
||||
|
||||
public enum SyncType {
|
||||
ALL, // 全量同步
|
||||
VIEW, // 同步视图
|
||||
JOB, // 同步作业
|
||||
BUILD // 同步构建记录
|
||||
}
|
||||
|
||||
public enum SyncStatus {
|
||||
SUCCESS, // 同步成功
|
||||
FAILED, // 同步失败
|
||||
RUNNING // 同步中
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_jenkins_view")
|
||||
@LogicDelete
|
||||
public class JenkinsView extends Entity<Long> {
|
||||
|
||||
@Column(name = "jenkins_id", nullable = false)
|
||||
private Long jenkinsId;
|
||||
|
||||
@Column(name = "view_name", nullable = false)
|
||||
private String viewName;
|
||||
|
||||
@Column(name = "view_url", nullable = false)
|
||||
private String viewUrl;
|
||||
|
||||
private String description;
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_menu")
|
||||
@LogicDelete
|
||||
public class Menu extends Entity<Long> {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
private String permission;
|
||||
|
||||
private String path;
|
||||
|
||||
private String component;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer type; // 0-目录 1-菜单 2-按钮
|
||||
|
||||
private String icon;
|
||||
|
||||
@Column(name = "parent_id")
|
||||
private Long parentId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer sort = 0;
|
||||
|
||||
private Boolean hidden = false;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_repository_branch")
|
||||
@LogicDelete
|
||||
public class RepositoryBranch extends Entity<Long> {
|
||||
|
||||
@Column(name = "repository_id", nullable = false)
|
||||
private Long repositoryId;
|
||||
|
||||
@Column(name = "project_id", nullable = false)
|
||||
private Long projectId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "commit_id")
|
||||
private String commitId;
|
||||
|
||||
@Column(name = "commit_message", columnDefinition = "TEXT")
|
||||
private String commitMessage;
|
||||
|
||||
@Column(name = "commit_author")
|
||||
private String commitAuthor;
|
||||
|
||||
@Column(name = "commit_date")
|
||||
private LocalDateTime commitDate;
|
||||
|
||||
private Boolean protected_ = false;
|
||||
|
||||
@Column(name = "developers_can_push")
|
||||
private Boolean developersCanPush = true;
|
||||
|
||||
@Column(name = "developers_can_merge")
|
||||
private Boolean developersCanMerge = true;
|
||||
|
||||
@Column(name = "can_push")
|
||||
private Boolean canPush = true;
|
||||
|
||||
@Column(name = "default_branch")
|
||||
private Boolean defaultBranch = false;
|
||||
|
||||
@Column(name = "web_url")
|
||||
private String webUrl;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_repository_config")
|
||||
@LogicDelete
|
||||
public class RepositoryConfig extends Entity<Long> {
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String url;
|
||||
|
||||
@Column(name = "access_token", nullable = false)
|
||||
private String accessToken;
|
||||
|
||||
@Column(name = "api_version")
|
||||
private String apiVersion;
|
||||
|
||||
private Integer sort;
|
||||
|
||||
private String remark;
|
||||
|
||||
@Column(name = "last_sync_time")
|
||||
private LocalDateTime lastSyncTime;
|
||||
|
||||
@Column(name = "last_sync_status")
|
||||
@Enumerated(EnumType.STRING)
|
||||
private RepositorySyncHistory.SyncStatus lastSyncStatus;
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_repository_group")
|
||||
@LogicDelete
|
||||
public class RepositoryGroup extends Entity<Long> {
|
||||
|
||||
@Column(name = "repository_id", nullable = false)
|
||||
private Long repositoryId;
|
||||
|
||||
@Column(name = "group_id", nullable = false)
|
||||
private Long groupId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String path;
|
||||
|
||||
private String description;
|
||||
|
||||
private String visibility;
|
||||
|
||||
@Column(name = "parent_id")
|
||||
private Long parentId;
|
||||
|
||||
@Column(name = "web_url")
|
||||
private String webUrl;
|
||||
|
||||
@Column(name = "avatar_url")
|
||||
private String avatarUrl;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_repository_project")
|
||||
@LogicDelete
|
||||
public class RepositoryProject extends Entity<Long> {
|
||||
|
||||
@Column(name = "repository_id", nullable = false)
|
||||
private Long repositoryId;
|
||||
|
||||
@Column(name = "project_id", nullable = false)
|
||||
private Long projectId;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String path;
|
||||
|
||||
private String description;
|
||||
|
||||
private String visibility;
|
||||
|
||||
@Column(name = "group_id")
|
||||
private Long groupId;
|
||||
|
||||
@Column(name = "default_branch")
|
||||
private String defaultBranch;
|
||||
|
||||
@Column(name = "web_url")
|
||||
private String webUrl;
|
||||
|
||||
@Column(name = "ssh_url")
|
||||
private String sshUrl;
|
||||
|
||||
@Column(name = "http_url")
|
||||
private String httpUrl;
|
||||
|
||||
@Column(name = "last_activity_at")
|
||||
private LocalDateTime lastActivityAt;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_repository_sync_history")
|
||||
@LogicDelete
|
||||
public class RepositorySyncHistory extends Entity<Long> {
|
||||
|
||||
@Column(name = "repository_id", nullable = false)
|
||||
private Long repositoryId;
|
||||
|
||||
@Column(name = "sync_type", nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SyncType syncType;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private SyncStatus status;
|
||||
|
||||
@Column(name = "error_message", columnDefinition = "TEXT")
|
||||
private String errorMessage;
|
||||
|
||||
@Column(name = "start_time", nullable = false)
|
||||
private LocalDateTime startTime;
|
||||
|
||||
@Column(name = "end_time")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
public enum SyncType {
|
||||
GROUP, PROJECT, BRANCH
|
||||
}
|
||||
|
||||
public enum SyncStatus {
|
||||
SUCCESS, FAILED, RUNNING
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_role")
|
||||
@LogicDelete
|
||||
public class Role extends Entity<Long> {
|
||||
|
||||
@NotBlank(message = "角色名称不能为空")
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "角色编码不能为空")
|
||||
@Column(nullable = false, unique = true)
|
||||
private String code;
|
||||
|
||||
private String description;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Integer sort = 0;
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_role_menu")
|
||||
@LogicDelete
|
||||
public class RoleMenu extends Entity<Long> {
|
||||
|
||||
@Column(name = "role_id", nullable = false)
|
||||
private Long roleId;
|
||||
|
||||
@Column(name = "menu_id", nullable = false)
|
||||
private Long menuId;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_tenant")
|
||||
@LogicDelete
|
||||
public class Tenant extends Entity<Long> {
|
||||
|
||||
@NotBlank(message = "租户名称不能为空")
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@NotBlank(message = "租户编码不能为空")
|
||||
@Column(nullable = false, unique = true)
|
||||
private String code;
|
||||
|
||||
@Column(name = "contact_name")
|
||||
private String contactName;
|
||||
|
||||
@Column(name = "contact_phone")
|
||||
private String contactPhone;
|
||||
|
||||
private String email;
|
||||
|
||||
private String address;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
}
|
||||
@ -1,31 +1,143 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.SoftDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.AggregateRoot;
|
||||
import com.qqchen.deploy.backend.event.UserRoleChangedEvent;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "t_user")
|
||||
@SoftDelete
|
||||
public class User extends Entity<Long> {
|
||||
@Table(name = "sys_user")
|
||||
@LogicDelete
|
||||
public class User extends AggregateRoot<Long> {
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String username;
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String email;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String password;
|
||||
|
||||
@Column(length = 50)
|
||||
private String nickname;
|
||||
|
||||
private String email;
|
||||
|
||||
private String phone;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
}
|
||||
|
||||
@Column(name = "dept_id")
|
||||
private Long deptId;
|
||||
|
||||
@Column(name = "dept_name")
|
||||
private String deptName;
|
||||
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private Set<UserRole> userRoles = new HashSet<>();
|
||||
|
||||
public void addRole(Role role) {
|
||||
UserRole userRole = new UserRole(this, role);
|
||||
userRoles.add(userRole);
|
||||
registerDomainEvent(new UserRoleChangedEvent(this.getId(), role.getId(), "ADD"));
|
||||
validateState();
|
||||
}
|
||||
|
||||
public void removeRole(Role role) {
|
||||
boolean removed = userRoles.removeIf(ur -> ur.getRole().equals(role));
|
||||
if (removed) {
|
||||
registerDomainEvent(new UserRoleChangedEvent(this.getId(), role.getId(), "REMOVE"));
|
||||
validateState();
|
||||
}
|
||||
}
|
||||
|
||||
public void changePassword(String oldPassword, String newPassword) {
|
||||
if (!this.password.equals(oldPassword)) {
|
||||
throw new IllegalArgumentException("Old password is incorrect");
|
||||
}
|
||||
this.password = newPassword;
|
||||
registerDomainEvent(new PasswordChangedEvent(this.getId()));
|
||||
validateState();
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
if (this.enabled != enabled) {
|
||||
this.enabled = enabled;
|
||||
registerDomainEvent(new UserStatusChangedEvent(this.getId(), enabled));
|
||||
validateState();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBasicInfo(String nickname, String phone, String email) {
|
||||
boolean changed = false;
|
||||
|
||||
if (!Objects.equals(this.nickname, nickname)) {
|
||||
this.nickname = nickname;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!Objects.equals(this.phone, phone)) {
|
||||
this.phone = phone;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!Objects.equals(this.email, email)) {
|
||||
this.email = email;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
registerDomainEvent(new UserUpdatedEvent(this.getId()));
|
||||
validateState();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasRole(String roleCode) {
|
||||
return userRoles.stream()
|
||||
.map(UserRole::getRole)
|
||||
.anyMatch(role -> role.getCode().equals(roleCode));
|
||||
}
|
||||
|
||||
public Set<String> getRoleCodes() {
|
||||
return userRoles.stream()
|
||||
.map(UserRole::getRole)
|
||||
.map(Role::getCode)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateState() {
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
throw new IllegalStateException("Username cannot be empty");
|
||||
}
|
||||
if (email == null || !email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
|
||||
throw new IllegalStateException("Invalid email format");
|
||||
}
|
||||
if (password == null || password.length() < 6) {
|
||||
throw new IllegalStateException("Password must be at least 6 characters");
|
||||
}
|
||||
if (phone != null && !phone.matches("^\\d{11}$")) {
|
||||
throw new IllegalStateException("Invalid phone number format");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateBeforeDelete() {
|
||||
if (!userRoles.isEmpty()) {
|
||||
throw new IllegalStateException("Cannot delete user with assigned roles");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_user_role")
|
||||
@LogicDelete
|
||||
public class UserRole extends Entity<Long> {
|
||||
|
||||
@Column(name = "user_id", nullable = false)
|
||||
private Long userId;
|
||||
|
||||
@Column(name = "role_id", nullable = false)
|
||||
private Long roleId;
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.qqchen.deploy.backend.event;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class UserEventListener {
|
||||
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void handleUserRoleChanged(UserRoleChangedEvent event) {
|
||||
log.info("User role changed - userId: {}, roleId: {}, action: {}",
|
||||
event.getUserId(),
|
||||
event.getRoleId(),
|
||||
event.getAction());
|
||||
|
||||
// 这里可以添加后续处理逻辑
|
||||
// 例如:发送通知、更新缓存等
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.qqchen.deploy.backend.event;
|
||||
|
||||
import com.qqchen.deploy.backend.common.event.DomainEvent;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class UserRoleChangedEvent extends DomainEvent {
|
||||
private final Long userId;
|
||||
private final Long roleId;
|
||||
private final String action; // "ADD" or "REMOVE"
|
||||
public UserRoleChangedEvent(Long userId, Long roleId, String action) {
|
||||
super();
|
||||
this.userId = userId;
|
||||
this.roleId = roleId;
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
12
backend/src/main/resources/messages.properties
Normal file
12
backend/src/main/resources/messages.properties
Normal file
@ -0,0 +1,12 @@
|
||||
# \u4E2D\u6587
|
||||
response.success=\u64CD\u4F5C\u6210\u529F
|
||||
response.error=\u7CFB\u7EDF\u9519\u8BEF
|
||||
response.invalid.param=\u65E0\u6548\u7684\u53C2\u6570
|
||||
response.unauthorized=\u672A\u6388\u6743
|
||||
response.forbidden=\u7981\u6B62\u8BBF\u95EE
|
||||
response.not.found=\u8D44\u6E90\u672A\u627E\u5230
|
||||
response.conflict=\u8D44\u6E90\u51B2\u7A81
|
||||
|
||||
user.not.found=\u7528\u6237\u4E0D\u5B58\u5728
|
||||
user.username.exists=\u7528\u6237\u540D\u5DF2\u5B58\u5728
|
||||
user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728
|
||||
@ -1,12 +0,0 @@
|
||||
# 中文
|
||||
response.success=操作成功
|
||||
response.error=系统错误
|
||||
response.invalid.param=无效的参数
|
||||
response.unauthorized=未授权
|
||||
response.forbidden=禁止访问
|
||||
response.not.found=资源未找到
|
||||
response.conflict=资源冲突
|
||||
|
||||
user.not.found=用户不存在
|
||||
user.username.exists=用户名已存在
|
||||
user.email.exists=邮箱已存在
|
||||
12
backend/src/main/resources/messages_zh_CN.properties
Normal file
12
backend/src/main/resources/messages_zh_CN.properties
Normal file
@ -0,0 +1,12 @@
|
||||
# \u4E2D\u6587
|
||||
response.success=\u64CD\u4F5C\u6210\u529F
|
||||
response.error=\u7CFB\u7EDF\u9519\u8BEF
|
||||
response.invalid.param=\u65E0\u6548\u7684\u53C2\u6570
|
||||
response.unauthorized=\u672A\u6388\u6743
|
||||
response.forbidden=\u7981\u6B62\u8BBF\u95EE
|
||||
response.not.found=\u8D44\u6E90\u672A\u627E\u5230
|
||||
response.conflict=\u8D44\u6E90\u51B2\u7A81
|
||||
|
||||
user.not.found=\u7528\u6237\u4E0D\u5B58\u5728
|
||||
user.username.exists=\u7528\u6237\u540D\u5DF2\u5B58\u5728
|
||||
user.email.exists=\u90AE\u7BB1\u5DF2\u5B58\u5728
|
||||
@ -1,13 +0,0 @@
|
||||
package com.qqchen.deploy.common;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class BackendApplicationTests {
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user