可直接运行,修改了实体类的关系。
This commit is contained in:
parent
0537a5d8e4
commit
94aeb16a61
127
backend/README.md
Normal file
127
backend/README.md
Normal file
@ -0,0 +1,127 @@
|
||||
`
|
||||
分层结构从上到下:
|
||||
`
|
||||
```
|
||||
Controller (表现层)
|
||||
↓
|
||||
Service (业务层)
|
||||
↓
|
||||
Repository (数据访问层)
|
||||
```
|
||||
`
|
||||
对于外部集成:
|
||||
`
|
||||
```
|
||||
Controller
|
||||
↓
|
||||
Service ←→ Integration Service (集成层)
|
||||
↓
|
||||
Repository
|
||||
```
|
||||
|
||||
```
|
||||
GET /api/users - 查询所有用户
|
||||
GET /api/users/list?enabled=true - 查询所有启用的用户
|
||||
GET /api/users/page?pageNum=1&pageSize=10 - 分页查询用户
|
||||
```
|
||||
|
||||
`查询日期示例`
|
||||
```
|
||||
UserQuery query = new UserQuery();
|
||||
query.setCreateTimeRange(
|
||||
LocalDateTime.now().minusDays(7), // 一周内
|
||||
LocalDateTime.now()
|
||||
);
|
||||
query.setEnabled(true);
|
||||
query.setCreateBy("admin");
|
||||
|
||||
|
||||
@QueryField(type = QueryType.IN)
|
||||
private String status; // 可以传入 "ACTIVE,PENDING,CLOSED"
|
||||
|
||||
```
|
||||
```
|
||||
QueryDSL使用方法
|
||||
@Service
|
||||
@Transactional
|
||||
public class UserServiceImpl extends BaseServiceImpl<User, Long> implements UserService {
|
||||
|
||||
private final UserRoleRepository userRoleRepository;
|
||||
private final QUserRole qUserRole = QUserRole.userRole;
|
||||
|
||||
public UserServiceImpl(UserRepository userRepository, UserRoleRepository userRoleRepository) {
|
||||
super(userRepository);
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
}
|
||||
|
||||
public Set<UserRole> getUserRoles(Long userId) {
|
||||
// 使用QueryDSL构建查询条件
|
||||
Predicate predicate = qUserRole.user.id.eq(userId);
|
||||
return StreamSupport.stream(
|
||||
userRoleRepository.findAll(predicate).spliterator(),
|
||||
false
|
||||
).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public void assignRole(Long userId, Long roleId) {
|
||||
User user = findById(userId);
|
||||
Role role = roleRepository.findById(roleId)
|
||||
.orElseThrow(() -> new RuntimeException("Role not found"));
|
||||
|
||||
// 检查是否已存在
|
||||
Predicate predicate = qUserRole.user.id.eq(userId)
|
||||
.and(qUserRole.role.id.eq(roleId));
|
||||
|
||||
if (!userRoleRepository.exists(predicate)) {
|
||||
UserRole userRole = new UserRole(user, role);
|
||||
userRoleRepository.save(userRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
-- 插入正常用户数据
|
||||
INSERT INTO sys_user (
|
||||
username, password, nickname, email, phone,
|
||||
enabled, deleted, dept_id, dept_name,
|
||||
create_by, create_time, update_by, update_time, version
|
||||
) VALUES
|
||||
-- 管理员用户
|
||||
('admin', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '系统管理员', 'admin@example.com', '13800138000',
|
||||
true, false, 1, '技术部',
|
||||
'system', '2024-01-01 09:00:00', null, null, 0),
|
||||
|
||||
-- 普通用户
|
||||
('user01', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '张三', 'zhangsan@example.com', '13800138001',
|
||||
true, false, 1, '技术部',
|
||||
'admin', '2024-01-02 10:00:00', null, null, 0),
|
||||
|
||||
('user02', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '李四', 'lisi@example.com', '13800138002',
|
||||
true, false, 2, '市场部',
|
||||
'admin', '2024-01-03 11:00:00', 'admin', '2024-01-04 15:00:00', 1),
|
||||
|
||||
-- 已禁用的用户
|
||||
('disabled_user', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '王五', 'wangwu@example.com', '13800138003',
|
||||
false, false, 2, '市场部',
|
||||
'admin', '2024-01-05 14:00:00', 'admin', '2024-01-06 16:00:00', 1),
|
||||
|
||||
-- 已删除的用户
|
||||
('deleted_user', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '赵六', 'zhaoliu@example.com', '13800138004',
|
||||
true, true, 3, '财务部',
|
||||
'admin', '2024-01-07 10:00:00', 'admin', '2024-01-08 09:00:00', 2),
|
||||
|
||||
-- 最近创建的用户
|
||||
('new_user01', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '小明', 'xiaoming@example.com', '13800138005',
|
||||
true, false, 1, '技术部',
|
||||
'admin', '2024-03-01 09:00:00', null, null, 0),
|
||||
|
||||
('new_user02', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '小红', 'xiaohong@example.com', '13800138006',
|
||||
true, false, 2, '市场部',
|
||||
'admin', '2024-03-02 10:00:00', null, null, 0),
|
||||
|
||||
-- 多次更新的用户
|
||||
('updated_user', '$2a$10$mW/yJPHjyueQ1g26YxiZNOtr6bKVF4P/w/VHLVHHhxslY.YlXhbcm', '小张', 'xiaozhang@example.com', '13800138007',
|
||||
true, false, 3, '财务部',
|
||||
'admin', '2024-02-01 09:00:00', 'admin', '2024-03-01 15:00:00', 5);
|
||||
```
|
||||
@ -18,12 +18,26 @@
|
||||
<java.version>21</java.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<spring-cloud.version>2023.0.0</spring-cloud.version>
|
||||
<mapstruct.version>1.5.5.Final</mapstruct.version>
|
||||
<querydsl.version>5.0.0</querydsl.version>
|
||||
<lombok.version>1.18.30</lombok.version>
|
||||
<spring-security.version>6.2.0</spring-security.version>
|
||||
<jjwt.version>0.12.3</jjwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-dependencies</artifactId>
|
||||
<version>${spring-cloud.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Boot -->
|
||||
<dependency>
|
||||
@ -101,6 +115,31 @@
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenFeign -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-impl</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-jackson</artifactId>
|
||||
<version>${jjwt.version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
`查询日期示例`
|
||||
```
|
||||
UserQuery query = new UserQuery();
|
||||
query.setCreateTimeRange(
|
||||
LocalDateTime.now().minusDays(7), // 一周内
|
||||
LocalDateTime.now()
|
||||
);
|
||||
query.setEnabled(true);
|
||||
query.setCreateBy("admin");
|
||||
|
||||
|
||||
@QueryField(type = QueryType.IN)
|
||||
private String status; // 可以传入 "ACTIVE,PENDING,CLOSED"
|
||||
|
||||
```
|
||||
@ -2,9 +2,11 @@ package com.qqchen.deploy.backend;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableFeignClients
|
||||
public class BackendApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@ -9,7 +9,7 @@ import com.qqchen.deploy.backend.dto.query.UserQuery;
|
||||
import com.qqchen.deploy.backend.dto.request.UserRequest;
|
||||
import com.qqchen.deploy.backend.dto.response.UserResponse;
|
||||
import com.qqchen.deploy.backend.dto.request.UserRegisterRequest;
|
||||
import com.qqchen.deploy.backend.service.UserService;
|
||||
import com.qqchen.deploy.backend.service.IUserService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -22,11 +22,11 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/api/v1/users")
|
||||
public class UserApiController extends BaseController<User, Long, UserQuery, UserRequest, UserResponse> {
|
||||
|
||||
protected final UserService userService;
|
||||
protected final IUserService userService;
|
||||
|
||||
public UserApiController(UserService userService, UserConverter converter) {
|
||||
public UserApiController(IUserService userService, UserConverter converter) {
|
||||
super(userService, converter);
|
||||
this.userService = userService;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
|
||||
@ -10,9 +10,8 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import java.util.Optional;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaAuditing
|
||||
public class JpaConfig {
|
||||
|
||||
@EnableJpaAuditing(auditorAwareRef = "auditorProvider")
|
||||
public class JpaAuditingConfig {
|
||||
@Bean
|
||||
public AuditorAware<String> auditorProvider() {
|
||||
return () -> {
|
||||
@ -2,11 +2,11 @@ package com.qqchen.deploy.backend.common.controller;
|
||||
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import com.qqchen.deploy.backend.common.converter.BaseConverter;
|
||||
import com.qqchen.deploy.backend.common.dto.BaseResponse;
|
||||
import com.qqchen.deploy.backend.common.query.BaseQuery;
|
||||
import com.qqchen.deploy.backend.common.dto.BaseRequest;
|
||||
import com.qqchen.deploy.backend.common.api.Response;
|
||||
import com.qqchen.deploy.backend.common.service.BaseService;
|
||||
import jakarta.annotation.Resource;
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -16,23 +16,25 @@ import java.util.List;
|
||||
/**
|
||||
* 通用REST控制器
|
||||
*/
|
||||
public abstract class BaseController<T extends Entity<ID>, ID extends Serializable, Q extends BaseQuery, R extends BaseRequest, V> {
|
||||
public abstract class BaseController<T extends Entity<ID>, ID extends Serializable, Q extends BaseQuery, REQ extends BaseRequest, RESP extends BaseResponse> {
|
||||
|
||||
@Resource
|
||||
protected BaseService<T, ID> service;
|
||||
protected final IBaseService<T, ID> service;
|
||||
protected final BaseConverter<T, REQ, RESP> converter;
|
||||
|
||||
@Resource
|
||||
protected BaseConverter<T, R, V> converter;
|
||||
protected BaseController(IBaseService<T, ID> service, BaseConverter<T, REQ, RESP> converter) {
|
||||
this.service = service;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Response<V> create(@RequestBody R request) {
|
||||
public Response<RESP> create(@RequestBody REQ request) {
|
||||
T entity = converter.toEntity(request);
|
||||
T savedEntity = service.create(entity);
|
||||
return Response.success(converter.toResponse(savedEntity));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public Response<V> update(@PathVariable ID id, @RequestBody R request) {
|
||||
public Response<RESP> update(@PathVariable ID id, @RequestBody REQ request) {
|
||||
T entity = service.findById(id);
|
||||
converter.updateEntity(entity, request);
|
||||
T updatedEntity = service.update(entity);
|
||||
@ -46,20 +48,26 @@ public abstract class BaseController<T extends Entity<ID>, ID extends Serializab
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Response<V> findById(@PathVariable ID id) {
|
||||
public Response<RESP> findById(@PathVariable ID id) {
|
||||
T entity = service.findById(id);
|
||||
return Response.success(converter.toResponse(entity));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public Response<List<V>> findAll() {
|
||||
public Response<List<RESP>> findAll() {
|
||||
List<T> entities = service.findAll();
|
||||
return Response.success(converter.toResponseList(entities));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
public Response<Page<V>> page(Q query) {
|
||||
public Response<Page<RESP>> page(Q query) {
|
||||
Page<T> page = service.page(query);
|
||||
return Response.success(page.map(entity -> converter.toResponse(entity)));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
public Response<List<RESP>> findAll(Q query) {
|
||||
List<T> entities = service.findAll(query);
|
||||
return Response.success(converter.toResponseList(entities));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.qqchen.deploy.backend.common.integration.dto;
|
||||
|
||||
public interface ThirdPartyDTO {
|
||||
// 标记接口,表明这是第三方系统的数据结构
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
package com.qqchen.deploy.backend.common.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@NoRepositoryBean
|
||||
public interface BaseRepository<T extends Entity<ID>, ID extends Serializable> extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T> {
|
||||
|
||||
@Override
|
||||
@Query("select e from #{#entityName} e where e.deleted = false")
|
||||
List<T> findAll();
|
||||
|
||||
@Override
|
||||
@Query("select e from #{#entityName} e where e.id = ?1 and e.deleted = false")
|
||||
Optional<T> findById(ID id);
|
||||
|
||||
@Override
|
||||
default void delete(T entity) {
|
||||
entity.setDeleted(true);
|
||||
save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void deleteById(ID id) {
|
||||
findById(id).ifPresent(this::delete);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,129 @@
|
||||
package com.qqchen.deploy.backend.common.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@NoRepositoryBean
|
||||
public interface IBaseRepository<T extends Entity<ID>, ID extends Serializable>
|
||||
extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T> {
|
||||
// extends JpaRepository<T, ID>, QuerydslPredicateExecutor<T>, JpaSpecificationExecutor<T> {
|
||||
|
||||
|
||||
@Override
|
||||
@Query("select e from #{#entityName} e where e.deleted = false")
|
||||
List<T> findAll();
|
||||
|
||||
@Override
|
||||
@Query("select e from #{#entityName} e where e.id = ?1 and e.deleted = false")
|
||||
Optional<T> findById(ID id);
|
||||
|
||||
@Override
|
||||
default void delete(T entity) {
|
||||
entity.setDeleted(true);
|
||||
save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void deleteById(ID id) {
|
||||
findById(id).ifPresent(this::delete);
|
||||
}
|
||||
|
||||
// 批量操作
|
||||
@Modifying
|
||||
@Query("update #{#entityName} e set e.deleted = true where e.id in ?1")
|
||||
void logicDeleteByIds(Collection<ID> ids);
|
||||
|
||||
// @Modifying
|
||||
// @Query("update #{#entityName} e set e.enabled = ?2 where e.id in ?1")
|
||||
// void updateEnabledByIds(Collection<ID> ids, boolean enabled);
|
||||
|
||||
// 快速查询方法
|
||||
Optional<T> findByIdAndDeletedFalse(ID id);
|
||||
|
||||
List<T> findByIdInAndDeletedFalse(Collection<ID> ids);
|
||||
|
||||
boolean existsByIdAndDeletedFalse(ID id);
|
||||
|
||||
// 自定义查询
|
||||
@Query("select e from #{#entityName} e where e.deleted = false and " +
|
||||
"(?1 is null or e.createTime >= ?1) and " +
|
||||
"(?2 is null or e.createTime <= ?2)")
|
||||
List<T> findByCreateTimeBetween(LocalDateTime start, LocalDateTime end);
|
||||
|
||||
@Query("select e from #{#entityName} e where e.deleted = false and " +
|
||||
"(?1 is null or e.createBy = ?1)")
|
||||
List<T> findByCreateBy(String creator);
|
||||
|
||||
// 统计方法
|
||||
@Query("select count(e) from #{#entityName} e where e.deleted = false")
|
||||
long countNonDeleted();
|
||||
|
||||
// @Query("select count(e) from #{#entityName} e where e.deleted = false and e.enabled = ?1")
|
||||
// long countByEnabled(boolean enabled);
|
||||
|
||||
// 高级查询
|
||||
@Query("select e from #{#entityName} e where e.deleted = false " +
|
||||
"order by e.createTime desc")
|
||||
List<T> findLatest(Pageable pageable);
|
||||
|
||||
@Query("select distinct e.createBy from #{#entityName} e where e.deleted = false")
|
||||
List<String> findAllCreators();
|
||||
|
||||
// 批量更新
|
||||
@Modifying
|
||||
@Query("update #{#entityName} e set e.updateBy = ?2, e.updateTime = ?3 where e.id in ?1")
|
||||
void updateAuditInfo(Collection<ID> ids, String updateBy, LocalDateTime updateTime);
|
||||
|
||||
/**
|
||||
* 根据条件查询并排序
|
||||
*/
|
||||
default List<T> findAllByCondition(com.querydsl.core.types.Predicate predicate, Sort sort) {
|
||||
Iterable<T> iterable = findAll(predicate, sort);
|
||||
List<T> result = new ArrayList<>();
|
||||
iterable.forEach(result::add);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 批量保存并返回保存的实体
|
||||
default List<T> saveAllAndReturn(Iterable<T> entities) {
|
||||
return saveAll(entities);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件查询并排序
|
||||
* 使用QueryDSL的Predicate进行条件查询
|
||||
*/
|
||||
@Override
|
||||
Iterable<T> findAll(com.querydsl.core.types.Predicate predicate);
|
||||
|
||||
@Override
|
||||
Iterable<T> findAll(com.querydsl.core.types.Predicate predicate, Sort sort);
|
||||
|
||||
/**
|
||||
* 提供一个默认的转换方法
|
||||
*/
|
||||
default List<T> findAllAndConvert(com.querydsl.core.types.Predicate predicate, Sort sort) {
|
||||
Iterable<T> iterable = findAll(predicate, sort);
|
||||
List<T> result = new ArrayList<>();
|
||||
iterable.forEach(result::add);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,17 @@
|
||||
package com.qqchen.deploy.backend.common.config;
|
||||
package com.qqchen.deploy.backend.common.security.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
@ -69,4 +73,14 @@ public class SecurityConfig {
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
|
||||
return config.getAuthenticationManager();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.qqchen.deploy.backend.common.security.filter;
|
||||
|
||||
import com.qqchen.deploy.backend.common.security.util.JwtTokenUtil;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private final JwtTokenUtil jwtTokenUtil;
|
||||
|
||||
private final UserDetailsService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
String authHeader = request.getHeader("Authorization");
|
||||
String token = null;
|
||||
String username = null;
|
||||
|
||||
if (authHeader != null && authHeader.startsWith("Bearer ")) {
|
||||
token = authHeader.substring(7);
|
||||
username = jwtTokenUtil.getUsernameFromToken(token);
|
||||
}
|
||||
|
||||
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
||||
|
||||
if (jwtTokenUtil.validateToken(token, userDetails)) {
|
||||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
|
||||
userDetails, null, userDetails.getAuthorities());
|
||||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Cannot set user authentication", e);
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
package com.qqchen.deploy.backend.common.security.util;
|
||||
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class JwtTokenUtil {
|
||||
|
||||
@Value("${jwt.secret}")
|
||||
private String secret;
|
||||
|
||||
@Value("${jwt.expiration}")
|
||||
private Long expiration;
|
||||
|
||||
private SecretKey key;
|
||||
|
||||
private SecretKey getKey() {
|
||||
if (key == null) {
|
||||
// 确保密钥长度至少为 256 位
|
||||
byte[] keyBytes = new byte[32];
|
||||
byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8);
|
||||
System.arraycopy(secretBytes, 0, keyBytes, 0, Math.min(secretBytes.length, keyBytes.length));
|
||||
key = Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
public String generateToken(UserDetails userDetails) {
|
||||
Date now = new Date();
|
||||
Date expiryDate = new Date(now.getTime() + expiration * 1000);
|
||||
|
||||
return Jwts.builder()
|
||||
.subject(userDetails.getUsername())
|
||||
.issuedAt(now)
|
||||
.expiration(expiryDate)
|
||||
.signWith(getKey())
|
||||
.compact();
|
||||
}
|
||||
|
||||
public String getUsernameFromToken(String token) {
|
||||
try {
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(getKey())
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.getPayload();
|
||||
return claims.getSubject();
|
||||
} catch (Exception e) {
|
||||
log.error("Error getting username from token", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validateToken(String token, UserDetails userDetails) {
|
||||
try {
|
||||
String username = getUsernameFromToken(token);
|
||||
Claims claims = Jwts.parser()
|
||||
.verifyWith(getKey())
|
||||
.build()
|
||||
.parseSignedClaims(token)
|
||||
.getPayload();
|
||||
|
||||
boolean isTokenExpired = claims.getExpiration().before(new Date());
|
||||
|
||||
return (username.equals(userDetails.getUsername()) && !isTokenExpired);
|
||||
} catch (Exception e) {
|
||||
log.error("Error validating token", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,7 +10,7 @@ import java.util.List;
|
||||
/**
|
||||
* 通用服务接口
|
||||
*/
|
||||
public interface BaseService<T extends Entity<ID>, ID extends Serializable> {
|
||||
public interface IBaseService<T extends Entity<ID>, ID extends Serializable> {
|
||||
T create(T entity);
|
||||
|
||||
T update(T entity);
|
||||
@ -21,5 +21,7 @@ public interface BaseService<T extends Entity<ID>, ID extends Serializable> {
|
||||
|
||||
List<T> findAll();
|
||||
|
||||
List<T> findAll(BaseQuery query);
|
||||
|
||||
Page<T> page(BaseQuery query);
|
||||
}
|
||||
@ -2,6 +2,7 @@ package com.qqchen.deploy.backend.common.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@ -11,9 +12,9 @@ import com.qqchen.deploy.backend.common.enums.QueryType;
|
||||
import com.qqchen.deploy.backend.common.query.BaseQuery;
|
||||
import com.qqchen.deploy.backend.common.query.DateRange;
|
||||
import com.qqchen.deploy.backend.common.query.Range;
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.common.annotation.QueryField;
|
||||
import com.qqchen.deploy.backend.common.service.BaseService;
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.common.utils.EntityPathResolver;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.core.types.EntityPath;
|
||||
@ -29,17 +30,17 @@ import org.springframework.util.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@Transactional
|
||||
public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializable>
|
||||
implements BaseService<T, ID> {
|
||||
public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializable> implements IBaseService<T, ID> {
|
||||
|
||||
protected final BaseRepository<T, ID> repository;
|
||||
protected final IBaseRepository<T, ID> repository;
|
||||
|
||||
protected final EntityPath<T> entityPath;
|
||||
|
||||
protected BaseServiceImpl(BaseRepository<T, ID> repository) {
|
||||
protected BaseServiceImpl(IBaseRepository<T, ID> repository) {
|
||||
this.repository = repository;
|
||||
this.entityPath = getEntityPath();
|
||||
}
|
||||
@ -65,7 +66,6 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializa
|
||||
@Override
|
||||
public Page<T> page(BaseQuery query) {
|
||||
BooleanBuilder builder = new BooleanBuilder().and(Expressions.asBoolean(true).isTrue());
|
||||
|
||||
if (query != null) {
|
||||
buildQueryPredicate(query, builder);
|
||||
}
|
||||
@ -74,7 +74,6 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializa
|
||||
if (genericTypes != null && genericTypes.length > 0) {
|
||||
Class<T> entityClass = (Class<T>) genericTypes[0];
|
||||
LogicDelete softDelete = entityClass.getAnnotation(LogicDelete.class);
|
||||
|
||||
if (softDelete != null && softDelete.value()) {
|
||||
Path<?> deletedPath = EntityPathResolver.getPath(entityPath, "deleted");
|
||||
if (deletedPath instanceof BooleanPath) {
|
||||
@ -83,7 +82,6 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializa
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return repository.findAll(builder, createPageRequest(query));
|
||||
}
|
||||
|
||||
@ -284,4 +282,40 @@ public abstract class BaseServiceImpl<T extends Entity<ID>, ID extends Serializa
|
||||
public List<T> findAll() {
|
||||
return repository.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> findAll(BaseQuery query) {
|
||||
BooleanBuilder builder = new BooleanBuilder().and(Expressions.asBoolean(true).isTrue());
|
||||
|
||||
// 添加查询条件
|
||||
if (query != null) {
|
||||
buildQueryPredicate(query, builder);
|
||||
}
|
||||
|
||||
// 处理软删除
|
||||
if (query == null || query.getDeleted() == null) {
|
||||
Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(getClass(), BaseServiceImpl.class);
|
||||
if (genericTypes != null && genericTypes.length > 0) {
|
||||
Class<T> entityClass = (Class<T>) genericTypes[0];
|
||||
LogicDelete softDelete = entityClass.getAnnotation(LogicDelete.class);
|
||||
if (softDelete != null && softDelete.value()) {
|
||||
Path<?> deletedPath = EntityPathResolver.getPath(entityPath, "deleted");
|
||||
if (deletedPath instanceof BooleanPath) {
|
||||
builder.and(((BooleanPath) deletedPath).eq(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取排序信息
|
||||
Sort sort = query != null && StringUtils.hasText(query.getSortField()) ?
|
||||
Sort.by(Sort.Direction.fromString(query.getSortOrder()), query.getSortField()) :
|
||||
Sort.by(Sort.Direction.DESC, "createTime");
|
||||
|
||||
// 执行查询并返回结果
|
||||
Iterable<T> iterable = repository.findAll(builder, sort);
|
||||
List<T> result = new ArrayList<>();
|
||||
iterable.forEach(result::add);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ package com.qqchen.deploy.backend.controller;
|
||||
import com.qqchen.deploy.backend.api.UserApiController;
|
||||
import com.qqchen.deploy.backend.common.api.Response;
|
||||
import com.qqchen.deploy.backend.converter.UserConverter;
|
||||
import com.qqchen.deploy.backend.service.UserService;
|
||||
import com.qqchen.deploy.backend.service.IUserService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
@ -13,8 +13,11 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequestMapping("/mgmt/users")
|
||||
public class UserController extends UserApiController {
|
||||
|
||||
public UserController(UserService userService, UserConverter converter) {
|
||||
protected final IUserService userService;
|
||||
|
||||
public UserController(IUserService userService, UserConverter converter) {
|
||||
super(userService, converter);
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@GetMapping("/check-username")
|
||||
|
||||
@ -1,16 +1,25 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Transient;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ -46,4 +55,10 @@ public class Department extends Entity<Long> {
|
||||
|
||||
@Transient // 不映射到数据库
|
||||
private List<Department> children = new ArrayList<>();
|
||||
|
||||
// 修改关联关系,通过UserDepartment关联
|
||||
@OneToMany(mappedBy = "department")
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Set<UserDepartment> userDepartments = new HashSet<>();
|
||||
}
|
||||
@ -7,6 +7,7 @@ import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ -40,4 +41,6 @@ public class Menu extends Entity<Long> {
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
|
||||
// List<RoleMenu> roleMenu;
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
@ -9,8 +10,11 @@ import jakarta.persistence.Table;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@Data
|
||||
@ -33,6 +37,8 @@ public class Role extends Entity<Long> {
|
||||
@Column(nullable = false)
|
||||
private Integer sort = 0;
|
||||
|
||||
@OneToMany(mappedBy = "role", cascade = CascadeType.ALL) // 指向 UserRole 的 role 属性
|
||||
private List<UserRole> userRoles;
|
||||
@OneToMany(mappedBy = "role", cascade = CascadeType.ALL)
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Set<UserRole> userRoles = new HashSet<>();
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.AggregateRoot;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
@ -7,9 +8,11 @@ import com.qqchen.deploy.backend.event.UserRoleChangedEvent;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -23,32 +26,35 @@ import java.util.stream.Collectors;
|
||||
@Table(name = "sys_user")
|
||||
@LogicDelete
|
||||
public class User extends Entity<Long> {
|
||||
|
||||
|
||||
@Column(unique = true, nullable = false)
|
||||
private String username;
|
||||
|
||||
|
||||
@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)
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Set<UserRole> userRoles = new HashSet<>();
|
||||
|
||||
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL) // 指向 UserRole 的 user 属性
|
||||
private Set<UserRole> userRoles;
|
||||
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Set<UserDepartment> userDepartments = new HashSet<>();
|
||||
|
||||
// public void addRole(Role role) {
|
||||
// UserRole userRole = new UserRole(this, role);
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_user_department")
|
||||
@LogicDelete
|
||||
public class UserDepartment extends Entity<Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id", unique = true)
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private User user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "department_id")
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Department department;
|
||||
|
||||
protected UserDepartment() {
|
||||
// JPA需要无参构造函数
|
||||
}
|
||||
|
||||
public UserDepartment(User user, Department department) {
|
||||
this.user = user;
|
||||
this.department = department;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package com.qqchen.deploy.backend.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.qqchen.deploy.backend.common.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.common.domain.Entity;
|
||||
import jakarta.persistence.Column;
|
||||
@ -11,6 +12,7 @@ import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ -19,12 +21,16 @@ import lombok.EqualsAndHashCode;
|
||||
@LogicDelete
|
||||
public class UserRole extends Entity<Long> {
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY) // 添加懒加载
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id")
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private User user;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY) // 添加懒加载
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "role_id")
|
||||
@JsonIgnore
|
||||
@ToString.Exclude
|
||||
private Role role;
|
||||
|
||||
// 添加构造方法
|
||||
@ -50,4 +56,6 @@ public class UserRole extends Entity<Long> {
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package com.qqchen.deploy.backend.integration;
|
||||
|
||||
import com.qqchen.deploy.backend.integration.client.IJenkinsClient;
|
||||
import com.qqchen.deploy.backend.integration.dto.JenkinsBuildDTO;
|
||||
import com.qqchen.deploy.backend.integration.dto.JenkinsConnectionDTO;
|
||||
import feign.FeignException;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JenkinsService {
|
||||
|
||||
// @Resource
|
||||
// private final IJenkinsClient jenkinsClient;
|
||||
//
|
||||
// public boolean testConnection(JenkinsConnectionDTO config) {
|
||||
// try {
|
||||
// String authHeader = createAuthHeader(config.getUsername(), config.getPassword());
|
||||
// jenkinsClient.testConnection(authHeader);
|
||||
// log.info("Jenkins连接测试成功");
|
||||
// return true;
|
||||
// } catch (FeignException.Unauthorized e) {
|
||||
// log.error("Jenkins连接测试失败: 认证失败");
|
||||
// return false;
|
||||
// } catch (Exception e) {
|
||||
// log.error("Jenkins连接测试失败: {}", e.getMessage());
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public BuildInfo getBuildInfo(JenkinsConnectionDTO config, String jobName, Integer buildNumber) {
|
||||
// try {
|
||||
// String authHeader = createAuthHeader(config.getUsername(), config.getPassword());
|
||||
// JenkinsBuildDTO jenkinsBuild = jenkinsClient.getBuildInfo(authHeader, jobName, buildNumber);
|
||||
// return convertToBuildInfo(jenkinsBuild);
|
||||
// } catch (Exception e) {
|
||||
// log.error("获取Jenkins构建信息失败: {}", e.getMessage());
|
||||
// throw new RuntimeException("Failed to get build info", e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private String createAuthHeader(String username, String password) {
|
||||
// String auth = username + ":" + password;
|
||||
// return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
|
||||
// }
|
||||
//
|
||||
// private BuildInfo convertToBuildInfo(JenkinsBuildDTO dto) {
|
||||
// BuildInfo buildInfo = new BuildInfo();
|
||||
// buildInfo.setJobName(dto.getJobName());
|
||||
// buildInfo.setBuildNumber(dto.getBuildNumber());
|
||||
// buildInfo.setBuildUrl(dto.getUrl());
|
||||
// buildInfo.setBuildTime(LocalDateTime.ofInstant(
|
||||
// Instant.ofEpochMilli(dto.getTimestamp()),
|
||||
// ZoneId.systemDefault()
|
||||
// ));
|
||||
//
|
||||
// // 转换构建状态
|
||||
// buildInfo.setStatus(convertBuildStatus(dto.getResult(), dto.getStatus()));
|
||||
//
|
||||
// return buildInfo;
|
||||
// }
|
||||
//
|
||||
// private BuildInfo.BuildStatus convertBuildStatus(String result, String status) {
|
||||
// if ("IN_PROGRESS".equals(status)) {
|
||||
// return BuildInfo.BuildStatus.IN_PROGRESS;
|
||||
// }
|
||||
//
|
||||
// return switch (result) {
|
||||
// case "SUCCESS" -> BuildInfo.BuildStatus.SUCCESS;
|
||||
// case "FAILURE" -> BuildInfo.BuildStatus.FAILURE;
|
||||
// case "ABORTED" -> BuildInfo.BuildStatus.CANCELLED;
|
||||
// default -> throw new IllegalStateException("Unknown build status: " + result);
|
||||
// };
|
||||
// }
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package com.qqchen.deploy.backend.integration.client;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@FeignClient(name = "jenkins-service", url = "#{null}") // 动态URL
|
||||
public interface IJenkinsClient {
|
||||
|
||||
@GetMapping("/api/json")
|
||||
Map<String, Object> testConnection(
|
||||
@RequestHeader("Authorization") String authorization
|
||||
);
|
||||
|
||||
@PostMapping("/job/{jobName}/build")
|
||||
void triggerBuild(
|
||||
@RequestHeader("Authorization") String authorization,
|
||||
@PathVariable("jobName") String jobName
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.qqchen.deploy.backend.integration.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
@Data
|
||||
@Component
|
||||
public class JenkinsProperties {
|
||||
|
||||
private String url;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
|
||||
public String getBasicAuth() {
|
||||
String auth = username + ":" + password;
|
||||
return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
package com.qqchen.deploy.backend.integration.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class BuildInfo {
|
||||
private String jobName;
|
||||
|
||||
private Integer buildNumber;
|
||||
|
||||
private BuildStatus status;
|
||||
|
||||
private LocalDateTime buildTime;
|
||||
|
||||
private String buildUrl;
|
||||
|
||||
public enum BuildStatus {
|
||||
SUCCESS, FAILURE, IN_PROGRESS, CANCELLED
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.qqchen.deploy.backend.integration.dto;
|
||||
|
||||
import com.qqchen.deploy.backend.common.integration.dto.ThirdPartyDTO;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class JenkinsBuildDTO implements ThirdPartyDTO {
|
||||
|
||||
private String jobName;
|
||||
|
||||
private Integer buildNumber;
|
||||
|
||||
private String status;
|
||||
|
||||
private String result;
|
||||
|
||||
private Long timestamp;
|
||||
|
||||
private String url;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.qqchen.deploy.backend.integration.dto;
|
||||
|
||||
import com.qqchen.deploy.backend.common.integration.dto.ThirdPartyDTO;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class JenkinsConnectionDTO implements ThirdPartyDTO {
|
||||
|
||||
private String url;
|
||||
|
||||
private String username;
|
||||
|
||||
private String password;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
package com.qqchen.deploy.backend.integration.enums;
|
||||
|
||||
public enum JenkinsBuildStatus {
|
||||
SUCCESS, FAILURE, IN_PROGRESS, CANCELLED
|
||||
}
|
||||
@ -1,15 +1,14 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.Department;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface DepartmentRepository extends BaseRepository<Department, Long> {
|
||||
public interface IDepartmentRepository extends IBaseRepository<Department, Long> {
|
||||
|
||||
List<Department> findByParentIdAndDeletedFalseOrderBySort(Long parentId);
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsBuild;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface JenkinsBuildRepository extends BaseRepository<JenkinsBuild, Long> {
|
||||
public interface IJenkinsBuildRepository extends IBaseRepository<JenkinsBuild, Long> {
|
||||
List<JenkinsBuild> findByJobIdAndDeletedFalse(Long jobId);
|
||||
List<JenkinsBuild> findByJobIdAndBuildNumberAndDeletedFalse(Long jobId, Integer buildNumber);
|
||||
void deleteByJobIdAndDeletedFalse(Long jobId);
|
||||
@ -1,13 +1,13 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsConfig;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface JenkinsConfigRepository extends BaseRepository<JenkinsConfig, Long> {
|
||||
public interface IJenkinsConfigRepository extends IBaseRepository<JenkinsConfig, Long> {
|
||||
List<JenkinsConfig> findByDeletedFalseOrderBySort();
|
||||
boolean existsByNameAndDeletedFalse(String name);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsJob;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
@ -8,7 +8,7 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface JenkinsJobRepository extends BaseRepository<JenkinsJob, Long> {
|
||||
public interface IJenkinsJobRepository extends IBaseRepository<JenkinsJob, Long> {
|
||||
List<JenkinsJob> findByJenkinsIdAndDeletedFalse(Long jenkinsId);
|
||||
List<JenkinsJob> findByJenkinsIdAndJobNameAndDeletedFalse(Long jenkinsId, String jobName);
|
||||
void deleteByJenkinsIdAndDeletedFalse(Long jenkinsId);
|
||||
@ -1,12 +1,12 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsSyncHistory;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface JenkinsSyncHistoryRepository extends BaseRepository<JenkinsSyncHistory, Long> {
|
||||
public interface IJenkinsSyncHistoryRepository extends IBaseRepository<JenkinsSyncHistory, Long> {
|
||||
List<JenkinsSyncHistory> findTop50ByOrderByStartTimeDesc();
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsView;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface JenkinsViewRepository extends BaseRepository<JenkinsView, Long> {
|
||||
public interface IJenkinsViewRepository extends IBaseRepository<JenkinsView, Long> {
|
||||
List<JenkinsView> findByJenkinsIdAndDeletedFalse(Long jenkinsId);
|
||||
List<JenkinsView> findByJenkinsIdAndViewNameAndDeletedFalse(Long jenkinsId, String viewName);
|
||||
void deleteByJenkinsIdAndDeletedFalse(Long jenkinsId);
|
||||
@ -2,12 +2,11 @@ package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.Menu;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
@Repository
|
||||
public interface MenuRepository extends JpaRepository<Menu, Long> {
|
||||
public interface IMenuRepository extends JpaRepository<Menu, Long> {
|
||||
|
||||
List<Menu> findByDeletedFalseOrderBySort();
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RepositoryBranch;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Repository
|
||||
public interface RepositoryBranchRepository extends BaseRepository<RepositoryBranch, Long> {
|
||||
public interface IRepositoryBranchRepository extends IBaseRepository<RepositoryBranch, Long> {
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@ -1,14 +1,14 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RepositoryConfig;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RepositoryConfigRepository extends BaseRepository<RepositoryConfig, Long> {
|
||||
public interface IRepositoryConfigRepository extends IBaseRepository<RepositoryConfig, Long> {
|
||||
List<RepositoryConfig> findByDeletedFalseOrderBySort();
|
||||
boolean existsByNameAndDeletedFalse(String name);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RepositoryGroup;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@ -10,7 +10,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RepositoryGroupRepository extends BaseRepository<RepositoryGroup, Long> {
|
||||
public interface IRepositoryGroupRepository extends IBaseRepository<RepositoryGroup, Long> {
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@ -1,6 +1,6 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RepositoryProject;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@ -10,7 +10,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RepositoryProjectRepository extends BaseRepository<RepositoryProject, Long> {
|
||||
public interface IRepositoryProjectRepository extends IBaseRepository<RepositoryProject, Long> {
|
||||
|
||||
@Modifying
|
||||
@Transactional
|
||||
@ -1,13 +1,13 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RepositorySyncHistory;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RepositorySyncHistoryRepository extends BaseRepository<RepositorySyncHistory, Long> {
|
||||
public interface IRepositorySyncHistoryRepository extends IBaseRepository<RepositorySyncHistory, Long> {
|
||||
List<RepositorySyncHistory> findTop50ByOrderByStartTimeDesc();
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.RoleMenu;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RoleMenuRepository extends BaseRepository<RoleMenu, Long> {
|
||||
public interface IRoleMenuRepository extends IBaseRepository<RoleMenu, Long> {
|
||||
|
||||
List<RoleMenu> findByRoleId(Long roleId);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.Role;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface RoleRepository extends BaseRepository<Role, Long> {
|
||||
public interface IRoleRepository extends IBaseRepository<Role, Long> {
|
||||
|
||||
List<Role> findByDeletedFalseOrderBySort();
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.Tenant;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface TenantRepository extends BaseRepository<Tenant, Long> {
|
||||
public interface ITenantRepository extends IBaseRepository<Tenant, Long> {
|
||||
|
||||
List<Tenant> findByDeletedFalseOrderById();
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.User;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@ -9,7 +9,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends BaseRepository<User, Long> {
|
||||
public interface IUserRepository extends IBaseRepository<User, Long> {
|
||||
|
||||
Optional<User> findByUsernameAndDeletedFalse(String username);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.qqchen.deploy.backend.repository;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.repository.BaseRepository;
|
||||
import com.qqchen.deploy.backend.common.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.entity.UserRole;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
@ -11,7 +11,7 @@ import org.springframework.stereotype.Repository;
|
||||
import java.util.Set;
|
||||
|
||||
@Repository
|
||||
public interface UserRoleRepository extends BaseRepository<UserRole, Long> {
|
||||
public interface IUserRoleRepository extends IBaseRepository<UserRole, Long> {
|
||||
|
||||
@Query("SELECT ur FROM UserRole ur WHERE ur.user.id = :userId")
|
||||
Set<UserRole> findByUserId(@Param("userId") Long userId);
|
||||
@ -0,0 +1,18 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.Department;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IDepartmentService extends IBaseService<Department, Long> {
|
||||
|
||||
List<Department> getTree();
|
||||
|
||||
void validateCode(String code);
|
||||
|
||||
void validateName(String name);
|
||||
|
||||
Integer getNextSort(Long parentId);
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.JenkinsConfig;
|
||||
|
||||
public interface IJenkinsService extends IBaseService<JenkinsConfig, Long> {
|
||||
// boolean testConnection(JenkinsTestConnectionDTO dto);
|
||||
|
||||
Long asyncSyncAll(Long jenkinsId);
|
||||
|
||||
Long asyncSyncView(Long jenkinsId);
|
||||
|
||||
Long asyncSyncJob(Long jenkinsId);
|
||||
|
||||
Long asyncSyncBuild(Long jenkinsId);
|
||||
|
||||
// List<JenkinsSyncHistoryDTO> getSyncHistories();
|
||||
|
||||
// List<ViewResponse> getViews(Long jenkinsId);
|
||||
|
||||
// List<JobResponse> getJobs(Long jenkinsId);
|
||||
|
||||
// List<BuildResponse> getBuilds(Long jenkinsId, Long jobId);
|
||||
|
||||
// List<JobResponse> getJobsByView(Long jenkinsId, String viewName);
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.Menu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IMenuService extends IBaseService<Menu, Long> {
|
||||
|
||||
// List<MenuDTO> getMenuTree();
|
||||
|
||||
// List<MenuDTO> getMenuTreeWithoutButtons();
|
||||
|
||||
// List<MenuDTO> getUserMenus(Long userId);
|
||||
|
||||
List<Menu> getMenusByRoleId(Long roleId);
|
||||
|
||||
void saveRoleMenus(Long roleId, List<Long> menuIds);
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.RepositoryConfig;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IRepositoryService extends IBaseService<RepositoryConfig, Long> {
|
||||
|
||||
// 仓库配置管理
|
||||
List<RepositoryConfig> listConfigs();
|
||||
RepositoryConfig createConfig(RepositoryConfig config);
|
||||
RepositoryConfig updateConfig(Long id, RepositoryConfig config);
|
||||
void deleteConfig(Long id);
|
||||
|
||||
// 测试连接
|
||||
boolean testConnection(RepositoryConfig config);
|
||||
// boolean testConnection(TestConnectionDTO dto);
|
||||
|
||||
// 同步操作
|
||||
void syncAll(Long repositoryId);
|
||||
void syncGroups(Long repositoryId);
|
||||
void syncProjects(Long repositoryId, Long groupId);
|
||||
void syncBranches(Long repositoryId, Long projectId);
|
||||
|
||||
/**
|
||||
* 异步同步仓库数据
|
||||
* @param repositoryId 仓库ID
|
||||
* @return 同步历史ID
|
||||
*/
|
||||
Long asyncSyncAll(Long repositoryId);
|
||||
|
||||
/**
|
||||
* 获取同步状态
|
||||
* @param historyId 同步历史ID
|
||||
* @return 仓库同步状态
|
||||
*/
|
||||
// RepositorySyncStatusDTO getSyncStatus(Long historyId);
|
||||
|
||||
/**
|
||||
* 获取正在同步的仓库列表
|
||||
* @return 正在同步的仓库信息列表
|
||||
*/
|
||||
// List<RunningSyncDTO> getRunningSyncs();
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.Role;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IRoleService extends IBaseService<Role, Long> {
|
||||
|
||||
void validateCode(String code);
|
||||
|
||||
void validateName(String name);
|
||||
|
||||
List<Long> getRoleMenuIds(Long roleId);
|
||||
|
||||
void updateRoleMenus(Long roleId, List<Long> menuIds);
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.Tenant;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ITenantService extends IBaseService<Tenant, Long> {
|
||||
|
||||
void validateCode(String code);
|
||||
|
||||
void validateName(String name);
|
||||
|
||||
List<Tenant> findAllEnabled();
|
||||
|
||||
boolean existsByCode(String code);
|
||||
|
||||
boolean existsByName(String name);
|
||||
|
||||
// List<Tenant> findAll(TenantQuery query);
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
package com.qqchen.deploy.backend.service;
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.BaseService;
|
||||
import com.qqchen.deploy.backend.common.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.entity.User;
|
||||
|
||||
public interface UserService extends BaseService<User, Long> {
|
||||
public interface IUserService extends IBaseService<User, Long> {
|
||||
User register(User user);
|
||||
User findByUsername(String username);
|
||||
boolean checkUsernameExists(String username);
|
||||
@ -0,0 +1,105 @@
|
||||
package com.qqchen.deploy.backend.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl;
|
||||
import com.qqchen.deploy.backend.entity.Department;
|
||||
import com.qqchen.deploy.backend.repository.IDepartmentRepository;
|
||||
import com.qqchen.deploy.backend.service.IDepartmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class DepartmentServiceImpl extends BaseServiceImpl<Department, Long> implements IDepartmentService {
|
||||
|
||||
private final IDepartmentRepository repository;
|
||||
|
||||
@Autowired
|
||||
public DepartmentServiceImpl(IDepartmentRepository repository) {
|
||||
super(repository);
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Department create(Department entity) {
|
||||
validateCode(entity.getCode());
|
||||
validateName(entity.getName());
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
public Department update(Long id, Department entity) {
|
||||
Department existing = repository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("部门不存在"));
|
||||
|
||||
entity.setVersion(existing.getVersion());
|
||||
entity.setId(id);
|
||||
|
||||
if (!existing.getCode().equals(entity.getCode())) {
|
||||
if (repository.existsByCodeAndDeletedFalse(entity.getCode())) {
|
||||
throw new RuntimeException("部门编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
if (!existing.getName().equals(entity.getName())) {
|
||||
if (repository.existsByNameAndDeletedFalse(entity.getName())) {
|
||||
throw new RuntimeException("部门名称已存在");
|
||||
}
|
||||
}
|
||||
|
||||
entity.setCreateTime(existing.getCreateTime());
|
||||
entity.setCreateBy(existing.getCreateBy());
|
||||
entity.setDeleted(existing.getDeleted());
|
||||
|
||||
return repository.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Department> getTree() {
|
||||
List<Department> departments = repository.findByDeletedFalseOrderBySort();
|
||||
return buildTree(departments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateCode(String code) {
|
||||
if (repository.existsByCodeAndDeletedFalse(code)) {
|
||||
throw new RuntimeException("部门编码已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateName(String name) {
|
||||
if (repository.existsByNameAndDeletedFalse(name)) {
|
||||
throw new RuntimeException("部门名称已存在");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getNextSort(Long parentId) {
|
||||
return repository.findMaxSortByParentId(parentId) + 1;
|
||||
}
|
||||
|
||||
private List<Department> buildTree(List<Department> departments) {
|
||||
Map<Long, List<Department>> parentIdMap = departments.stream()
|
||||
.collect(Collectors.groupingBy(d -> d.getParentId() == null ? 0L : d.getParentId()));
|
||||
|
||||
return buildTreeNodes(0L, parentIdMap);
|
||||
}
|
||||
|
||||
private List<Department> buildTreeNodes(Long parentId, Map<Long, List<Department>> parentIdMap) {
|
||||
List<Department> nodes = new ArrayList<>();
|
||||
|
||||
List<Department> children = parentIdMap.get(parentId);
|
||||
if (children != null) {
|
||||
for (Department child : children) {
|
||||
child.setChildren(buildTreeNodes(child.getId(), parentIdMap));
|
||||
nodes.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,612 @@
|
||||
//package com.qqchen.deploy.backend.service.impl;
|
||||
//
|
||||
//import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl;
|
||||
//import com.qqchen.deploy.backend.entity.JenkinsConfig;
|
||||
//import com.qqchen.deploy.backend.repository.IJenkinsBuildRepository;
|
||||
//import com.qqchen.deploy.backend.repository.IJenkinsConfigRepository;
|
||||
//import com.qqchen.deploy.backend.repository.IJenkinsJobRepository;
|
||||
//import com.qqchen.deploy.backend.repository.IJenkinsSyncHistoryRepository;
|
||||
//import com.qqchen.deploy.backend.repository.IJenkinsViewRepository;
|
||||
//import com.qqchen.deploy.backend.service.IJenkinsService;
|
||||
//import jakarta.persistence.EntityManager;
|
||||
//import jakarta.persistence.PersistenceContext;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.beans.factory.annotation.Autowired;
|
||||
//import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
//import org.springframework.core.ParameterizedTypeReference;
|
||||
//import org.springframework.http.HttpEntity;
|
||||
//import org.springframework.http.HttpHeaders;
|
||||
//import org.springframework.http.HttpMethod;
|
||||
//import org.springframework.http.HttpStatus;
|
||||
//import org.springframework.http.MediaType;
|
||||
//import org.springframework.http.ResponseEntity;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//import org.springframework.web.client.RestTemplate;
|
||||
//
|
||||
//import java.time.Duration;
|
||||
//import java.time.Instant;
|
||||
//import java.time.LocalDateTime;
|
||||
//import java.time.ZoneId;
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Base64;
|
||||
//import java.util.Collections;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.concurrent.CompletableFuture;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Service
|
||||
//public class IJenkinsServiceImpl extends BaseServiceImpl<JenkinsConfig, Long> implements IJenkinsService {
|
||||
//
|
||||
// private final IJenkinsConfigRepository jenkinsConfigRepository;
|
||||
// private final IJenkinsSyncHistoryRepository jenkinsSyncHistoryRepository;
|
||||
// private final IJenkinsViewRepository jenkinsViewRepository;
|
||||
// private final IJenkinsJobRepository jenkinsJobRepository;
|
||||
// private final IJenkinsBuildRepository jenkinsBuildRepository;
|
||||
//
|
||||
// @PersistenceContext
|
||||
// private EntityManager entityManager;
|
||||
//
|
||||
// // 使用 ConcurrentHashMap 记录正在执行的任务
|
||||
// private static final Map<Long, Boolean> RUNNING_TASKS = new ConcurrentHashMap<>();
|
||||
//
|
||||
// @Autowired
|
||||
// public IJenkinsServiceImpl(
|
||||
// IJenkinsConfigRepository jenkinsConfigRepository,
|
||||
// IJenkinsSyncHistoryRepository jenkinsSyncHistoryRepository,
|
||||
// IJenkinsViewRepository jenkinsViewRepository,
|
||||
// IJenkinsJobRepository jenkinsJobRepository,
|
||||
// IJenkinsBuildRepository jenkinsBuildRepository
|
||||
// ){
|
||||
// super(jenkinsConfigRepository);
|
||||
// this.jenkinsConfigRepository = jenkinsConfigRepository;
|
||||
// this.jenkinsSyncHistoryRepository = jenkinsSyncHistoryRepository;
|
||||
// this.jenkinsViewRepository = jenkinsViewRepository;
|
||||
// this.jenkinsJobRepository = jenkinsJobRepository;
|
||||
// this.jenkinsBuildRepository = jenkinsBuildRepository;
|
||||
// }
|
||||
//
|
||||
// private RestTemplate createRestTemplate() {
|
||||
// return new RestTemplateBuilder()
|
||||
// .setConnectTimeout(Duration.ofSeconds(30))
|
||||
// .setReadTimeout(Duration.ofSeconds(30))
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
// private HttpEntity<String> createHttpEntity(String username, String password) {
|
||||
// HttpHeaders headers = new HttpHeaders();
|
||||
// String auth = username + ":" + password;
|
||||
// byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
|
||||
// headers.set("Authorization", "Basic " + new String(encodedAuth));
|
||||
// headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
// return new HttpEntity<>(headers);
|
||||
// }
|
||||
//
|
||||
// @Transactional
|
||||
// public JenkinsConfig save(JenkinsConfig config) {
|
||||
// if (jenkinsConfigRepository.existsByNameAndDeletedFalse(config.getName())) {
|
||||
// throw new RuntimeException("Jenkins名称已存在");
|
||||
// }
|
||||
// return jenkinsConfigRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// @Transactional
|
||||
// public JenkinsConfig update(Long id, JenkinsConfig config) {
|
||||
// JenkinsConfig existing = jenkinsConfigRepository.findById(id)
|
||||
// .orElseThrow(() -> new RuntimeException("Jenkins配置不存在"));
|
||||
//
|
||||
// if (!existing.getName().equals(config.getName())
|
||||
// && jenkinsConfigRepository.existsByNameAndDeletedFalse(config.getName())) {
|
||||
// throw new RuntimeException("Jenkins名称已存在");
|
||||
// }
|
||||
//
|
||||
// config.setId(id);
|
||||
// config.setVersion(existing.getVersion());
|
||||
// config.setDeleted(existing.getDeleted());
|
||||
// return jenkinsConfigRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean testConnection(JenkinsTestConnectionDTO dto) {
|
||||
// try {
|
||||
// String url = String.format("%s/api/json", dto.getUrl().trim());
|
||||
// ResponseEntity<Map> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(dto.getUsername(), dto.getPassword()),
|
||||
// Map.class
|
||||
// );
|
||||
//
|
||||
// if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
// log.info("Jenkins连接测试成功");
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// log.error("Jenkins连接测试失败: 响应状态码 {}", response.getStatusCode());
|
||||
// return false;
|
||||
// } catch (Exception e) {
|
||||
// log.error("Jenkins连接测试失败: {}", e.getMessage());
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Long asyncSyncAll(Long jenkinsId) {
|
||||
// // 检查是否已有同步任务在运行
|
||||
// if (RUNNING_TASKS.containsKey(jenkinsId)) {
|
||||
// log.warn("Jenkins已有同步任务正在运行中, jenkinsId: {}", jenkinsId);
|
||||
// throw new ApiException("该Jenkins已有同步任务正在运行中");
|
||||
// }
|
||||
//
|
||||
// log.info("开始同步Jenkins数据, jenkinsId: {}", jenkinsId);
|
||||
//
|
||||
// JenkinsConfig config = jenkinsConfigRepository.findById(jenkinsId)
|
||||
// .orElseThrow(() -> new ApiException("Jenkins配置不存在"));
|
||||
//
|
||||
// // 创建全量同步历史记录
|
||||
// JenkinsSyncHistory allHistory = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.ALL);
|
||||
//
|
||||
// // 标记任务开始运行
|
||||
// RUNNING_TASKS.put(jenkinsId, true);
|
||||
//
|
||||
// try {
|
||||
// // 1. 同步视图
|
||||
// JenkinsSyncHistory viewHistory = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.VIEW);
|
||||
// try {
|
||||
// syncViews(config, viewHistory);
|
||||
// } catch (Exception e) {
|
||||
// log.error("视图同步失败", e);
|
||||
// updateSyncHistory(viewHistory, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// throw e;
|
||||
// }
|
||||
//
|
||||
// // 2. 同步作业
|
||||
// JenkinsSyncHistory jobHistory = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.JOB);
|
||||
// try {
|
||||
// syncJobs(config, jobHistory);
|
||||
// } catch (Exception e) {
|
||||
// log.error("作业同步失败", e);
|
||||
// updateSyncHistory(jobHistory, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// throw e;
|
||||
// }
|
||||
//
|
||||
// // 3. 同步构建
|
||||
// JenkinsSyncHistory buildHistory = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.BUILD);
|
||||
// try {
|
||||
// syncBuilds(config, buildHistory);
|
||||
// } catch (Exception e) {
|
||||
// log.error("构建同步失败", e);
|
||||
// updateSyncHistory(buildHistory, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// throw e;
|
||||
// }
|
||||
//
|
||||
// // 更新全量同步状态
|
||||
// updateSyncHistory(allHistory, JenkinsSyncHistory.SyncStatus.SUCCESS, null);
|
||||
// config.setLastAllSyncTime(LocalDateTime.now());
|
||||
// jenkinsConfigRepository.save(config);
|
||||
// log.info("Jenkins数据同步完成, jenkinsId: {}", jenkinsId);
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// log.error("Jenkins数据同步失败", e);
|
||||
// updateSyncHistory(allHistory, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// } finally {
|
||||
// RUNNING_TASKS.remove(jenkinsId);
|
||||
// }
|
||||
//
|
||||
// return allHistory.getId();
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 同步Jenkins视图
|
||||
// * @param config Jenkins配置
|
||||
// * @param history 同步历史记录
|
||||
// */
|
||||
// private void syncViews(JenkinsConfig config, JenkinsSyncHistory history) {
|
||||
// String url = String.format("%s/api/json?tree=views[name,url,description]", config.getUrl().trim());
|
||||
// ResponseEntity<Map<String, Object>> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(config.getUsername(), config.getPassword()),
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() != null) {
|
||||
// List<Map<String, Object>> views = (List<Map<String, Object>>) response.getBody().get("views");
|
||||
// List<JenkinsView> viewsToSave = new ArrayList<>();
|
||||
// Map<String, JenkinsView> existingViews = jenkinsViewRepository
|
||||
// .findByJenkinsIdAndDeletedFalse(config.getId())
|
||||
// .stream()
|
||||
// .collect(Collectors.toMap(JenkinsView::getViewName, v -> v));
|
||||
//
|
||||
// for (Map<String, Object> view : views) {
|
||||
// String viewName = (String) view.get("name");
|
||||
// // 跳过 "All" 视图
|
||||
// if ("All".equalsIgnoreCase(viewName)) {
|
||||
// log.debug("跳过All视图同步 - 仓库: {}", config.getName());
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// JenkinsView jenkinsView = existingViews.getOrDefault(viewName, new JenkinsView());
|
||||
// jenkinsView.setJenkinsId(config.getId());
|
||||
// jenkinsView.setViewName(viewName);
|
||||
// jenkinsView.setViewUrl((String) view.get("url"));
|
||||
// jenkinsView.setDescription((String) view.get("description"));
|
||||
// viewsToSave.add(jenkinsView);
|
||||
// }
|
||||
//
|
||||
// if (!viewsToSave.isEmpty()) {
|
||||
// jenkinsViewRepository.saveAll(viewsToSave);
|
||||
// log.info("同步Jenkins视图完成, 总数: {}, 实际同步: {}", views.size(), viewsToSave.size());
|
||||
//
|
||||
// // 更新配置的同步时间
|
||||
// config.setLastViewSyncTime(LocalDateTime.now());
|
||||
// jenkinsConfigRepository.save(config);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.SUCCESS, null);
|
||||
// }
|
||||
//
|
||||
// @Transactional
|
||||
// public void updateSyncHistory(JenkinsSyncHistory history,
|
||||
// JenkinsSyncHistory.SyncStatus status,
|
||||
// String errorMessage) {
|
||||
// // 重新获取最新的历史记录
|
||||
// JenkinsSyncHistory latestHistory = jenkinsSyncHistoryRepository.findById(history.getId())
|
||||
// .orElseThrow(() -> new ApiException("同步历史记录不存在"));
|
||||
//
|
||||
// latestHistory.setStatus(status);
|
||||
// latestHistory.setEndTime(LocalDateTime.now());
|
||||
// latestHistory.setErrorMessage(errorMessage);
|
||||
// jenkinsSyncHistoryRepository.save(latestHistory);
|
||||
// }
|
||||
//
|
||||
// @Transactional
|
||||
// public JenkinsSyncHistory createSyncHistory(Long jenkinsId, JenkinsSyncHistory.SyncType syncType) {
|
||||
// JenkinsSyncHistory history = new JenkinsSyncHistory();
|
||||
// history.setJenkinsId(jenkinsId);
|
||||
// history.setSyncType(syncType);
|
||||
// history.setStartTime(LocalDateTime.now());
|
||||
// history.setStatus(JenkinsSyncHistory.SyncStatus.RUNNING);
|
||||
// return jenkinsSyncHistoryRepository.save(history);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 同步Jenkins作业
|
||||
// * @param config Jenkins配置
|
||||
// * @param history 同步历记录
|
||||
// */
|
||||
// private void syncJobs(JenkinsConfig config, JenkinsSyncHistory history) {
|
||||
// String url = String.format("%s/api/json?tree=jobs[name,url,description,buildable,lastBuild[number,timestamp,result]]",
|
||||
// config.getUrl().trim());
|
||||
// ResponseEntity<Map<String, Object>> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(config.getUsername(), config.getPassword()),
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() != null) {
|
||||
// List<Map<String, Object>> jobs = (List<Map<String, Object>>) response.getBody().get("jobs");
|
||||
// List<JenkinsJob> jobsToSave = new ArrayList<>();
|
||||
// Map<String, JenkinsJob> existingJobs = jenkinsJobRepository
|
||||
// .findByJenkinsIdAndDeletedFalse(config.getId())
|
||||
// .stream()
|
||||
// .collect(Collectors.toMap(JenkinsJob::getJobName, j -> j));
|
||||
//
|
||||
// for (Map<String, Object> job : jobs) {
|
||||
// String jobName = (String) job.get("name");
|
||||
// JenkinsJob jenkinsJob = existingJobs.getOrDefault(jobName, new JenkinsJob());
|
||||
// jenkinsJob.setJenkinsId(config.getId());
|
||||
// jenkinsJob.setJobName(jobName);
|
||||
// jenkinsJob.setJobUrl((String) job.get("url"));
|
||||
// jenkinsJob.setDescription((String) job.get("description"));
|
||||
// jenkinsJob.setBuildable((Boolean) job.get("buildable"));
|
||||
//
|
||||
// Map<String, Object> lastBuild = (Map<String, Object>) job.get("lastBuild");
|
||||
// if (lastBuild != null) {
|
||||
// jenkinsJob.setLastBuildNumber(((Number) lastBuild.get("number")).intValue());
|
||||
// long timestamp = ((Number) lastBuild.get("timestamp")).longValue();
|
||||
// jenkinsJob.setLastBuildTime(LocalDateTime.ofInstant(
|
||||
// Instant.ofEpochMilli(timestamp),
|
||||
// ZoneId.systemDefault()
|
||||
// ));
|
||||
// jenkinsJob.setLastBuildStatus((String) lastBuild.get("result"));
|
||||
// }
|
||||
// jobsToSave.add(jenkinsJob);
|
||||
// }
|
||||
//
|
||||
// if (!jobsToSave.isEmpty()) {
|
||||
// jenkinsJobRepository.saveAll(jobsToSave);
|
||||
// log.info("同步Jenkins作业完成, 总数: {}, 实际同步: {}", jobs.size(), jobsToSave.size());
|
||||
//
|
||||
// // 更新配置的同步时间
|
||||
// config.setLastJobSyncTime(LocalDateTime.now());
|
||||
// jenkinsConfigRepository.save(config);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.SUCCESS, null);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 同步Jenkins构建
|
||||
// * @param config Jenkins配置
|
||||
// * @param history 同步历史记录
|
||||
// */
|
||||
// private void syncBuilds(JenkinsConfig config, JenkinsSyncHistory history) {
|
||||
// List<JenkinsJob> jobs = jenkinsJobRepository.findByJenkinsIdAndDeletedFalse(config.getId());
|
||||
// List<JenkinsBuild> allBuildsToSave = new ArrayList<>();
|
||||
//
|
||||
// for (JenkinsJob job : jobs) {
|
||||
// String url = String.format("%s/api/json?tree=builds[number,url,timestamp,result,duration,actions[causes[*]]]",
|
||||
// job.getJobUrl().trim());
|
||||
// ResponseEntity<Map<String, Object>> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(config.getUsername(), config.getPassword()),
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() != null) {
|
||||
// List<Map<String, Object>> builds = (List<Map<String, Object>>) response.getBody().get("builds");
|
||||
// Map<Integer, JenkinsBuild> existingBuilds = jenkinsBuildRepository
|
||||
// .findByJobIdAndDeletedFalse(job.getId())
|
||||
// .stream()
|
||||
// .collect(Collectors.toMap(JenkinsBuild::getBuildNumber, b -> b));
|
||||
//
|
||||
// for (Map<String, Object> build : builds) {
|
||||
// Integer buildNumber = ((Number) build.get("number")).intValue();
|
||||
// JenkinsBuild jenkinsBuild = existingBuilds.getOrDefault(buildNumber, new JenkinsBuild());
|
||||
// jenkinsBuild.setJenkinsId(config.getId());
|
||||
// jenkinsBuild.setJobId(job.getId());
|
||||
// jenkinsBuild.setBuildNumber(buildNumber);
|
||||
// jenkinsBuild.setBuildUrl((String) build.get("url"));
|
||||
// jenkinsBuild.setBuildStatus((String) build.get("result"));
|
||||
//
|
||||
// long timestamp = ((Number) build.get("timestamp")).longValue();
|
||||
// jenkinsBuild.setStartTime(LocalDateTime.ofInstant(
|
||||
// Instant.ofEpochMilli(timestamp),
|
||||
// ZoneId.systemDefault()
|
||||
// ));
|
||||
//
|
||||
// jenkinsBuild.setDuration(((Number) build.get("duration")).longValue());
|
||||
//
|
||||
// // 处理触发原因
|
||||
// List<Map<String, Object>> actions = (List<Map<String, Object>>) build.get("actions");
|
||||
// if (actions != null) {
|
||||
// for (Map<String, Object> action : actions) {
|
||||
// if (action != null && action.containsKey("causes")) {
|
||||
// List<Map<String, Object>> causes = (List<Map<String, Object>>) action.get("causes");
|
||||
// if (causes != null && !causes.isEmpty()) {
|
||||
// jenkinsBuild.setTriggerCause((String) causes.get(0).get("shortDescription"));
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// allBuildsToSave.add(jenkinsBuild);
|
||||
// }
|
||||
// log.info("处理Jenkins构建历史, 作业: {}, 构建数量: {}", job.getJobName(), builds.size());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!allBuildsToSave.isEmpty()) {
|
||||
// jenkinsBuildRepository.saveAll(allBuildsToSave);
|
||||
// log.info("同步Jenkins构建完成, 总数: {}", allBuildsToSave.size());
|
||||
//
|
||||
// // 更新配置的同步时间
|
||||
// config.setLastBuildSyncTime(LocalDateTime.now());
|
||||
// jenkinsConfigRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.SUCCESS, null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<JenkinsSyncHistoryDTO> getSyncHistories() {
|
||||
// List<JenkinsSyncHistory> histories = jenkinsSyncHistoryRepository.findTop50ByOrderByStartTimeDesc();
|
||||
//
|
||||
// return histories.stream()
|
||||
// .map(history -> {
|
||||
// JenkinsConfig config = jenkinsConfigRepository.findById(history.getJenkinsId())
|
||||
// .orElse(null);
|
||||
//
|
||||
// return JenkinsSyncHistoryDTO.builder()
|
||||
// .id(history.getId())
|
||||
// .jenkinsId(history.getJenkinsId())
|
||||
// .jenkinsName(config != null ? config.getName() : "未知Jenkins")
|
||||
// .syncType(history.getSyncType())
|
||||
// .status(history.getStatus())
|
||||
// .startTime(history.getStartTime())
|
||||
// .endTime(history.getEndTime())
|
||||
// .errorMessage(history.getErrorMessage())
|
||||
// .build();
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Transactional
|
||||
// public void updateLastSyncTime(Long jenkinsId, String timeField) {
|
||||
// // 使用 JPQL 更新指定字段
|
||||
// String jpql = String.format("UPDATE JenkinsConfig j SET j.%s = :now WHERE j.id = :id", timeField);
|
||||
// entityManager.createQuery(jpql)
|
||||
// .setParameter("now", LocalDateTime.now())
|
||||
// .setParameter("id", jenkinsId)
|
||||
// .executeUpdate();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Long asyncSyncView(Long jenkinsId) {
|
||||
// // 检查是否已有同步任务在运行
|
||||
// if (RUNNING_TASKS.containsKey(jenkinsId)) {
|
||||
// log.warn("Jenkins已有同步任务正在运行中, jenkinsId: {}", jenkinsId);
|
||||
// throw new ApiException("该Jenkins已有同步任务正在运行中");
|
||||
// }
|
||||
//
|
||||
// log.info("开始同步Jenkins视图, jenkinsId: {}", jenkinsId);
|
||||
//
|
||||
// JenkinsConfig config = jenkinsConfigRepository.findById(jenkinsId)
|
||||
// .orElseThrow(() -> new ApiException("Jenkins配置不存在"));
|
||||
//
|
||||
// // 创建同步历史记录
|
||||
// JenkinsSyncHistory history = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.VIEW);
|
||||
//
|
||||
// // 标记任务开始运行
|
||||
// RUNNING_TASKS.put(jenkinsId, true);
|
||||
//
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// try {
|
||||
// syncViews(config, history);
|
||||
// } catch (Exception e) {
|
||||
// log.error("视图同步失败", e);
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// } finally {
|
||||
// RUNNING_TASKS.remove(jenkinsId);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return history.getId();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Long asyncSyncJob(Long jenkinsId) {
|
||||
// // 检查是否已有同步任务在运行
|
||||
// if (RUNNING_TASKS.containsKey(jenkinsId)) {
|
||||
// log.warn("Jenkins已有同步任务正在运行中, jenkinsId: {}", jenkinsId);
|
||||
// throw new ApiException("该Jenkins已有同步任务正在运行中");
|
||||
// }
|
||||
//
|
||||
// log.info("开始同步Jenkins作业, jenkinsId: {}", jenkinsId);
|
||||
//
|
||||
// JenkinsConfig config = jenkinsConfigRepository.findById(jenkinsId)
|
||||
// .orElseThrow(() -> new ApiException("Jenkins配置不存在"));
|
||||
//
|
||||
// // 创建同步历史记录
|
||||
// JenkinsSyncHistory history = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.JOB);
|
||||
//
|
||||
// // 标记任务开始运行
|
||||
// RUNNING_TASKS.put(jenkinsId, true);
|
||||
//
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// try {
|
||||
// syncJobs(config, history);
|
||||
// } catch (Exception e) {
|
||||
// log.error("作业同步失败", e);
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// } finally {
|
||||
// RUNNING_TASKS.remove(jenkinsId);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return history.getId();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Long asyncSyncBuild(Long jenkinsId) {
|
||||
// // 检查是否已有同步任务在运行
|
||||
// if (RUNNING_TASKS.containsKey(jenkinsId)) {
|
||||
// log.warn("Jenkins已有同步任务正在运行中, jenkinsId: {}", jenkinsId);
|
||||
// throw new ApiException("该Jenkins已有同步任务正在运行中");
|
||||
// }
|
||||
//
|
||||
// log.info("开始同步Jenkins构建, jenkinsId: {}", jenkinsId);
|
||||
//
|
||||
// JenkinsConfig config = jenkinsConfigRepository.findById(jenkinsId)
|
||||
// .orElseThrow(() -> new ApiException("Jenkins配置不存在"));
|
||||
//
|
||||
// // 创建同步历史记录
|
||||
// JenkinsSyncHistory history = createSyncHistory(jenkinsId, JenkinsSyncHistory.SyncType.BUILD);
|
||||
//
|
||||
// // 标记任务开始运行
|
||||
// RUNNING_TASKS.put(jenkinsId, true);
|
||||
//
|
||||
// CompletableFuture.runAsync(() -> {
|
||||
// try {
|
||||
// syncBuilds(config, history);
|
||||
// } catch (Exception e) {
|
||||
// log.error("构建同步失败", e);
|
||||
// updateSyncHistory(history, JenkinsSyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// } finally {
|
||||
// RUNNING_TASKS.remove(jenkinsId);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return history.getId();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<ViewResponse> getViews(Long jenkinsId) {
|
||||
// List<JenkinsView> views = jenkinsViewRepository.findByJenkinsIdAndDeletedFalse(jenkinsId);
|
||||
// return views.stream()
|
||||
// .map(view -> ViewResponse.builder()
|
||||
// .id(view.getId())
|
||||
// .jenkinsId(view.getJenkinsId())
|
||||
// .viewName(view.getViewName())
|
||||
// .viewUrl(view.getViewUrl())
|
||||
// .description(view.getDescription())
|
||||
// .build())
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<JobResponse> getJobs(Long jenkinsId) {
|
||||
// List<JenkinsJob> jobs = jenkinsJobRepository.findByJenkinsIdAndDeletedFalse(jenkinsId);
|
||||
// return jobs.stream()
|
||||
// .map(job -> JobResponse.builder()
|
||||
// .id(job.getId())
|
||||
// .jenkinsId(job.getJenkinsId())
|
||||
// .viewId(job.getView() != null ? job.getView().getId() : null)
|
||||
// .viewName(job.getView() != null ? job.getView().getViewName() : null)
|
||||
// .jobName(job.getJobName())
|
||||
// .jobUrl(job.getJobUrl())
|
||||
// .description(job.getDescription())
|
||||
// .buildable(job.getBuildable())
|
||||
// .lastBuildNumber(job.getLastBuildNumber())
|
||||
// .lastBuildTime(job.getLastBuildTime())
|
||||
// .lastBuildStatus(job.getLastBuildStatus())
|
||||
// .build())
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<BuildResponse> getBuilds(Long jenkinsId, Long jobId) {
|
||||
// List<JenkinsBuild> builds = jenkinsBuildRepository.findByJobIdAndDeletedFalseOrderByBuildNumberDesc(jobId);
|
||||
// return builds.stream()
|
||||
// .map(build -> BuildResponse.builder()
|
||||
// .id(build.getId())
|
||||
// .jenkinsId(build.getJenkinsId())
|
||||
// .jobId(build.getJobId())
|
||||
// .buildNumber(build.getBuildNumber())
|
||||
// .buildUrl(build.getBuildUrl())
|
||||
// .buildStatus(build.getBuildStatus())
|
||||
// .startTime(build.getStartTime())
|
||||
// .duration(build.getDuration())
|
||||
// .triggerCause(build.getTriggerCause())
|
||||
// .build())
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<JobResponse> getJobsByView(Long jenkinsId, String viewName) {
|
||||
// List<JenkinsJob> jobs = jenkinsJobRepository.findJobsByJenkinsIdAndViewName(jenkinsId, viewName);
|
||||
// return jobs.stream()
|
||||
// .map(job -> JobResponse.builder()
|
||||
// .id(job.getId())
|
||||
// .jenkinsId(job.getJenkinsId())
|
||||
// .viewId(job.getView().getId())
|
||||
// .viewName(job.getView().getViewName())
|
||||
// .jobName(job.getJobName())
|
||||
// .jobUrl(job.getJobUrl())
|
||||
// .description(job.getDescription())
|
||||
// .buildable(job.getBuildable())
|
||||
// .lastBuildNumber(job.getLastBuildNumber())
|
||||
// .lastBuildTime(job.getLastBuildTime())
|
||||
// .lastBuildStatus(job.getLastBuildStatus())
|
||||
// .build())
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,254 @@
|
||||
//package com.qqchen.deploy.backend.service.impl;
|
||||
//
|
||||
//import com.qqchen.application.dto.MenuDTO;
|
||||
//import com.qqchen.application.query.MenuQuery;
|
||||
//import com.qqchen.application.service.MenuService;
|
||||
//import com.qqchen.common.exception.ApiException;
|
||||
//import com.qqchen.common.service.impl.BaseServiceImpl;
|
||||
//import com.qqchen.domain.entity.Menu;
|
||||
//import com.qqchen.domain.entity.RoleMenu;
|
||||
//import com.qqchen.domain.repository.MenuRepository;
|
||||
//import com.qqchen.domain.repository.RoleMenuRepository;
|
||||
//import lombok.RequiredArgsConstructor;
|
||||
//import org.springframework.beans.BeanUtils;
|
||||
//import org.springframework.data.jpa.repository.JpaRepository;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//
|
||||
//import java.util.ArrayList;
|
||||
//import java.util.Arrays;
|
||||
//import java.util.Comparator;
|
||||
//import java.util.List;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//@Service
|
||||
//@RequiredArgsConstructor
|
||||
//public class IMenuServiceImpl extends BaseServiceImpl<Menu, MenuQuery> implements MenuService {
|
||||
//
|
||||
// private final MenuRepository menuRepository;
|
||||
// private final RoleMenuRepository roleMenuRepository;
|
||||
//
|
||||
// @Override
|
||||
// protected JpaRepository<Menu, Long> getRepository() {
|
||||
// return menuRepository;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<MenuDTO> getMenuTree() {
|
||||
// List<Menu> menus = menuRepository.findByDeletedFalseOrderBySort();
|
||||
// return buildMenuTree(menus);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<MenuDTO> getUserMenus(Long userId) {
|
||||
// // TODO: 根据用户ID获取角色,然后获取菜单
|
||||
// return new ArrayList<>();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Menu> getMenusByRoleId(Long roleId) {
|
||||
// List<RoleMenu> roleMenus = roleMenuRepository.findByRoleId(roleId);
|
||||
// return roleMenus.stream()
|
||||
// .map(rm -> menuRepository.findById(rm.getMenuId())
|
||||
// .orElseThrow(() -> new ApiException("菜单不存在")))
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void saveRoleMenus(Long roleId, List<Long> menuIds) {
|
||||
// // 先删除原有的关联
|
||||
// roleMenuRepository.deleteByRoleId(roleId);
|
||||
//
|
||||
// // 保存新的关联
|
||||
// List<RoleMenu> roleMenus = menuIds.stream()
|
||||
// .map(menuId -> {
|
||||
// RoleMenu rm = new RoleMenu();
|
||||
// rm.setRoleId(roleId);
|
||||
// rm.setMenuId(menuId);
|
||||
// return rm;
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// roleMenuRepository.saveAll(roleMenus);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public Menu update(Long id, Menu menu) {
|
||||
// Menu existing = findById(id)
|
||||
// .orElseThrow(() -> new ApiException("菜单不存在"));
|
||||
//
|
||||
// // 设置不允许修改的字段
|
||||
// menu.setId(id);
|
||||
// menu.setVersion(existing.getVersion());
|
||||
// menu.setDeleted(existing.getDeleted());
|
||||
//
|
||||
// // 如果是按钮类型,清空路径和组件
|
||||
// if (menu.getType() == 2) {
|
||||
// menu.setPath(null);
|
||||
// menu.setComponent(null);
|
||||
// menu.setIcon(null);
|
||||
// }
|
||||
//
|
||||
// // 如果是目录,设置固定组件
|
||||
// if (menu.getType() == 0) {
|
||||
// menu.setComponent("LAYOUT");
|
||||
// }
|
||||
//
|
||||
// // 如果没有父级菜单,设置为根节点
|
||||
// if (menu.getParentId() == null) {
|
||||
// menu.setParentId(0L);
|
||||
// }
|
||||
//
|
||||
// return menuRepository.save(menu);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public Menu save(Menu menu) {
|
||||
// // 如果是按钮类型,清空路径和组件
|
||||
// if (menu.getType() == 2) {
|
||||
// menu.setPath(null);
|
||||
// menu.setComponent(null);
|
||||
// menu.setIcon(null);
|
||||
// }
|
||||
//
|
||||
// // 如果是目录,设置固定组件
|
||||
// if (menu.getType() == 0) {
|
||||
// menu.setComponent("LAYOUT");
|
||||
// }
|
||||
//
|
||||
// // 如果没有父级菜单,设置为根节点
|
||||
// if (menu.getParentId() == null) {
|
||||
// menu.setParentId(0L);
|
||||
// }
|
||||
//
|
||||
// menu.setDeleted(false);
|
||||
// Menu savedMenu = menuRepository.save(menu);
|
||||
//
|
||||
// // 如果是菜单类型,自动创建增删改查按钮
|
||||
// if (menu.getType() == 1) {
|
||||
// createDefaultButtons(savedMenu);
|
||||
// }
|
||||
//
|
||||
// return savedMenu;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 创建默认的按钮权限
|
||||
// */
|
||||
// private void createDefaultButtons(Menu menu) {
|
||||
// // 获取基础权限标识
|
||||
// String basePermission = getBasePermission(menu.getPath());
|
||||
//
|
||||
// // 创建默认按钮列表
|
||||
// List<Menu> buttons = List.of(
|
||||
// createButton(menu.getName() + "查看", basePermission + ":view", menu.getId(), 1),
|
||||
// createButton(menu.getName() + "新增", basePermission + ":add", menu.getId(), 2),
|
||||
// createButton(menu.getName() + "修改", basePermission + ":edit", menu.getId(), 3),
|
||||
// createButton(menu.getName() + "删除", basePermission + ":delete", menu.getId(), 4)
|
||||
// );
|
||||
//
|
||||
// menuRepository.saveAll(buttons);
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 创建按钮
|
||||
// */
|
||||
// private Menu createButton(String name, String permission, Long parentId, int sort) {
|
||||
// Menu button = new Menu();
|
||||
// button.setName(name);
|
||||
// button.setPermission(permission);
|
||||
// button.setType(2);
|
||||
// button.setParentId(parentId);
|
||||
// button.setSort(sort);
|
||||
// button.setEnabled(true);
|
||||
// button.setDeleted(false);
|
||||
// return button;
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 根据路径获取基础权限标识
|
||||
// * 例如:/system/user -> system:user
|
||||
// */
|
||||
// private String getBasePermission(String path) {
|
||||
// if (path == null) {
|
||||
// return "";
|
||||
// }
|
||||
// // 移除开头的斜杠
|
||||
// if (path.startsWith("/")) {
|
||||
// path = path.substring(1);
|
||||
// }
|
||||
// // 将斜杠替换为冒号
|
||||
// return path.replace("/", ":");
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void delete(Long id) {
|
||||
// Menu menu = findById(id)
|
||||
// .orElseThrow(() -> new ApiException("菜单不存在"));
|
||||
//
|
||||
// // 如果是菜单类型,同时删除其下的按钮
|
||||
// if (menu.getType() == 1) {
|
||||
// List<Menu> buttons = menuRepository.findByParentIdAndDeletedFalse(id);
|
||||
// if (!buttons.isEmpty()) {
|
||||
// for (Menu button : buttons) {
|
||||
// button.setDeleted(true);
|
||||
// menuRepository.save(button);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 检查是否有子菜单
|
||||
// List<Menu> children = menuRepository.findByParentIdAndDeletedFalse(id);
|
||||
// if (!children.isEmpty()) {
|
||||
// throw new ApiException("该菜单下还有子菜单,不能删除");
|
||||
// }
|
||||
//
|
||||
// menu.setDeleted(true);
|
||||
// menuRepository.save(menu);
|
||||
// }
|
||||
//
|
||||
// private List<MenuDTO> buildMenuTree(List<Menu> menus) {
|
||||
// // 先找出所有的根节点(parentId为null或0的节点)
|
||||
// List<Menu> rootMenus = menus.stream()
|
||||
// .filter(menu -> menu.getParentId() == null || menu.getParentId() == 0)
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// // 构建子树
|
||||
// return rootMenus.stream()
|
||||
// .map(menu -> buildMenuNode(menu, menus))
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 构建菜单节点
|
||||
// */
|
||||
// private MenuDTO buildMenuNode(Menu menu, List<Menu> allMenus) {
|
||||
// MenuDTO dto = new MenuDTO();
|
||||
// BeanUtils.copyProperties(menu, dto);
|
||||
//
|
||||
// // 查找当前节点的子节点
|
||||
// List<Menu> children = allMenus.stream()
|
||||
// .filter(m -> menu.getId().equals(m.getParentId()))
|
||||
// .sorted(Comparator.comparing(Menu::getSort))
|
||||
// .collect(Collectors.toList());
|
||||
//
|
||||
// if (!children.isEmpty()) {
|
||||
// dto.setChildren(children.stream()
|
||||
// .map(child -> buildMenuNode(child, allMenus))
|
||||
// .collect(Collectors.toList()));
|
||||
// }
|
||||
//
|
||||
// return dto;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<MenuDTO> getMenuTreeWithoutButtons() {
|
||||
// // 获取所有非按钮类型的菜单
|
||||
// List<Menu> menus = menuRepository.findByTypeInAndDeletedFalseOrderBySort(Arrays.asList(0, 1)); // 0-目录 1-菜单
|
||||
// return buildMenuTree(menus);
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,688 @@
|
||||
//package com.qqchen.deploy.backend.service.impl;
|
||||
//
|
||||
//import com.qqchen.application.dto.RepositorySyncStatusDTO;
|
||||
//import com.qqchen.application.dto.RunningSyncDTO;
|
||||
//import com.qqchen.application.dto.TestConnectionDTO;
|
||||
//import com.qqchen.application.service.RepositoryService;
|
||||
//import com.qqchen.common.exception.ApiException;
|
||||
//import com.qqchen.domain.entity.RepositoryBranch;
|
||||
//import com.qqchen.domain.entity.RepositoryConfig;
|
||||
//import com.qqchen.domain.entity.RepositoryGroup;
|
||||
//import com.qqchen.domain.entity.RepositoryProject;
|
||||
//import com.qqchen.domain.entity.RepositorySyncHistory;
|
||||
//import com.qqchen.domain.repository.RepositoryBranchRepository;
|
||||
//import com.qqchen.domain.repository.RepositoryConfigRepository;
|
||||
//import com.qqchen.domain.repository.RepositoryGroupRepository;
|
||||
//import com.qqchen.domain.repository.RepositoryProjectRepository;
|
||||
//import com.qqchen.domain.repository.RepositorySyncHistoryRepository;
|
||||
//import lombok.Getter;
|
||||
//import lombok.RequiredArgsConstructor;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
//import org.springframework.core.ParameterizedTypeReference;
|
||||
//import org.springframework.core.task.AsyncTaskExecutor;
|
||||
//import org.springframework.http.HttpEntity;
|
||||
//import org.springframework.http.HttpHeaders;
|
||||
//import org.springframework.http.HttpMethod;
|
||||
//import org.springframework.http.HttpStatus;
|
||||
//import org.springframework.http.MediaType;
|
||||
//import org.springframework.http.ResponseEntity;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.transaction.PlatformTransactionManager;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//import org.springframework.transaction.support.TransactionTemplate;
|
||||
//import org.springframework.web.client.RestTemplate;
|
||||
//
|
||||
//import java.time.Duration;
|
||||
//import java.time.LocalDateTime;
|
||||
//import java.util.Collection;
|
||||
//import java.util.Collections;
|
||||
//import java.util.List;
|
||||
//import java.util.Map;
|
||||
//import java.util.concurrent.CompletableFuture;
|
||||
//import java.util.concurrent.ConcurrentHashMap;
|
||||
//import java.util.concurrent.TimeUnit;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Service
|
||||
//@RequiredArgsConstructor
|
||||
//public class RepositoryServiceImpl implements RepositoryService {
|
||||
//
|
||||
// private final RepositoryConfigRepository configRepository;
|
||||
//
|
||||
// private final RepositoryGroupRepository groupRepository;
|
||||
//
|
||||
// private final RepositoryProjectRepository projectRepository;
|
||||
//
|
||||
// private final RepositoryBranchRepository branchRepository;
|
||||
//
|
||||
// private final RepositorySyncHistoryRepository syncHistoryRepository;
|
||||
//
|
||||
// private final AsyncTaskExecutor taskExecutor;
|
||||
//
|
||||
// private final PlatformTransactionManager transactionManager;
|
||||
//
|
||||
// // 使用 ConcurrentHashMap 记录正在执行的任务
|
||||
// private static final Map<Long, Boolean> RUNNING_TASKS = new ConcurrentHashMap<>();
|
||||
//
|
||||
// private RestTemplate createRestTemplate() {
|
||||
// return new RestTemplateBuilder()
|
||||
// .setConnectTimeout(Duration.ofSeconds(30))
|
||||
// .setReadTimeout(Duration.ofSeconds(30))
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
// private HttpEntity<String> createHttpEntity(String accessToken) {
|
||||
// HttpHeaders headers = new HttpHeaders();
|
||||
// headers.set("PRIVATE-TOKEN", accessToken.trim());
|
||||
// headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
|
||||
// return new HttpEntity<>(headers);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<RepositoryConfig> listConfigs() {
|
||||
// return configRepository.findByDeletedFalseOrderBySort();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public RepositoryConfig createConfig(RepositoryConfig config) {
|
||||
// if (configRepository.existsByNameAndDeletedFalse(config.getName())) {
|
||||
// throw new ApiException("仓库名称已存在");
|
||||
// }
|
||||
//
|
||||
// if (!testConnection(config)) {
|
||||
// throw new ApiException("仓库连接测试失败");
|
||||
// }
|
||||
//
|
||||
// return configRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public RepositoryConfig updateConfig(Long id, RepositoryConfig config) {
|
||||
// RepositoryConfig existing = configRepository.findById(id)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// if (!existing.getName().equals(config.getName())
|
||||
// && configRepository.existsByNameAndDeletedFalse(config.getName())) {
|
||||
// throw new ApiException("仓库名称已存在");
|
||||
// }
|
||||
//
|
||||
// if (!existing.getUrl().equals(config.getUrl())
|
||||
// || !existing.getAccessToken().equals(config.getAccessToken())) {
|
||||
// if (!testConnection(config)) {
|
||||
// throw new ApiException("仓库连接测试失败");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// config.setId(id);
|
||||
// config.setVersion(existing.getVersion());
|
||||
// config.setDeleted(existing.getDeleted());
|
||||
// return configRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void deleteConfig(Long id) {
|
||||
// RepositoryConfig config = configRepository.findById(id)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// config.setDeleted(true);
|
||||
// configRepository.save(config);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean testConnection(RepositoryConfig config) {
|
||||
// try {
|
||||
// String url = String.format("%s/api/v4/user", config.getUrl().trim());
|
||||
// ResponseEntity<Map> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(config.getAccessToken()),
|
||||
// Map.class
|
||||
// );
|
||||
//
|
||||
// if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
// log.info("测试连接成功,用户: {}", response.getBody().get("username"));
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// log.error("测试连接失败: 响应状态码 {}", response.getStatusCode());
|
||||
// return false;
|
||||
// } catch (Exception e) {
|
||||
// log.error("测试连接失败: {}", e.getMessage());
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean testConnection(TestConnectionDTO dto) {
|
||||
// try {
|
||||
// String url = String.format("%s/api/v4/user", dto.getUrl().trim());
|
||||
// ResponseEntity<Map> response = createRestTemplate().exchange(
|
||||
// url,
|
||||
// HttpMethod.GET,
|
||||
// createHttpEntity(dto.getAccessToken()),
|
||||
// Map.class
|
||||
// );
|
||||
//
|
||||
// if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
|
||||
// log.info("测试连接成功,用户: {}", response.getBody().get("username"));
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// log.error("测试连接失败: 响应状态码 {}", response.getStatusCode());
|
||||
// return false;
|
||||
// } catch (Exception e) {
|
||||
// log.error("测试连接失败: {}", e.getMessage());
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public Long asyncSyncAll(Long repositoryId) {
|
||||
// // 检查是否已有同步任务在运行
|
||||
// if (RUNNING_TASKS.containsKey(repositoryId)) {
|
||||
// throw new ApiException("该仓库已有同步任务正在运行中");
|
||||
// }
|
||||
//
|
||||
// log.info("开始异步同步仓库数据, repositoryId: {}", repositoryId);
|
||||
//
|
||||
// RepositoryConfig config = configRepository.findById(repositoryId)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// // 创建同步历史记录
|
||||
// RepositorySyncHistory history = new RepositorySyncHistory();
|
||||
// history.setRepositoryId(repositoryId);
|
||||
// history.setSyncType(RepositorySyncHistory.SyncType.GROUP);
|
||||
// history.setStartTime(LocalDateTime.now());
|
||||
// history.setStatus(RepositorySyncHistory.SyncStatus.RUNNING);
|
||||
// syncHistoryRepository.save(history);
|
||||
//
|
||||
// // 标记任务开始运行
|
||||
// RUNNING_TASKS.put(repositoryId, true);
|
||||
//
|
||||
// taskExecutor.execute(() -> {
|
||||
// // 用于存储同步过程中的错误信息
|
||||
// StringBuilder errorMessages = new StringBuilder();
|
||||
//
|
||||
// try {
|
||||
// RestTemplate restTemplate = createRestTemplate();
|
||||
// HttpEntity<String> entity = createHttpEntity(config.getAccessToken());
|
||||
//
|
||||
// // 1. 同步所有数据到内存
|
||||
// RepositorySyncDataCache dataHolder = new RepositorySyncDataCache();
|
||||
//
|
||||
// // 2. 同步群组数据
|
||||
// try {
|
||||
// CompletableFuture<Boolean> groupsFuture = syncGroupsParallel(config, entity, restTemplate, dataHolder);
|
||||
// boolean groupsSuccess = groupsFuture.get(10, TimeUnit.MINUTES);
|
||||
// if (!groupsSuccess) {
|
||||
// errorMessages.append("群组同步失败; ");
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("群组同步失败", e);
|
||||
// errorMessages.append("群组同步异常: ").append(e.getMessage()).append("; ");
|
||||
// }
|
||||
//
|
||||
// // 3. 如果同步成功,同步项目数据
|
||||
// if (errorMessages.isEmpty() && !dataHolder.getGroups().isEmpty()) {
|
||||
// try {
|
||||
// CompletableFuture<Boolean> projectsFuture = syncProjectsParallel(
|
||||
// config, entity, restTemplate, dataHolder.getGroups().values(), dataHolder);
|
||||
// boolean projectsSuccess = projectsFuture.get(10, TimeUnit.MINUTES);
|
||||
// if (!projectsSuccess) {
|
||||
// errorMessages.append("项目同步失败; ");
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("项目同步失败", e);
|
||||
// errorMessages.append("项目同步异常: ").append(e.getMessage()).append("; ");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 4. 如果项目同步成功,同步分支数据
|
||||
// if (errorMessages.isEmpty() && !dataHolder.getProjects().isEmpty()) {
|
||||
// try {
|
||||
// CompletableFuture<Boolean> branchesFuture = syncBranchesParallel(
|
||||
// config, entity, restTemplate, dataHolder.getProjects().values(), dataHolder);
|
||||
// boolean branchesSuccess = branchesFuture.get(10, TimeUnit.MINUTES);
|
||||
// if (!branchesSuccess) {
|
||||
// errorMessages.append("分支同步失败; ");
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("分支同步失败", e);
|
||||
// errorMessages.append("分支同步异常: ").append(e.getMessage()).append("; ");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 5. 如果所有数据都同步成功,在新的事务中更新数据库
|
||||
// if (errorMessages.isEmpty()) {
|
||||
// try {
|
||||
// updateDatabaseWithTransaction(repositoryId, dataHolder);
|
||||
// updateSyncHistory(history, RepositorySyncHistory.SyncStatus.SUCCESS, null);
|
||||
// log.info("仓库数据同步完成, repositoryId: {}", repositoryId);
|
||||
// } catch (Exception e) {
|
||||
// log.error("数据库更新失败", e);
|
||||
// errorMessages.append("数据库更新失败: ").append(e.getMessage());
|
||||
// updateSyncHistory(history, RepositorySyncHistory.SyncStatus.FAILED, errorMessages.toString());
|
||||
// }
|
||||
// } else {
|
||||
// updateSyncHistory(history, RepositorySyncHistory.SyncStatus.FAILED, errorMessages.toString());
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("仓库数同步失败", e);
|
||||
// updateSyncHistory(history, RepositorySyncHistory.SyncStatus.FAILED, e.getMessage());
|
||||
// } finally {
|
||||
// // 无论成功失败,都移除运行标记
|
||||
// RUNNING_TASKS.remove(repositoryId);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// return history.getId();
|
||||
// }
|
||||
//
|
||||
// // 使用编程式事务
|
||||
// private void updateDatabaseWithTransaction(Long repositoryId, RepositorySyncDataCache dataHolder) {
|
||||
// TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
// transactionTemplate.execute(status -> {
|
||||
// try {
|
||||
// updateDatabase(repositoryId, dataHolder);
|
||||
// return null;
|
||||
// } catch (Exception e) {
|
||||
// status.setRollbackOnly();
|
||||
// throw e;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// // 实际的数据库更新操作
|
||||
// private void updateDatabase(Long repositoryId, RepositorySyncDataCache dataHolder) {
|
||||
// log.info("开始更新数据库...");
|
||||
//
|
||||
// try {
|
||||
// // 1. 删除旧数据
|
||||
// log.info("删除旧数据...");
|
||||
// branchRepository.deleteByRepositoryId(repositoryId);
|
||||
// projectRepository.deleteByRepositoryId(repositoryId);
|
||||
// groupRepository.deleteByRepositoryId(repositoryId);
|
||||
//
|
||||
// // 2. 保存新数据
|
||||
// log.info("保存新数据...");
|
||||
// if (!dataHolder.getGroups().isEmpty()) {
|
||||
// groupRepository.saveAll(dataHolder.getGroups().values());
|
||||
// }
|
||||
// if (!dataHolder.getProjects().isEmpty()) {
|
||||
// projectRepository.saveAll(dataHolder.getProjects().values());
|
||||
// }
|
||||
// if (!dataHolder.getBranches().isEmpty()) {
|
||||
// branchRepository.saveAll(dataHolder.getBranches().values());
|
||||
// }
|
||||
//
|
||||
// log.info("数据库更新完成");
|
||||
// } catch (Exception e) {
|
||||
// log.error("数据库更新失败", e);
|
||||
// throw new ApiException("数据库更新失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private CompletableFuture<Boolean> syncGroupsParallel(
|
||||
// RepositoryConfig config,
|
||||
// HttpEntity<String> entity,
|
||||
// RestTemplate restTemplate,
|
||||
// RepositorySyncDataCache dataHolder) {
|
||||
//
|
||||
// String groupsUrl = String.format("%s/api/v4/groups?per_page=100", config.getUrl());
|
||||
// try {
|
||||
// log.info("开始同步群组 - 仓库: {}", config.getName());
|
||||
//
|
||||
// ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
|
||||
// groupsUrl,
|
||||
// HttpMethod.GET,
|
||||
// entity,
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() == null) {
|
||||
// log.warn("未获取到群组数据 - 仓库: {}", config.getName());
|
||||
// return CompletableFuture.completedFuture(true);
|
||||
// }
|
||||
//
|
||||
// for (Map<String, Object> group : response.getBody()) {
|
||||
// try {
|
||||
// RepositoryGroup repositoryGroup = createGroup(config.getId(), group);
|
||||
// dataHolder.getGroups().put(repositoryGroup.getGroupId(), repositoryGroup);
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理群组失败 - 仓库: {}, 群组: {}, 错误: {}",
|
||||
// config.getName(), group.get("name"), e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log.info("群组同步完成 - 仓库: {}, 总数: {}", config.getName(), response.getBody().size());
|
||||
// return CompletableFuture.completedFuture(true);
|
||||
// } catch (Exception e) {
|
||||
// log.error("同步群组失败 - 仓库: {}, 错误: {}", config.getName(), e.getMessage());
|
||||
// return CompletableFuture.completedFuture(false);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private CompletableFuture<Boolean> syncProjectsParallel(
|
||||
// RepositoryConfig config,
|
||||
// HttpEntity<String> entity,
|
||||
// RestTemplate restTemplate,
|
||||
// Collection<RepositoryGroup> groups,
|
||||
// RepositorySyncDataCache dataHolder) {
|
||||
//
|
||||
// try {
|
||||
// log.info("开始同步项目 - 仓库: {}", config.getName());
|
||||
//
|
||||
// for (RepositoryGroup group : groups) {
|
||||
// try {
|
||||
// String projectsUrl = String.format("%s/api/v4/groups/%s/projects?per_page=100",
|
||||
// config.getUrl(), group.getGroupId());
|
||||
//
|
||||
// ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
|
||||
// projectsUrl,
|
||||
// HttpMethod.GET,
|
||||
// entity,
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() == null) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// for (Map<String, Object> project : response.getBody()) {
|
||||
// try {
|
||||
// RepositoryProject repositoryProject = createProject(config.getId(), project);
|
||||
// dataHolder.getProjects().put(repositoryProject.getProjectId(), repositoryProject);
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理项目失败 - 仓库: {}, 项目: {}, 错误: {}",
|
||||
// config.getName(), project.get("name"), e.getMessage());
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理群组项目失败 - 仓库: {}, 群组: {}, 错误: {}",
|
||||
// config.getName(), group.getName(), e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log.info("项目同步完成 - 仓库: {}", config.getName());
|
||||
// return CompletableFuture.completedFuture(true);
|
||||
// } catch (Exception e) {
|
||||
// log.error("同步项目失败 - 仓库: {}, 错误: {}", config.getName(), e.getMessage());
|
||||
// return CompletableFuture.completedFuture(false);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private CompletableFuture<Boolean> syncBranchesParallel(
|
||||
// RepositoryConfig config,
|
||||
// HttpEntity<String> entity,
|
||||
// RestTemplate restTemplate,
|
||||
// Collection<RepositoryProject> projects,
|
||||
// RepositorySyncDataCache dataHolder) {
|
||||
//
|
||||
// try {
|
||||
// log.info("开始同步分支 - 仓库: {}", config.getName());
|
||||
//
|
||||
// for (RepositoryProject project : projects) {
|
||||
// try {
|
||||
// String branchesUrl = String.format("%s/api/v4/projects/%s/repository/branches",
|
||||
// config.getUrl(), project.getProjectId());
|
||||
//
|
||||
// ResponseEntity<List<Map<String, Object>>> response = restTemplate.exchange(
|
||||
// branchesUrl,
|
||||
// HttpMethod.GET,
|
||||
// entity,
|
||||
// new ParameterizedTypeReference<>() {}
|
||||
// );
|
||||
//
|
||||
// if (response.getBody() == null) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// for (Map<String, Object> branch : response.getBody()) {
|
||||
// try {
|
||||
// RepositoryBranch repositoryBranch = createBranch(
|
||||
// config.getId(),
|
||||
// project.getProjectId().toString(),
|
||||
// branch
|
||||
// );
|
||||
// dataHolder.getBranches().put(
|
||||
// project.getProjectId() + "-" + repositoryBranch.getName(),
|
||||
// repositoryBranch
|
||||
// );
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理分支失败 - 仓库: {}, 项目: {}, 分支: {}, 错误: {}",
|
||||
// config.getName(), project.getName(), branch.get("name"), e.getMessage());
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// log.error("处理项目分支失败 - 仓库: {}, 项目: {}, 错误: {}",
|
||||
// config.getName(), project.getName(), e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log.info("分支同步完成 - 仓库: {}", config.getName());
|
||||
// return CompletableFuture.completedFuture(true);
|
||||
// } catch (Exception e) {
|
||||
// log.error("同步分支失败 - 仓库: {}, 错误: {}", config.getName(), e.getMessage());
|
||||
// return CompletableFuture.completedFuture(false);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public RepositorySyncStatusDTO getSyncStatus(Long historyId) {
|
||||
// RepositorySyncHistory history = syncHistoryRepository.findById(historyId)
|
||||
// .orElseThrow(() -> new ApiException("同步历史记录不存在"));
|
||||
//
|
||||
// return RepositorySyncStatusDTO.builder()
|
||||
// .status(history.getStatus())
|
||||
// .startTime(history.getStartTime())
|
||||
// .endTime(history.getEndTime())
|
||||
// .errorMessage(history.getErrorMessage())
|
||||
// .build();
|
||||
// }
|
||||
//
|
||||
// private void updateSyncHistory(RepositorySyncHistory history,
|
||||
// RepositorySyncHistory.SyncStatus status,
|
||||
// String errorMessage) {
|
||||
// // 更新同步历史记录
|
||||
// history.setStatus(status);
|
||||
// history.setEndTime(LocalDateTime.now());
|
||||
// history.setErrorMessage(errorMessage);
|
||||
// syncHistoryRepository.save(history);
|
||||
//
|
||||
// // 更新仓库配置的最后同步状态
|
||||
// RepositoryConfig config = configRepository.findById(history.getRepositoryId())
|
||||
// .orElse(null);
|
||||
// if (config != null) {
|
||||
// config.setLastSyncTime(history.getEndTime());
|
||||
// config.setLastSyncStatus(status);
|
||||
// configRepository.save(config);
|
||||
// log.info("更新仓库同步状态 - 仓库: {}, 状态: {}, 时间: {}",
|
||||
// config.getName(), status, history.getEndTime());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 创建群组对象(不保存到数据库)
|
||||
// private RepositoryGroup createGroup(Long repositoryId, Map<String, Object> group) {
|
||||
// RepositoryGroup repositoryGroup = new RepositoryGroup();
|
||||
// repositoryGroup.setRepositoryId(repositoryId);
|
||||
// repositoryGroup.setGroupId(Long.valueOf(group.get("id").toString()));
|
||||
// repositoryGroup.setName((String) group.get("name"));
|
||||
// repositoryGroup.setPath((String) group.get("path"));
|
||||
// repositoryGroup.setDescription((String) group.get("description"));
|
||||
// repositoryGroup.setVisibility((String) group.get("visibility"));
|
||||
// repositoryGroup.setWebUrl((String) group.get("web_url"));
|
||||
// return repositoryGroup;
|
||||
// }
|
||||
//
|
||||
// // 创建项目对象(不保存到数据库)
|
||||
// private RepositoryProject createProject(Long repositoryId, Map<String, Object> project) {
|
||||
// RepositoryProject repositoryProject = new RepositoryProject();
|
||||
// repositoryProject.setRepositoryId(repositoryId);
|
||||
// repositoryProject.setProjectId(Long.valueOf(project.get("id").toString()));
|
||||
// repositoryProject.setName((String) project.get("name"));
|
||||
// repositoryProject.setPath((String) project.get("path"));
|
||||
// repositoryProject.setDescription((String) project.get("description"));
|
||||
// repositoryProject.setVisibility((String) project.get("visibility"));
|
||||
// repositoryProject.setDefaultBranch((String) project.get("default_branch"));
|
||||
// repositoryProject.setWebUrl((String) project.get("web_url"));
|
||||
// repositoryProject.setSshUrl((String) project.get("ssh_url_to_repo"));
|
||||
// repositoryProject.setHttpUrl((String) project.get("http_url_to_repo"));
|
||||
// return repositoryProject;
|
||||
// }
|
||||
//
|
||||
// // 创建分支对象(不保存到数据库)
|
||||
// private RepositoryBranch createBranch(Long repositoryId, String projectId, Map<String, Object> branch) {
|
||||
// RepositoryBranch repositoryBranch = new RepositoryBranch();
|
||||
// repositoryBranch.setRepositoryId(repositoryId);
|
||||
// repositoryBranch.setProjectId(Long.valueOf(projectId));
|
||||
// repositoryBranch.setName((String) branch.get("name"));
|
||||
//
|
||||
// Map<String, Object> commit = (Map<String, Object>) branch.get("commit");
|
||||
// if (commit != null) {
|
||||
// repositoryBranch.setCommitId((String) commit.get("id"));
|
||||
// repositoryBranch.setCommitMessage((String) commit.get("message"));
|
||||
// repositoryBranch.setCommitAuthor((String) commit.get("author_name"));
|
||||
// String commitDate = (String) commit.get("committed_date");
|
||||
// if (commitDate != null) {
|
||||
// repositoryBranch.setCommitDate(LocalDateTime.parse(commitDate.substring(0, 19)));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// repositoryBranch.setProtected_((Boolean) branch.get("protected"));
|
||||
// repositoryBranch.setDevelopersCanPush((Boolean) branch.get("developers_can_push"));
|
||||
// repositoryBranch.setDevelopersCanMerge((Boolean) branch.get("developers_can_merge"));
|
||||
// return repositoryBranch;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void syncAll(Long repositoryId) {
|
||||
// // 为了保向后兼容,我们调用新的异步方法
|
||||
// asyncSyncAll(repositoryId);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void syncGroups(Long repositoryId) {
|
||||
// // 实现群组同步
|
||||
// log.info("开始同步群组数据, repositoryId: {}", repositoryId);
|
||||
// RepositoryConfig config = configRepository.findById(repositoryId)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// RestTemplate restTemplate = createRestTemplate();
|
||||
// HttpEntity<String> entity = createHttpEntity(config.getAccessToken());
|
||||
// RepositorySyncDataCache dataHolder = new RepositorySyncDataCache();
|
||||
//
|
||||
// try {
|
||||
// syncGroupsParallel(config, entity, restTemplate, dataHolder).get(10, TimeUnit.MINUTES);
|
||||
// updateDatabase(repositoryId, dataHolder);
|
||||
// } catch (Exception e) {
|
||||
// log.error("群组同步失败", e);
|
||||
// throw new ApiException("群组同步失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void syncProjects(Long repositoryId, Long groupId) {
|
||||
// // 实现项目同步
|
||||
// log.info("开始同步项目数据, repositoryId: {}, groupId: {}", repositoryId, groupId);
|
||||
// RepositoryConfig config = configRepository.findById(repositoryId)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// RepositoryGroup group = groupRepository.findByRepositoryIdAndGroupId(repositoryId, groupId)
|
||||
// .orElseThrow(() -> new ApiException("群组不存在"));
|
||||
//
|
||||
// RestTemplate restTemplate = createRestTemplate();
|
||||
// HttpEntity<String> entity = createHttpEntity(config.getAccessToken());
|
||||
// RepositorySyncDataCache dataHolder = new RepositorySyncDataCache();
|
||||
//
|
||||
// try {
|
||||
// List<RepositoryGroup> groups = Collections.singletonList(group);
|
||||
// syncProjectsParallel(config, entity, restTemplate, groups, dataHolder).get(10, TimeUnit.MINUTES);
|
||||
// updateDatabase(repositoryId, dataHolder);
|
||||
// } catch (Exception e) {
|
||||
// log.error("项目同步失败", e);
|
||||
// throw new ApiException("项目同步失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void syncBranches(Long repositoryId, Long projectId) {
|
||||
// // 实现分支同步
|
||||
// log.info("开始同步分支数据, repositoryId: {}, projectId: {}", repositoryId, projectId);
|
||||
// RepositoryConfig config = configRepository.findById(repositoryId)
|
||||
// .orElseThrow(() -> new ApiException("仓库配置不存在"));
|
||||
//
|
||||
// RepositoryProject project = projectRepository.findByRepositoryIdAndProjectId(repositoryId, projectId)
|
||||
// .orElseThrow(() -> new ApiException("项目不存在"));
|
||||
//
|
||||
// RestTemplate restTemplate = createRestTemplate();
|
||||
// HttpEntity<String> entity = createHttpEntity(config.getAccessToken());
|
||||
// RepositorySyncDataCache dataHolder = new RepositorySyncDataCache();
|
||||
//
|
||||
// try {
|
||||
// List<RepositoryProject> projects = Collections.singletonList(project);
|
||||
// syncBranchesParallel(config, entity, restTemplate, projects, dataHolder).get(10, TimeUnit.MINUTES);
|
||||
// updateDatabase(repositoryId, dataHolder);
|
||||
// } catch (Exception e) {
|
||||
// log.error("分支同步失败", e);
|
||||
// throw new ApiException("分支同步失败: " + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<RunningSyncDTO> getRunningSyncs() {
|
||||
// // 查询最近的50条同步历史记录
|
||||
// List<RepositorySyncHistory> histories = syncHistoryRepository
|
||||
// .findTop50ByOrderByStartTimeDesc();
|
||||
//
|
||||
// return histories.stream()
|
||||
// .map(history -> {
|
||||
// RepositoryConfig config = configRepository
|
||||
// .findById(history.getRepositoryId())
|
||||
// .orElse(null);
|
||||
//
|
||||
// // 检查任务是否真正在运行
|
||||
// boolean isActuallyRunning = RUNNING_TASKS.containsKey(history.getRepositoryId());
|
||||
//
|
||||
// // 如果数据库状态为 RUNNING 但实际未运行,更新状态为 FAILED
|
||||
// if (history.getStatus() == RepositorySyncHistory.SyncStatus.RUNNING
|
||||
// && !isActuallyRunning) {
|
||||
// history.setStatus(RepositorySyncHistory.SyncStatus.FAILED);
|
||||
// history.setErrorMessage("同步任务意外终止");
|
||||
// history.setEndTime(LocalDateTime.now());
|
||||
// syncHistoryRepository.save(history);
|
||||
// }
|
||||
//
|
||||
// return RunningSyncDTO.builder()
|
||||
// .historyId(history.getId())
|
||||
// .repositoryId(history.getRepositoryId())
|
||||
// .repositoryName(config != null ? config.getName() : "未知仓库")
|
||||
// .startTime(history.getStartTime())
|
||||
// .syncType(history.getSyncType().name())
|
||||
// .status(history.getStatus())
|
||||
// .endTime(history.getEndTime())
|
||||
// .errorMessage(history.getErrorMessage())
|
||||
// .isActuallyRunning(isActuallyRunning) // 添加实际运行状态
|
||||
// .build();
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// // ... 继续实现其他方法吗?
|
||||
//
|
||||
// /**
|
||||
// * 仓库同步数据缓存,用于在同步过程中临时存储数据
|
||||
// */
|
||||
// @Getter
|
||||
// private static class RepositorySyncDataCache {
|
||||
// // 使用 ConcurrentHashMap 确保线程安全
|
||||
// private final Map<Long, RepositoryGroup> groups = new ConcurrentHashMap<>();
|
||||
// private final Map<Long, RepositoryProject> projects = new ConcurrentHashMap<>();
|
||||
// private final Map<String, RepositoryBranch> branches = new ConcurrentHashMap<>();
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,139 @@
|
||||
//package com.qqchen.deploy.backend.service.impl;
|
||||
//
|
||||
//import com.qqchen.application.query.RoleQuery;
|
||||
//import com.qqchen.application.service.RoleService;
|
||||
//import com.qqchen.common.exception.ApiException;
|
||||
//import com.qqchen.common.service.impl.BaseServiceImpl;
|
||||
//import com.qqchen.domain.entity.Role;
|
||||
//import com.qqchen.domain.entity.RoleMenu;
|
||||
//import com.qqchen.domain.repository.RoleMenuRepository;
|
||||
//import com.qqchen.domain.repository.RoleRepository;
|
||||
//import lombok.RequiredArgsConstructor;
|
||||
//import lombok.extern.slf4j.Slf4j;
|
||||
//import org.springframework.data.jpa.repository.JpaRepository;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.transaction.annotation.Transactional;
|
||||
//
|
||||
//import java.util.List;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//@Slf4j
|
||||
//@Service
|
||||
//@RequiredArgsConstructor
|
||||
//public class RoleServiceImpl extends BaseServiceImpl<Role, RoleQuery> implements RoleService {
|
||||
//
|
||||
// private final RoleRepository roleRepository;
|
||||
// private final RoleMenuRepository roleMenuRepository;
|
||||
//
|
||||
// @Override
|
||||
// protected JpaRepository<Role, Long> getRepository() {
|
||||
// return roleRepository;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Long> getRoleMenuIds(Long roleId) {
|
||||
// return roleMenuRepository.findByRoleId(roleId)
|
||||
// .stream()
|
||||
// .map(RoleMenu::getMenuId)
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void updateRoleMenus(Long roleId, List<Long> menuIds) {
|
||||
// // 验证角色是否存在
|
||||
// Role role = findById(roleId)
|
||||
// .orElseThrow(() -> new ApiException("角色不存在"));
|
||||
//
|
||||
// // 不允许修改超级管理员的权限
|
||||
// if ("ROLE_ADMIN".equals(role.getCode())) {
|
||||
// throw new ApiException("不能修改超级管理员的权限");
|
||||
// }
|
||||
//
|
||||
// // 删除原有权限
|
||||
// roleMenuRepository.deleteByRoleId(roleId);
|
||||
//
|
||||
// // 保存新的权限
|
||||
// if (menuIds != null && !menuIds.isEmpty()) {
|
||||
// List<RoleMenu> roleMenus = menuIds.stream()
|
||||
// .map(menuId -> {
|
||||
// RoleMenu roleMenu = new RoleMenu();
|
||||
// roleMenu.setRoleId(roleId);
|
||||
// roleMenu.setMenuId(menuId);
|
||||
// return roleMenu;
|
||||
// })
|
||||
// .collect(Collectors.toList());
|
||||
// roleMenuRepository.saveAll(roleMenus);
|
||||
// }
|
||||
//
|
||||
// log.info("角色 {} 的权限已更新", role.getName());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public void delete(Long id) {
|
||||
// Role role = findById(id)
|
||||
// .orElseThrow(() -> new ApiException("角色不存在"));
|
||||
//
|
||||
// // 不允许删除超级管理员角色
|
||||
// if ("ROLE_ADMIN".equals(role.getCode())) {
|
||||
// throw new ApiException("不能删除超级管理员角色");
|
||||
// }
|
||||
//
|
||||
// // 执行软删除
|
||||
// role.setDeleted(true);
|
||||
// roleRepository.save(role);
|
||||
// log.info("角色 {} 已删除", role.getName());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public Role save(Role entity) {
|
||||
// validateCode(entity.getCode());
|
||||
// validateName(entity.getName());
|
||||
// entity.setDeleted(false);
|
||||
// return super.save(entity);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// @Transactional
|
||||
// public Role update(Long id, Role entity) {
|
||||
// Role existing = findById(id)
|
||||
// .orElseThrow(() -> new ApiException("角色不存在"));
|
||||
//
|
||||
// // 不允许修改超级管理员角色的编码
|
||||
// if ("ROLE_ADMIN".equals(existing.getCode()) && !existing.getCode().equals(entity.getCode())) {
|
||||
// throw new ApiException("不能修改超级管理员角色的编码");
|
||||
// }
|
||||
//
|
||||
// if (!existing.getCode().equals(entity.getCode())) {
|
||||
// validateCode(entity.getCode());
|
||||
// }
|
||||
// if (!existing.getName().equals(entity.getName())) {
|
||||
// validateName(entity.getName());
|
||||
// }
|
||||
//
|
||||
// entity.setVersion(existing.getVersion());
|
||||
// entity.setDeleted(existing.getDeleted());
|
||||
// return super.update(id, entity);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void validateCode(String code) {
|
||||
// if (roleRepository.existsByCodeAndDeletedFalse(code)) {
|
||||
// throw new ApiException("角色编码已存在");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void validateName(String name) {
|
||||
// if (roleRepository.existsByNameAndDeletedFalse(name)) {
|
||||
// throw new ApiException("角色名称已存在");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Role> findAll() {
|
||||
// return roleRepository.findByDeletedFalseOrderBySort();
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,113 @@
|
||||
//package com.qqchen.deploy.backend.service.impl;
|
||||
//
|
||||
//import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl;
|
||||
//import com.qqchen.deploy.backend.entity.Tenant;
|
||||
//import com.qqchen.deploy.backend.repository.ITenantRepository;
|
||||
//import com.qqchen.deploy.backend.service.ITenantService;
|
||||
//import com.querydsl.core.BooleanBuilder;
|
||||
//import jakarta.transaction.Transactional;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.util.StringUtils;
|
||||
//
|
||||
//import java.util.List;
|
||||
//
|
||||
//@Service
|
||||
//@Transactional
|
||||
//public class TenantServiceImpl extends BaseServiceImpl<Tenant, Long> implements ITenantService {
|
||||
//
|
||||
// private final ITenantRepository tenantRepository;
|
||||
//
|
||||
// public TenantServiceImpl(ITenantRepository tenantRepository) {
|
||||
// super(tenantRepository);
|
||||
// this.tenantRepository = tenantRepository;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Tenant> findAll(TenantQuery query) {
|
||||
// QTenant tenant = QTenant.tenant;
|
||||
// BooleanBuilder builder = new BooleanBuilder();
|
||||
//
|
||||
// // 基础条件:未删除
|
||||
// builder.and(tenant.deleted.eq(false));
|
||||
//
|
||||
// // 动态条件
|
||||
// if (query != null) {
|
||||
// // 名称模糊查询
|
||||
// if (StringUtils.hasText(query.getName())) {
|
||||
// builder.and(tenant.name.like("%" + query.getName().trim() + "%"));
|
||||
// }
|
||||
//
|
||||
// // 编码模糊查询
|
||||
// if (StringUtils.hasText(query.getCode())) {
|
||||
// builder.and(tenant.code.like("%" + query.getCode().trim() + "%"));
|
||||
// }
|
||||
//
|
||||
// // 状态精确查询
|
||||
// if (query.getEnabled() != null) {
|
||||
// builder.and(tenant.enabled.eq(query.getEnabled()));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 按ID排序
|
||||
// return (List<Tenant>) tenantRepository.findAll(builder, tenant.id.asc());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<Tenant> findAllEnabled() {
|
||||
// QTenant tenant = QTenant.tenant;
|
||||
// return (List<Tenant>) tenantRepository.findAll(
|
||||
// tenant.deleted.eq(false)
|
||||
// .and(tenant.enabled.eq(true)),
|
||||
// tenant.id.asc()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Tenant save(Tenant entity) {
|
||||
// validateCode(entity.getCode());
|
||||
// validateName(entity.getName());
|
||||
// entity.setDeleted(false);
|
||||
// return super.save(entity);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Tenant update(Long id, Tenant entity) {
|
||||
// Tenant existing = findById(id)
|
||||
// .orElseThrow(() -> new ApiException("租户不存在"));
|
||||
//
|
||||
// if (!existing.getCode().equals(entity.getCode())) {
|
||||
// validateCode(entity.getCode());
|
||||
// }
|
||||
// if (!existing.getName().equals(entity.getName())) {
|
||||
// validateName(entity.getName());
|
||||
// }
|
||||
//
|
||||
// entity.setVersion(existing.getVersion());
|
||||
// entity.setDeleted(existing.getDeleted());
|
||||
// return super.update(id, entity);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void validateCode(String code) {
|
||||
// if (tenantRepository.existsByCodeAndDeletedFalse(code)) {
|
||||
// throw new ApiException("租户编码已存在");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void validateName(String name) {
|
||||
// if (tenantRepository.existsByNameAndDeletedFalse(name)) {
|
||||
// throw new ApiException("租户名称已存在");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean existsByCode(String code) {
|
||||
// return tenantRepository.existsByCodeAndDeletedFalse(code);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean existsByName(String name) {
|
||||
// return tenantRepository.existsByNameAndDeletedFalse(name);
|
||||
// }
|
||||
//}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.qqchen.deploy.backend.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.entity.User;
|
||||
import com.qqchen.deploy.backend.repository.IUserRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Resource
|
||||
private final IUserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
User user = userRepository.findByUsernameAndDeletedFalse(username)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
|
||||
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
user.getUsername(),
|
||||
user.getPassword(),
|
||||
user.getEnabled(),
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER"))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -2,20 +2,20 @@ package com.qqchen.deploy.backend.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.common.service.impl.BaseServiceImpl;
|
||||
import com.qqchen.deploy.backend.entity.User;
|
||||
import com.qqchen.deploy.backend.repository.UserRepository;
|
||||
import com.qqchen.deploy.backend.service.UserService;
|
||||
import com.qqchen.deploy.backend.repository.IUserRepository;
|
||||
import com.qqchen.deploy.backend.service.IUserService;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class UserServiceImpl extends BaseServiceImpl<User, Long> implements UserService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
public class UserServiceImpl extends BaseServiceImpl<User, Long> implements IUserService {
|
||||
|
||||
private final IUserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
public UserServiceImpl(UserRepository userRepository) {
|
||||
public UserServiceImpl(IUserRepository userRepository) {
|
||||
super(userRepository);
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
|
||||
@ -3,9 +3,9 @@ server:
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://192.168.1.111:3306/deploy-ease-platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
username: deploy-ease-platform
|
||||
password: qichen5210523
|
||||
url: jdbc:mysql://127.0.0.1:3306/2024_11_24_platform?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: root
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jpa:
|
||||
hibernate:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user