Merge branch 'main' of https://demo.stam.kr/leejisun9/bio_backend
This commit is contained in:
31
README.md
31
README.md
@@ -49,6 +49,7 @@ src/main/java/com/bio/bio_backend/
|
||||
|
||||
```java
|
||||
public class ApiResponseDto<T> {
|
||||
private boolean success; // 성공/실패 여부 (true/false)
|
||||
private int code; // HTTP 상태 코드
|
||||
private String message; // 응답 메시지 (ApiResponseCode enum 값)
|
||||
private String description; // 응답 설명
|
||||
@@ -62,6 +63,7 @@ public class ApiResponseDto<T> {
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"code": 201,
|
||||
"message": "COMMON_SUCCESS_CREATED",
|
||||
"description": "Created successfully",
|
||||
@@ -77,6 +79,7 @@ public class ApiResponseDto<T> {
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"code": 409,
|
||||
"message": "USER_ID_DUPLICATE",
|
||||
"description": "User ID already exists"
|
||||
@@ -131,7 +134,8 @@ public enum ApiResponseCode {
|
||||
|
||||
- **모든 API 응답**: `ApiResponseDto<T>`로 감싸서 반환
|
||||
- **공용 응답 코드**: `COMMON_` 접두사로 시작하는 범용 코드 사용
|
||||
- **일관된 구조**: `code`, `message`, `description`, `data` 필드로 표준화
|
||||
- **일관된 구조**: `success`, `code`, `message`, `description`, `data` 필드로 표준화
|
||||
- **성공/실패 구분**: `success` 필드로 명확한 성공/실패 여부 전달
|
||||
- **제네릭 활용**: `<T>`를 통해 다양한 데이터 타입 지원
|
||||
|
||||
### 3. JWT 인증 시스템
|
||||
@@ -163,6 +167,21 @@ public enum ApiResponseCode {
|
||||
- **URL**: `http://localhost:8080/service/swagger-ui.html`
|
||||
- **API Docs**: `http://localhost:8080/service/api-docs`
|
||||
|
||||
### 5. 시스템 모니터링 (Actuator)
|
||||
|
||||
#### Health 체크
|
||||
|
||||
- **기본 Health**: `http://localhost:8080/service/actuator/health`
|
||||
- **Readiness Probe**: `http://localhost:8080/service/actuator/health/readiness`
|
||||
- **Liveness Probe**: `http://localhost:8080/service/actuator/health/liveness`
|
||||
|
||||
#### 시스템 정보
|
||||
|
||||
- **애플리케이션 정보**: `http://localhost:8080/service/actuator/info`
|
||||
- **환경 설정**: `http://localhost:8080/service/actuator/env`
|
||||
- **설정 속성**: `http://localhost:8080/service/actuator/configprops`
|
||||
- **메트릭**: `http://localhost:8080/service/actuator/metrics`
|
||||
|
||||
#### 주요 어노테이션
|
||||
|
||||
```java
|
||||
@@ -182,7 +201,7 @@ public enum ApiResponseCode {
|
||||
- **SwaggerConfig.java**: OpenAPI 기본 정보 설정
|
||||
- **application.properties**: Swagger UI 커스터마이징
|
||||
|
||||
### 5. 트랜잭션 관리
|
||||
### 6. 트랜잭션 관리
|
||||
|
||||
#### 기본 설정
|
||||
|
||||
@@ -206,7 +225,7 @@ public class MemberServiceImpl {
|
||||
- **메서드별**: 데이터 수정 시에만 `@Transactional` 개별 적용
|
||||
- **설정**: `spring.jpa.open-in-view=false` (성능 최적화)
|
||||
|
||||
### 6. 오류 등록 및 사용
|
||||
### 7. 오류 등록 및 사용
|
||||
|
||||
#### 오류 코드 등록
|
||||
|
||||
@@ -233,7 +252,7 @@ throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE);
|
||||
- **예외 클래스**: `ApiException`으로 비즈니스 로직 예외 처리
|
||||
- **자동 처리**: `GlobalExceptionHandler`가 일관된 응답 형태로 변환
|
||||
|
||||
### 7. 로깅 시스템
|
||||
### 8. 로깅 시스템
|
||||
|
||||
#### @LogExecution 어노테이션 사용법
|
||||
|
||||
@@ -287,7 +306,7 @@ public OrderDto processOrder() { }
|
||||
|
||||
**중요**: `@LogExecution` 어노테이션이 없으면 메서드 실행 로그가 출력되지 않습니다
|
||||
|
||||
### 8. MapStruct
|
||||
### 9. MapStruct
|
||||
|
||||
**매퍼 인터페이스**
|
||||
|
||||
@@ -311,7 +330,7 @@ Member entity = memberMapper.toEntity(dto);
|
||||
|
||||
**자동 생성**: 컴파일 시 `MemberMapperImpl` 구현체 생성
|
||||
|
||||
### 9. BaseEntity 상속
|
||||
### 10. BaseEntity 상속
|
||||
|
||||
**모든 엔티티는 `BaseEntity` 상속을 원칙으로 합니다.**
|
||||
|
||||
|
@@ -38,6 +38,9 @@ dependencies {
|
||||
// Validation
|
||||
implementation 'org.springframework.boot:spring-boot-starter-validation'
|
||||
|
||||
// Spring Boot Actuator
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
|
||||
// MapStruct
|
||||
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
|
||||
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
|
||||
|
@@ -1,4 +1,47 @@
|
||||
|
||||
create table st_common_code (
|
||||
sort_order integer not null,
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
created_oid bigint,
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
updated_oid bigint,
|
||||
code varchar(50) not null unique,
|
||||
group_code varchar(50) not null,
|
||||
parent_code varchar(50),
|
||||
character_ref1 varchar(100),
|
||||
character_ref2 varchar(100),
|
||||
character_ref3 varchar(100),
|
||||
character_ref4 varchar(100),
|
||||
character_ref5 varchar(100),
|
||||
name varchar(100) not null,
|
||||
description varchar(500),
|
||||
created_id varchar(255),
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create table st_common_group_code (
|
||||
sort_order integer not null,
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
created_oid bigint,
|
||||
oid bigint not null,
|
||||
updated_at timestamp(6) not null,
|
||||
updated_oid bigint,
|
||||
code varchar(50) not null unique,
|
||||
character_ref1_title varchar(100),
|
||||
character_ref2_title varchar(100),
|
||||
character_ref3_title varchar(100),
|
||||
character_ref4_title varchar(100),
|
||||
character_ref5_title varchar(100),
|
||||
name varchar(100) not null,
|
||||
created_id varchar(255),
|
||||
updated_id varchar(255),
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create table st_file (
|
||||
use_flag boolean not null,
|
||||
created_at timestamp(6) not null,
|
||||
@@ -38,5 +81,17 @@
|
||||
primary key (oid)
|
||||
);
|
||||
|
||||
create index idx_common_code_code
|
||||
on st_common_code (code);
|
||||
|
||||
create index idx_common_code_group_code
|
||||
on st_common_code (group_code);
|
||||
|
||||
create index idx_common_code_parent_code
|
||||
on st_common_code (parent_code);
|
||||
|
||||
create index idx_common_group_code_code
|
||||
on st_common_group_code (code);
|
||||
|
||||
create index idx_member_user_id
|
||||
on st_member (user_id);
|
||||
|
@@ -0,0 +1,208 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.controller;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.*;
|
||||
import com.bio.bio_backend.domain.admin.common_code.service.CommonCodeService;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonGroupCodeMapper;
|
||||
import com.bio.bio_backend.global.dto.ApiResponseDto;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.annotation.LogExecution;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.media.Content;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/admin/common-code")
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "공통 코드 관리", description = "공통 코드 및 그룹 코드 관리 API")
|
||||
public class CommonCodeController {
|
||||
|
||||
private final CommonCodeService commonCodeService;
|
||||
private final CommonCodeMapper commonCodeMapper;
|
||||
private final CommonGroupCodeMapper commonGroupCodeMapper;
|
||||
|
||||
// 그룹 코드 관련 API
|
||||
@LogExecution("그룹 코드 생성")
|
||||
@Operation(summary = "그룹 코드 생성", description = "새로운 그룹 코드를 생성합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "201", description = "그룹 코드 생성 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 그룹 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping("/group")
|
||||
public ResponseEntity<ApiResponseDto<CreateCommonGroupCodeResponseDto>> createGroupCode(@RequestBody @Valid CreateCommonGroupCodeRequestDto requestDto) {
|
||||
CommonGroupCodeDto groupCodeDto = commonGroupCodeMapper.toCommonGroupCodeDto(requestDto);
|
||||
CommonGroupCodeDto createdGroupCode = commonCodeService.createGroupCode(groupCodeDto);
|
||||
CreateCommonGroupCodeResponseDto responseDto = commonGroupCodeMapper.toCreateCommonGroupCodeResponseDto(createdGroupCode);
|
||||
ApiResponseDto<CreateCommonGroupCodeResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 수정")
|
||||
@Operation(summary = "그룹 코드 수정", description = "기존 그룹 코드를 수정합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 수정 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PutMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<String>> updateGroupCode(
|
||||
@PathVariable String code,
|
||||
@RequestBody @Valid UpdateCommonGroupCodeRequestDto requestDto) {
|
||||
CommonGroupCodeDto groupCodeDto = commonGroupCodeMapper.toCommonGroupCodeDto(requestDto);
|
||||
commonCodeService.updateGroupCode(code, groupCodeDto);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_UPDATED));
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 삭제")
|
||||
@Operation(summary = "그룹 코드 삭제", description = "그룹 코드를 삭제합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 삭제 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@DeleteMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<Void>> deleteGroupCode(@PathVariable String code) {
|
||||
commonCodeService.deleteGroupCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_DELETED));
|
||||
}
|
||||
|
||||
@LogExecution("그룹 코드 조회")
|
||||
@Operation(summary = "그룹 코드 조회", description = "특정 그룹 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹 코드 조회 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "그룹 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/group/{code}")
|
||||
public ResponseEntity<ApiResponseDto<CommonGroupCodeDto>> getGroupCode(@PathVariable String code) {
|
||||
CommonGroupCodeDto groupCode = commonCodeService.getGroupCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCode));
|
||||
}
|
||||
|
||||
@LogExecution("전체 그룹 코드 조회")
|
||||
@Operation(summary = "전체 그룹 코드 조회", description = "모든 그룹 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "전체 그룹 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonGroupCodeDto>>> getAllGroupCodes() {
|
||||
List<CommonGroupCodeDto> groupCodes = commonCodeService.getAllGroupCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCodes));
|
||||
}
|
||||
|
||||
@LogExecution("활성 그룹 코드 조회")
|
||||
@Operation(summary = "활성 그룹 코드 조회", description = "사용 중인 그룹 코드만 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "활성 그룹 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group/active")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonGroupCodeDto>>> getActiveGroupCodes() {
|
||||
List<CommonGroupCodeDto> groupCodes = commonCodeService.getActiveGroupCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, groupCodes));
|
||||
}
|
||||
|
||||
// 공통 코드 관련 API
|
||||
@LogExecution("공통 코드 생성")
|
||||
@Operation(summary = "공통 코드 생성", description = "새로운 공통 코드를 생성합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "201", description = "공통 코드 생성 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "409", description = "중복된 공통 코드", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponseDto<CreateCommonCodeResponseDto>> createCode(@RequestBody @Valid CreateCommonCodeRequestDto requestDto) {
|
||||
CommonCodeDto commonCodeDto = commonCodeMapper.toCommonCodeDto(requestDto);
|
||||
CommonCodeDto createdCommonCode = commonCodeService.createCode(commonCodeDto);
|
||||
CreateCommonCodeResponseDto responseDto = commonCodeMapper.toCreateCommonCodeResponseDto(createdCommonCode);
|
||||
ApiResponseDto<CreateCommonCodeResponseDto> apiResponse = ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_CREATED, responseDto);
|
||||
|
||||
return ResponseEntity.status(HttpStatus.CREATED).body(apiResponse);
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 수정")
|
||||
@Operation(summary = "공통 코드 수정", description = "기존 공통 코드를 수정합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 수정 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@PutMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<String>> updateCode(
|
||||
@PathVariable String code,
|
||||
@RequestBody @Valid UpdateCommonCodeRequestDto requestDto) {
|
||||
CommonCodeDto commonCodeDto = commonCodeMapper.toCommonCodeDto(requestDto);
|
||||
commonCodeService.updateCode(code, commonCodeDto);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_UPDATED));
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 삭제")
|
||||
@Operation(summary = "공통 코드 삭제", description = "공통 코드를 삭제합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 삭제 성공"),
|
||||
@ApiResponse(responseCode = "400", description = "하위 공통 코드가 존재하여 삭제할 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class))),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@DeleteMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<Void>> deleteCode(@PathVariable String code) {
|
||||
commonCodeService.deleteCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_DELETED));
|
||||
}
|
||||
|
||||
@LogExecution("공통 코드 조회")
|
||||
@Operation(summary = "공통 코드 조회", description = "특정 공통 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "공통 코드 조회 성공"),
|
||||
@ApiResponse(responseCode = "404", description = "공통 코드를 찾을 수 없음", content = @Content(schema = @Schema(implementation = ApiResponseDto.class)))
|
||||
})
|
||||
@GetMapping("/{code}")
|
||||
public ResponseEntity<ApiResponseDto<CommonCodeDto>> getCode(@PathVariable String code) {
|
||||
CommonCodeDto commonCode = commonCodeService.getCode(code);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCode));
|
||||
}
|
||||
|
||||
@LogExecution("그룹별 공통 코드 조회")
|
||||
@Operation(summary = "그룹별 공통 코드 조회", description = "특정 그룹에 속한 공통 코드들을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "그룹별 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/group/{groupCode}/codes")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getCodesByGroupCode(@PathVariable String groupCode) {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getActiveCodesByGroupCode(groupCode);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
|
||||
@LogExecution("상위 코드별 공통 코드 조회")
|
||||
@Operation(summary = "상위 코드별 공통 코드 조회", description = "특정 상위 코드에 속한 공통 코드들을 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "상위 코드별 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping("/parent/{parentCode}/codes")
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getCodesByParentCode(@PathVariable String parentCode) {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getActiveCodesByParentCode(parentCode);
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
|
||||
@LogExecution("전체 공통 코드 조회")
|
||||
@Operation(summary = "전체 공통 코드 조회", description = "모든 공통 코드를 조회합니다.")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "전체 공통 코드 조회 성공")
|
||||
})
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponseDto<List<CommonCodeDto>>> getAllCodes() {
|
||||
List<CommonCodeDto> commonCodes = commonCodeService.getAllCodes();
|
||||
return ResponseEntity.ok(ApiResponseDto.success(ApiResponseCode.COMMON_SUCCESS_RETRIEVED, commonCodes));
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonCodeDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String description;
|
||||
private String groupCode;
|
||||
private String parentCode;
|
||||
private String characterRef1;
|
||||
private String characterRef2;
|
||||
private String characterRef3;
|
||||
private String characterRef4;
|
||||
private String characterRef5;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommonGroupCodeDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String characterRef1Title;
|
||||
private String characterRef2Title;
|
||||
private String characterRef3Title;
|
||||
private String characterRef4Title;
|
||||
private String characterRef5Title;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "코드는 필수입니다")
|
||||
@Size(max = 50, message = "코드는 50자를 초과할 수 없습니다")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 500, message = "설명은 500자를 초과할 수 없습니다")
|
||||
private String description;
|
||||
|
||||
@NotBlank(message = "그룹 코드는 필수입니다")
|
||||
@Size(max = 50, message = "그룹 코드는 50자를 초과할 수 없습니다")
|
||||
private String groupCode;
|
||||
|
||||
@Size(max = 50, message = "상위 코드는 50자를 초과할 수 없습니다")
|
||||
private String parentCode;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2는 100자를 초과할 수 없습니다")
|
||||
private String characterRef2;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4는 100자를 초과할 수 없습니다")
|
||||
private String characterRef4;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5는 100자를 초과할 수 없습니다")
|
||||
private String characterRef5;
|
||||
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonCodeResponseDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String description;
|
||||
private String groupCode;
|
||||
private String parentCode;
|
||||
private String characterRef1;
|
||||
private String characterRef2;
|
||||
private String characterRef3;
|
||||
private String characterRef4;
|
||||
private String characterRef5;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonGroupCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "코드는 필수입니다")
|
||||
@Size(max = 50, message = "코드는 50자를 초과할 수 없습니다")
|
||||
private String code;
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 100, message = "차트 참조1 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조2 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef2Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조3 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조4 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef4Title;
|
||||
|
||||
@Size(max = 100, message = "차트 참조5 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef5Title;
|
||||
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CreateCommonGroupCodeResponseDto {
|
||||
|
||||
private Long oid;
|
||||
private String code;
|
||||
private String name;
|
||||
private String characterRef1Title;
|
||||
private String characterRef2Title;
|
||||
private String characterRef3Title;
|
||||
private String characterRef4Title;
|
||||
private String characterRef5Title;
|
||||
private Integer sortOrder;
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateCommonCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 500, message = "설명은 500자를 초과할 수 없습니다")
|
||||
private String description;
|
||||
|
||||
@NotBlank(message = "그룹 코드는 필수입니다")
|
||||
@Size(max = 50, message = "그룹 코드는 50자를 초과할 수 없습니다")
|
||||
private String groupCode;
|
||||
|
||||
@Size(max = 50, message = "상위 코드는 50자를 초과할 수 없습니다")
|
||||
private String parentCode;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2는 100자를 초과할 수 없습니다")
|
||||
private String characterRef2;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4는 100자를 초과할 수 없습니다")
|
||||
private String characterRef4;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5는 100자를 초과할 수 없습니다")
|
||||
private String characterRef5;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.Size;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UpdateCommonGroupCodeRequestDto {
|
||||
|
||||
@NotBlank(message = "이름은 필수입니다")
|
||||
@Size(max = 100, message = "이름은 100자를 초과할 수 없습니다")
|
||||
private String name;
|
||||
|
||||
@Size(max = 100, message = "문자 참조1 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef1Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조2 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef2Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조3 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef3Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조4 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef4Title;
|
||||
|
||||
@Size(max = 100, message = "문자 참조5 제목은 100자를 초과할 수 없습니다")
|
||||
private String characterRef5Title;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
private Boolean useFlag;
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.entity;
|
||||
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = AppConstants.TABLE_PREFIX + "common_code",
|
||||
indexes = {
|
||||
@Index(name = "idx_common_code_code", columnList = "code"),
|
||||
@Index(name = "idx_common_code_group_code", columnList = "group_code"),
|
||||
@Index(name = "idx_common_code_parent_code", columnList = "parent_code")
|
||||
}
|
||||
)
|
||||
public class CommonCode extends BaseEntity {
|
||||
|
||||
@Column(name = "code", nullable = false, length = 50, unique = true)
|
||||
private String code;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "description", length = 500)
|
||||
private String description;
|
||||
|
||||
@Column(name = "group_code", nullable = false, length = 50)
|
||||
private String groupCode;
|
||||
|
||||
@Column(name = "parent_code", length = 50)
|
||||
private String parentCode;
|
||||
|
||||
@Column(name = "character_ref1", length = 100)
|
||||
private String characterRef1;
|
||||
|
||||
@Column(name = "character_ref2", length = 100)
|
||||
private String characterRef2;
|
||||
|
||||
@Column(name = "character_ref3", length = 100)
|
||||
private String characterRef3;
|
||||
|
||||
@Column(name = "character_ref4", length = 100)
|
||||
private String characterRef4;
|
||||
|
||||
@Column(name = "character_ref5", length = 100)
|
||||
private String characterRef5;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Column(name = "use_flag", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
|
||||
// 관계 설정
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(
|
||||
name = "group_code",
|
||||
referencedColumnName = "code",
|
||||
insertable = false,
|
||||
updatable = false,
|
||||
foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT)
|
||||
)
|
||||
private CommonGroupCode commonGroupCode;
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.entity;
|
||||
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
import com.bio.bio_backend.global.entity.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@Getter @Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@Table(
|
||||
name = AppConstants.TABLE_PREFIX + "common_group_code",
|
||||
indexes = {
|
||||
@Index(name = "idx_common_group_code_code", columnList = "code")
|
||||
}
|
||||
)
|
||||
public class CommonGroupCode extends BaseEntity {
|
||||
|
||||
@Column(name = "code", nullable = false, length = 50, unique = true)
|
||||
private String code;
|
||||
|
||||
@Column(name = "name", nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "character_ref1_title", length = 100)
|
||||
private String characterRef1Title;
|
||||
|
||||
@Column(name = "character_ref2_title", length = 100)
|
||||
private String characterRef2Title;
|
||||
|
||||
@Column(name = "character_ref3_title", length = 100)
|
||||
private String characterRef3Title;
|
||||
|
||||
@Column(name = "character_ref4_title", length = 100)
|
||||
private String characterRef4Title;
|
||||
|
||||
@Column(name = "character_ref5_title", length = 100)
|
||||
private String characterRef5Title;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
@Builder.Default
|
||||
private Integer sortOrder = 0;
|
||||
|
||||
@Column(name = "use_flag", nullable = false)
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonCodeResponseDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.UpdateCommonCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface CommonCodeMapper {
|
||||
|
||||
/**
|
||||
* CommonCode 엔티티를 CommonCodeDto로 변환
|
||||
*/
|
||||
CommonCodeDto toCommonCodeDto(CommonCode commonCode);
|
||||
|
||||
/**
|
||||
* CommonCodeDto를 CommonCode 엔티티로 변환
|
||||
*/
|
||||
@Mapping(target = "commonGroupCode", ignore = true)
|
||||
CommonCode toCommonCode(CommonCodeDto commonCodeDto);
|
||||
|
||||
/**
|
||||
* CommonCode 엔티티 리스트를 CommonCodeDto 리스트로 변환
|
||||
*/
|
||||
List<CommonCodeDto> toCommonCodeDtoList(List<CommonCode> commonCodes);
|
||||
|
||||
/**
|
||||
* CommonCodeDto를 CreateCommonCodeResponseDto로 변환
|
||||
*/
|
||||
CreateCommonCodeResponseDto toCreateCommonCodeResponseDto(CommonCodeDto commonCodeDto);
|
||||
|
||||
/**
|
||||
* CreateCommonCodeRequestDto를 CommonCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
CommonCodeDto toCommonCodeDto(CreateCommonCodeRequestDto createRequestDto);
|
||||
|
||||
/**
|
||||
* UpdateCommonCodeRequestDto를 CommonCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "code", ignore = true)
|
||||
CommonCodeDto toCommonCodeDto(UpdateCommonCodeRequestDto updateRequestDto);
|
||||
|
||||
/**
|
||||
* CommonCodeDto의 값으로 CommonCode 엔티티를 업데이트
|
||||
*/
|
||||
@IgnoreBaseEntityMapping
|
||||
@Mapping(target = "commonGroupCode", ignore = true)
|
||||
void updateCommonCodeFromDto(CommonCodeDto commonCodeDto, @org.mapstruct.MappingTarget CommonCode commonCode);
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.mapper;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonGroupCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CreateCommonGroupCodeResponseDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.UpdateCommonGroupCodeRequestDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface CommonGroupCodeMapper {
|
||||
|
||||
/**
|
||||
* CommonGroupCode 엔티티를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(CommonGroupCode commonGroupCode);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto를 CommonGroupCode 엔티티로 변환
|
||||
*/
|
||||
CommonGroupCode toCommonGroupCode(CommonGroupCodeDto commonGroupCodeDto);
|
||||
|
||||
/**
|
||||
* CommonGroupCode 엔티티 리스트를 CommonGroupCodeDto 리스트로 변환
|
||||
*/
|
||||
List<CommonGroupCodeDto> toCommonGroupCodeDtoList(List<CommonGroupCode> commonGroupCodes);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto를 CreateCommonGroupCodeResponseDto로 변환
|
||||
*/
|
||||
CreateCommonGroupCodeResponseDto toCreateCommonGroupCodeResponseDto(CommonGroupCodeDto commonGroupCodeDto);
|
||||
|
||||
/**
|
||||
* CreateCommonGroupCodeRequestDto를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(CreateCommonGroupCodeRequestDto createRequestDto);
|
||||
|
||||
/**
|
||||
* UpdateCommonGroupCodeRequestDto를 CommonGroupCodeDto로 변환
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "code", ignore = true)
|
||||
CommonGroupCodeDto toCommonGroupCodeDto(UpdateCommonGroupCodeRequestDto updateRequestDto);
|
||||
|
||||
/**
|
||||
* CommonGroupCodeDto의 값으로 CommonGroupCode 엔티티를 업데이트
|
||||
*/
|
||||
@IgnoreBaseEntityMapping
|
||||
void updateCommonGroupCodeFromDto(CommonGroupCodeDto commonGroupCodeDto, @org.mapstruct.MappingTarget CommonGroupCode commonGroupCode);
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CommonCodeRepository extends JpaRepository<CommonCode, Long> {
|
||||
|
||||
Optional<CommonCode> findByCode(String code);
|
||||
|
||||
List<CommonCode> findByGroupCodeAndUseFlagOrderBySortOrderAsc(String groupCode, Boolean useFlag);
|
||||
|
||||
List<CommonCode> findByParentCodeAndUseFlagOrderBySortOrderAsc(String parentCode, Boolean useFlag);
|
||||
|
||||
@Query("SELECT cc FROM CommonCode cc WHERE cc.groupCode = :groupCode AND cc.useFlag = :useFlag ORDER BY cc.sortOrder ASC")
|
||||
List<CommonCode> findActiveCodesByGroupCodeOrderBySortOrder(@Param("groupCode") String groupCode, @Param("useFlag") Boolean useFlag);
|
||||
|
||||
@Query("SELECT cc FROM CommonCode cc WHERE cc.parentCode = :parentCode AND cc.useFlag = :useFlag ORDER BY cc.sortOrder ASC")
|
||||
List<CommonCode> findActiveCodesByParentCodeOrderBySortOrder(@Param("parentCode") String parentCode, @Param("useFlag") Boolean useFlag);
|
||||
|
||||
boolean existsByCode(String code);
|
||||
|
||||
boolean existsByGroupCode(String groupCode);
|
||||
|
||||
boolean existsByParentCode(String parentCode);
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.repository;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface CommonGroupCodeRepository extends JpaRepository<CommonGroupCode, Long> {
|
||||
|
||||
Optional<CommonGroupCode> findByCode(String code);
|
||||
|
||||
List<CommonGroupCode> findByUseFlagOrderBySortOrderAsc(Boolean useFlag);
|
||||
|
||||
@Query("SELECT cgc FROM CommonGroupCode cgc WHERE cgc.useFlag = :useFlag ORDER BY cgc.sortOrder ASC")
|
||||
List<CommonGroupCode> findActiveGroupCodesOrderBySortOrder(@Param("useFlag") Boolean useFlag);
|
||||
|
||||
boolean existsByCode(String code);
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.service;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommonCodeService {
|
||||
|
||||
// 그룹 코드 관련
|
||||
CommonGroupCodeDto createGroupCode(CommonGroupCodeDto groupCodeDto);
|
||||
void updateGroupCode(String code, CommonGroupCodeDto groupCodeDto);
|
||||
void deleteGroupCode(String code);
|
||||
CommonGroupCodeDto getGroupCode(String code);
|
||||
List<CommonGroupCodeDto> getAllGroupCodes();
|
||||
List<CommonGroupCodeDto> getActiveGroupCodes();
|
||||
|
||||
// 공통 코드 관련
|
||||
CommonCodeDto createCode(CommonCodeDto codeDto);
|
||||
void updateCode(String code, CommonCodeDto codeDto);
|
||||
void deleteCode(String code);
|
||||
CommonCodeDto getCode(String code);
|
||||
List<CommonCodeDto> getCodesByGroupCode(String groupCode);
|
||||
List<CommonCodeDto> getActiveCodesByGroupCode(String groupCode);
|
||||
List<CommonCodeDto> getCodesByParentCode(String parentCode);
|
||||
List<CommonCodeDto> getActiveCodesByParentCode(String parentCode);
|
||||
List<CommonCodeDto> getAllCodes();
|
||||
}
|
@@ -0,0 +1,166 @@
|
||||
package com.bio.bio_backend.domain.admin.common_code.service;
|
||||
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.dto.CommonGroupCodeDto;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonCode;
|
||||
import com.bio.bio_backend.domain.admin.common_code.entity.CommonGroupCode;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.mapper.CommonGroupCodeMapper;
|
||||
import com.bio.bio_backend.domain.admin.common_code.repository.CommonCodeRepository;
|
||||
import com.bio.bio_backend.domain.admin.common_code.repository.CommonGroupCodeRepository;
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
import com.bio.bio_backend.global.exception.ApiException;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(readOnly = true)
|
||||
public class CommonCodeServiceImpl implements CommonCodeService {
|
||||
|
||||
private final CommonGroupCodeRepository commonGroupCodeRepository;
|
||||
private final CommonCodeRepository commonCodeRepository;
|
||||
private final CommonCodeMapper commonCodeMapper;
|
||||
private final CommonGroupCodeMapper commonGroupCodeMapper;
|
||||
|
||||
// 그룹 코드 관련 메서드들
|
||||
@Override
|
||||
@Transactional
|
||||
public CommonGroupCodeDto createGroupCode(CommonGroupCodeDto groupCodeDto) {
|
||||
if (commonGroupCodeRepository.existsByCode(groupCodeDto.getCode())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_CODE_DUPLICATE);
|
||||
}
|
||||
|
||||
CommonGroupCode groupCode = commonGroupCodeMapper.toCommonGroupCode(groupCodeDto);
|
||||
CommonGroupCode savedGroupCode = commonGroupCodeRepository.save(groupCode);
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDto(savedGroupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateGroupCode(String code, CommonGroupCodeDto groupCodeDto) {
|
||||
CommonGroupCode existingGroupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
commonGroupCodeMapper.updateCommonGroupCodeFromDto(groupCodeDto, existingGroupCode);
|
||||
commonGroupCodeRepository.save(existingGroupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteGroupCode(String code) {
|
||||
CommonGroupCode groupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
// 하위 공통 코드가 있는지 확인
|
||||
if (commonCodeRepository.existsByGroupCode(code)) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "하위 공통 코드가 존재하여 삭제할 수 없습니다: " + code);
|
||||
}
|
||||
|
||||
commonGroupCodeRepository.delete(groupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonGroupCodeDto getGroupCode(String code) {
|
||||
CommonGroupCode groupCode = commonGroupCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "그룹 코드를 찾을 수 없습니다: " + code));
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDto(groupCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonGroupCodeDto> getAllGroupCodes() {
|
||||
List<CommonGroupCode> groupCodes = commonGroupCodeRepository.findAll();
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDtoList(groupCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonGroupCodeDto> getActiveGroupCodes() {
|
||||
List<CommonGroupCode> groupCodes = commonGroupCodeRepository.findByUseFlagOrderBySortOrderAsc(true);
|
||||
return commonGroupCodeMapper.toCommonGroupCodeDtoList(groupCodes);
|
||||
}
|
||||
|
||||
// 공통 코드 관련 메서드들
|
||||
@Override
|
||||
@Transactional
|
||||
public CommonCodeDto createCode(CommonCodeDto commonCodeDto) {
|
||||
if (commonCodeRepository.existsByCode(commonCodeDto.getCode())) {
|
||||
throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE, "이미 존재하는 공통 코드입니다: " + commonCodeDto.getCode());
|
||||
}
|
||||
|
||||
// 그룹 코드 존재 여부 확인
|
||||
if (!commonGroupCodeRepository.existsByCode(commonCodeDto.getGroupCode())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "존재하지 않는 그룹 코드입니다: " + commonCodeDto.getGroupCode());
|
||||
}
|
||||
|
||||
CommonCode commonCode = commonCodeMapper.toCommonCode(commonCodeDto);
|
||||
CommonCode savedCommonCode = commonCodeRepository.save(commonCode);
|
||||
return commonCodeMapper.toCommonCodeDto(savedCommonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateCode(String code, CommonCodeDto commonCodeDto) {
|
||||
CommonCode existingCommonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
commonCodeMapper.updateCommonCodeFromDto(commonCodeDto, existingCommonCode);
|
||||
commonCodeRepository.save(existingCommonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteCode(String code) {
|
||||
CommonCode commonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
|
||||
// 하위 공통 코드가 있는지 확인
|
||||
if (commonCodeRepository.existsByParentCode(code)) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_BAD_REQUEST, "하위 공통 코드가 존재하여 삭제할 수 없습니다: " + code);
|
||||
}
|
||||
|
||||
commonCodeRepository.delete(commonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonCodeDto getCode(String code) {
|
||||
CommonCode commonCode = commonCodeRepository.findByCode(code)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.COMMON_NOT_FOUND, "공통 코드를 찾을 수 없습니다: " + code));
|
||||
return commonCodeMapper.toCommonCodeDto(commonCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getCodesByGroupCode(String groupCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findByGroupCodeAndUseFlagOrderBySortOrderAsc(groupCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getActiveCodesByGroupCode(String groupCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findActiveCodesByGroupCodeOrderBySortOrder(groupCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getCodesByParentCode(String parentCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findByParentCodeAndUseFlagOrderBySortOrderAsc(parentCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getActiveCodesByParentCode(String parentCode) {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findActiveCodesByParentCodeOrderBySortOrder(parentCode, true);
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CommonCodeDto> getAllCodes() {
|
||||
List<CommonCode> commonCodes = commonCodeRepository.findAll();
|
||||
return commonCodeMapper.toCommonCodeDtoList(commonCodes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class FileUploadDto {
|
||||
private Long groupOid;
|
||||
private List<FileUploadResponseDto> files; // 파일 정보들
|
||||
private int totalCount;
|
||||
private int successCount;
|
||||
private int failureCount;
|
||||
private List<String> errorMessages;
|
||||
}
|
@@ -7,5 +7,4 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
public class FileUploadRequestDto {
|
||||
private MultipartFile file;
|
||||
private String description;
|
||||
private Long groupOid;
|
||||
}
|
||||
|
@@ -1,12 +1,15 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class FileUploadResponseDto {
|
||||
private Long oid;
|
||||
private Long groupOid;
|
||||
private String originalFileName;
|
||||
private String downloadUrl;
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package com.bio.bio_backend.domain.base.file.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class MultipleFileUploadRequestDto {
|
||||
private List<MultipartFile> files;
|
||||
private String description;
|
||||
|
@@ -8,6 +8,7 @@ import java.util.List;
|
||||
@Builder
|
||||
public class MultipleFileUploadResponseDto {
|
||||
private List<FileUploadResponseDto> files;
|
||||
private Long groupOid;
|
||||
private int totalCount;
|
||||
private int successCount;
|
||||
private int failureCount;
|
||||
|
@@ -57,7 +57,12 @@ public class FileServiceImpl implements FileService {
|
||||
File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), generateOid());
|
||||
|
||||
// 응답 DTO 생성 및 반환
|
||||
return createUploadResponse(savedFile);
|
||||
return FileUploadResponseDto.builder()
|
||||
.oid(savedFile.getOid())
|
||||
.groupOid(savedFile.getGroupOid())
|
||||
.originalFileName(savedFile.getOriginalFileName())
|
||||
.downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,7 +95,11 @@ public class FileServiceImpl implements FileService {
|
||||
|
||||
// 단일 파일 업로드 처리
|
||||
File savedFile = processFileUpload(multipartFile, requestDto.getDescription(), groupOid);
|
||||
FileUploadResponseDto uploadedFile = createUploadResponse(savedFile);
|
||||
FileUploadResponseDto uploadedFile = FileUploadResponseDto.builder()
|
||||
.oid(savedFile.getOid())
|
||||
.originalFileName(savedFile.getOriginalFileName())
|
||||
.downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
|
||||
.build();
|
||||
|
||||
uploadedFiles.add(uploadedFile);
|
||||
successCount++;
|
||||
@@ -105,8 +114,8 @@ public class FileServiceImpl implements FileService {
|
||||
}
|
||||
}
|
||||
|
||||
// 다중 파일 업로드 결과 반환
|
||||
return MultipleFileUploadResponseDto.builder()
|
||||
.groupOid(groupOid)
|
||||
.files(uploadedFiles)
|
||||
.totalCount(files.size())
|
||||
.successCount(successCount)
|
||||
@@ -135,7 +144,6 @@ public class FileServiceImpl implements FileService {
|
||||
|
||||
// DB에 파일 정보 저장
|
||||
File file = createFileEntity(originalFileName, storedFileName, targetLocation, multipartFile, description, groupOid);
|
||||
file.setCreator(SecurityUtils.getCurrentUserOid(), SecurityUtils.getCurrentUserId());
|
||||
|
||||
return fileRepository.save(file);
|
||||
|
||||
@@ -158,14 +166,6 @@ public class FileServiceImpl implements FileService {
|
||||
.build();
|
||||
}
|
||||
|
||||
private FileUploadResponseDto createUploadResponse(File savedFile) {
|
||||
return FileUploadResponseDto.builder()
|
||||
.oid(savedFile.getOid())
|
||||
.originalFileName(savedFile.getOriginalFileName())
|
||||
.downloadUrl(contextPath + "/files/download/" + savedFile.getOid())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getFileByOid(Long oid) {
|
||||
return fileRepository.findByOidAndUseFlagTrue(oid)
|
||||
@@ -192,16 +192,12 @@ public class FileServiceImpl implements FileService {
|
||||
File file = fileRepository.findByOidAndUseFlagTrue(oid)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.FILE_NOT_FOUND));
|
||||
|
||||
Long currentUserOid = SecurityUtils.getCurrentUserOid();
|
||||
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||
// 현재 사용자가 파일 소유자인지 확인
|
||||
if (currentUserId == null || !currentUserId.equals(file.getCreatedId())) {
|
||||
throw new ApiException(ApiResponseCode.COMMON_FORBIDDEN);
|
||||
}
|
||||
|
||||
// 수정자 정보 업데이트
|
||||
file.setUpdater(currentUserOid, currentUserId);
|
||||
|
||||
// 논리적 삭제: use_flag를 false로 변경
|
||||
file.setUseFlag(false);
|
||||
fileRepository.save(file);
|
||||
|
@@ -5,16 +5,15 @@ import com.bio.bio_backend.domain.base.member.dto.CreateMemberResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import com.bio.bio_backend.global.annotation.IgnoreBaseEntityMapping;
|
||||
import com.bio.bio_backend.global.config.GlobalMapperConfig;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
@Mapper(config = GlobalMapperConfig.class)
|
||||
public interface MemberMapper {
|
||||
|
||||
MemberMapper INSTANCE = Mappers.getMapper(MemberMapper.class);
|
||||
|
||||
/**
|
||||
* CreateMemberRequestDto를 MemberDto로 변환
|
||||
* 기본값 설정: role = MemberRole.MEMBER, useFlag = true
|
||||
|
@@ -8,6 +8,7 @@ import com.bio.bio_backend.domain.base.member.repository.MemberRepository;
|
||||
import com.bio.bio_backend.global.exception.ApiException;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.constants.AppConstants;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
@@ -19,8 +20,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@@ -54,9 +53,10 @@ public class MemberServiceImpl implements MemberService {
|
||||
.role(MemberRole.getDefault())
|
||||
.build();
|
||||
|
||||
Long oid = generateOid();
|
||||
member.setOid(oid);
|
||||
member.setCreator(AppConstants.ADMIN_OID, AppConstants.ADMIN_USER_ID);
|
||||
member.setCreatedOid(AppConstants.ADMIN_OID);
|
||||
member.setCreatedId(AppConstants.ADMIN_USER_ID);
|
||||
member.setUpdatedOid(AppConstants.ADMIN_OID);
|
||||
member.setUpdatedId(AppConstants.ADMIN_USER_ID);
|
||||
|
||||
Member savedMember = memberRepository.save(member);
|
||||
|
||||
|
@@ -0,0 +1,21 @@
|
||||
package com.bio.bio_backend.global.config;
|
||||
|
||||
import org.mapstruct.*;
|
||||
|
||||
@MapperConfig(
|
||||
componentModel = "spring",
|
||||
|
||||
// null 값은 매핑하지 않음 (부분 업데이트)
|
||||
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
|
||||
|
||||
// NPE 방지용 null 체크
|
||||
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
|
||||
|
||||
// 매핑 누락 시 컴파일 오류
|
||||
unmappedTargetPolicy = ReportingPolicy.ERROR,
|
||||
|
||||
// 컬렉션 매핑 전략
|
||||
collectionMappingStrategy = CollectionMappingStrategy.ACCESSOR_ONLY
|
||||
)
|
||||
public interface GlobalMapperConfig {
|
||||
}
|
@@ -14,7 +14,7 @@ public enum ApiResponseCode {
|
||||
|
||||
/*공통 Code*/
|
||||
// 200 OK
|
||||
COMMON_SUCCESS(HttpStatus.OK.value(), "요청 성공"),
|
||||
COMMON_SUCCESS(HttpStatus.OK.value(), "요청을 성공하였습니다"),
|
||||
COMMON_SUCCESS_CREATED(HttpStatus.CREATED.value(), "성공적으로 생성되었습니다"),
|
||||
COMMON_SUCCESS_UPDATED(HttpStatus.OK.value(), "성공적으로 수정되었습니다"),
|
||||
COMMON_SUCCESS_DELETED(HttpStatus.OK.value(), "성공적으로 삭제되었습니다"),
|
||||
@@ -39,6 +39,7 @@ public enum ApiResponseCode {
|
||||
|
||||
// 409 Conflict
|
||||
COMMON_CONFLICT(HttpStatus.CONFLICT.value(), "충돌이 발생했습니다"),
|
||||
COMMON_CODE_DUPLICATE(HttpStatus.CONFLICT.value(), "동일한 코드가 존재합니다"),
|
||||
|
||||
// 500 Internal Server Error
|
||||
COMMON_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버에서 오류가 발생했습니다"),
|
||||
|
@@ -12,14 +12,17 @@ import lombok.RequiredArgsConstructor;
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class ApiResponseDto<T> {
|
||||
|
||||
private static final boolean SUCCESS = true;
|
||||
private static final boolean FAIL = false;
|
||||
|
||||
private boolean success;
|
||||
private int code;
|
||||
private String message;
|
||||
private String description;
|
||||
private T data;
|
||||
|
||||
private static final int SUCCESS = 200;
|
||||
|
||||
private ApiResponseDto(int code, String message, String description, T data){
|
||||
private ApiResponseDto(boolean success, int code, String message, String description, T data){
|
||||
this.success = success;
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.description = description;
|
||||
@@ -27,19 +30,19 @@ public class ApiResponseDto<T> {
|
||||
}
|
||||
|
||||
public static <T> ApiResponseDto<T> success(ApiResponseCode responseCode, T data) {
|
||||
return new ApiResponseDto<T>(SUCCESS, responseCode.name(), responseCode.getDescription(), data);
|
||||
return new ApiResponseDto<T>(SUCCESS, responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), data);
|
||||
}
|
||||
|
||||
public static <T> ApiResponseDto<T> success(ApiResponseCode responseCode) {
|
||||
return new ApiResponseDto<T>(SUCCESS, responseCode.name(), responseCode.getDescription(), null);
|
||||
return new ApiResponseDto<T>(SUCCESS, responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), null);
|
||||
}
|
||||
|
||||
public static <T> ApiResponseDto<T> fail(ApiResponseCode responseCode, T data) {
|
||||
return new ApiResponseDto<T>(responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), data);
|
||||
return new ApiResponseDto<T>(FAIL, responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), data);
|
||||
}
|
||||
|
||||
public static <T> ApiResponseDto<T> fail(ApiResponseCode responseCode) {
|
||||
return new ApiResponseDto<T>(responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), null);
|
||||
return new ApiResponseDto<T>(FAIL, responseCode.getStatusCode(), responseCode.name(), responseCode.getDescription(), null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
|
||||
|
||||
|
||||
/**
|
||||
* 모든 엔티티가 상속받는 기본 엔티티 클래스
|
||||
@@ -18,7 +18,7 @@ import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
|
||||
@Getter
|
||||
@Setter
|
||||
@MappedSuperclass
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
@EntityListeners({AuditingEntityListener.class, BaseEntityListener.class})
|
||||
public abstract class BaseEntity {
|
||||
|
||||
@Id
|
||||
@@ -45,31 +45,4 @@ public abstract class BaseEntity {
|
||||
@Column(name = "updated_id")
|
||||
private String updatedId;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
if(this.oid == null) this.oid = generateOid();
|
||||
if(this.createdOid != null && this.updatedOid == null) this.updatedOid = this.createdOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 생성자 정보를 설정합니다.
|
||||
* @param createdOid 생성자 OID
|
||||
* @param createdId 생성자 ID
|
||||
*/
|
||||
public void setCreator(Long createdOid, String createdId) {
|
||||
this.createdOid = createdOid;
|
||||
this.createdId = createdId;
|
||||
this.updatedOid = createdOid;
|
||||
this.updatedId = createdId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 수정자 정보를 설정합니다.
|
||||
* @param updatedOid 수정자 OID
|
||||
* @param updatedId 수정자 ID
|
||||
*/
|
||||
public void setUpdater(Long updatedOid, String updatedId) {
|
||||
this.updatedOid = updatedOid;
|
||||
this.updatedId = updatedId;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
package com.bio.bio_backend.global.entity;
|
||||
|
||||
import com.bio.bio_backend.global.utils.SecurityUtils;
|
||||
import jakarta.persistence.PrePersist;
|
||||
import jakarta.persistence.PreUpdate;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import static com.bio.bio_backend.global.utils.OidUtils.generateOid;
|
||||
|
||||
/**
|
||||
* BaseEntity의 createdOid와 updatedOid 필드를 자동으로 설정하는 엔티티 리스너
|
||||
*/
|
||||
@Slf4j
|
||||
public class BaseEntityListener {
|
||||
|
||||
@PrePersist
|
||||
public void prePersist(BaseEntity entity) {
|
||||
if (entity.getOid() == null) {
|
||||
entity.setOid(generateOid());
|
||||
}
|
||||
|
||||
try {
|
||||
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||
Long currentUserOid = SecurityUtils.getCurrentUserOid();
|
||||
|
||||
if (currentUserOid != null) {
|
||||
entity.setCreatedOid(currentUserOid);
|
||||
entity.setUpdatedOid(currentUserOid);
|
||||
}
|
||||
|
||||
if (currentUserId != null) {
|
||||
entity.setCreatedId(currentUserId);
|
||||
entity.setUpdatedId(currentUserId);
|
||||
}
|
||||
} catch (SecurityException | IllegalStateException e) {
|
||||
log.warn("등록자 정보 설정 실패: {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("등록자 정보 설정 오류: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
public void preUpdate(BaseEntity entity) {
|
||||
try {
|
||||
String currentUserId = SecurityUtils.getCurrentUserId();
|
||||
Long currentUserOid = SecurityUtils.getCurrentUserOid();
|
||||
|
||||
if (currentUserOid != null) {
|
||||
entity.setUpdatedOid(currentUserOid);
|
||||
}
|
||||
|
||||
if (currentUserId != null) {
|
||||
entity.setUpdatedId(currentUserId);
|
||||
}
|
||||
} catch (SecurityException | IllegalStateException e) {
|
||||
log.warn("수정자 정보 설정 실패: {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("수정자 정보 설정 오류: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -11,6 +11,6 @@ public class CustomIdGenerator implements IdentifierGenerator {
|
||||
|
||||
@Override
|
||||
public Serializable generate(SharedSessionContractImplementor session, Object object) {
|
||||
return OidUtils.generateOid(); // 재사용
|
||||
return OidUtils.generateOid();
|
||||
}
|
||||
}
|
@@ -2,21 +2,30 @@ package com.bio.bio_backend.global.utils;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
import org.springframework.stereotype.Component;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.bio.bio_backend.domain.base.file.dto.FileUploadDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadRequestDto;
|
||||
import com.bio.bio_backend.domain.base.file.dto.MultipleFileUploadResponseDto;
|
||||
import com.bio.bio_backend.domain.base.file.service.FileService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 파일 관련 유틸리티 클래스
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class FileUtils {
|
||||
|
||||
private final FileService fileService;
|
||||
|
||||
/**
|
||||
* 파일 유효성 검사
|
||||
*/
|
||||
@@ -35,32 +44,6 @@ public class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 업로드 디렉토리 생성
|
||||
*/
|
||||
public static Path createUploadDirectory(String uploadPath) throws IOException {
|
||||
Path uploadDir = Paths.get(uploadPath);
|
||||
if (!Files.exists(uploadDir)) {
|
||||
Files.createDirectories(uploadDir);
|
||||
}
|
||||
return uploadDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 년월일 기반 업로드 디렉토리 생성
|
||||
* 예: uploads/2024/01/15/
|
||||
*/
|
||||
public static Path createDateBasedUploadDirectory(String baseUploadPath) throws IOException {
|
||||
LocalDate today = LocalDate.now();
|
||||
String yearMonthDay = today.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
|
||||
Path dateBasedPath = Paths.get(baseUploadPath, yearMonthDay);
|
||||
if (!Files.exists(dateBasedPath)) {
|
||||
Files.createDirectories(dateBasedPath);
|
||||
}
|
||||
return dateBasedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 년월 기반 업로드 디렉토리 생성
|
||||
* 예: uploads/2024/01/
|
||||
@@ -76,35 +59,6 @@ public class FileUtils {
|
||||
return yearMonthPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 년 기반 업로드 디렉토리 생성
|
||||
* 예: uploads/2024/
|
||||
*/
|
||||
public static Path createYearUploadDirectory(String baseUploadPath) throws IOException {
|
||||
LocalDate today = LocalDate.now();
|
||||
String year = today.format(DateTimeFormatter.ofPattern("yyyy"));
|
||||
|
||||
Path yearPath = Paths.get(baseUploadPath, year);
|
||||
if (!Files.exists(yearPath)) {
|
||||
Files.createDirectories(yearPath);
|
||||
}
|
||||
return yearPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 지정된 날짜로 업로드 디렉토리 생성
|
||||
* 예: uploads/2024/01/15/
|
||||
*/
|
||||
public static Path createDateBasedUploadDirectory(String baseUploadPath, LocalDate date) throws IOException {
|
||||
String yearMonthDay = date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
|
||||
Path dateBasedPath = Paths.get(baseUploadPath, yearMonthDay);
|
||||
if (!Files.exists(dateBasedPath)) {
|
||||
Files.createDirectories(dateBasedPath);
|
||||
}
|
||||
return dateBasedPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 확장자 추출
|
||||
*/
|
||||
@@ -127,7 +81,7 @@ public class FileUtils {
|
||||
*/
|
||||
public static Path saveFileToDisk(MultipartFile multipartFile, Path uploadDir, String storedFileName) throws IOException {
|
||||
Path targetLocation = uploadDir.resolve(storedFileName);
|
||||
Files.copy(multipartFile.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
|
||||
Files.copy(multipartFile.getInputStream(), targetLocation, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
|
||||
return targetLocation;
|
||||
}
|
||||
|
||||
@@ -138,173 +92,44 @@ public class FileUtils {
|
||||
return StringUtils.cleanPath(originalFileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 크기를 사람이 읽기 쉬운 형태로 변환
|
||||
*/
|
||||
public static String formatFileSize(long bytes) {
|
||||
if (bytes < 1024) return bytes + " B";
|
||||
if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
|
||||
if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
|
||||
return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 확장자로부터 MIME 타입 추정
|
||||
* 파일 업로드 (단일/다중 파일 모두 지원)
|
||||
* 사용 예시:
|
||||
* // 단일 파일 업로드
|
||||
* FileUploadDto fileResult = fileUtils.uploadFile(
|
||||
* requestDto.getFile(),
|
||||
* "프로필 이미지"
|
||||
* );
|
||||
* member.setFileGroupId(fileResult.getGroupOid());
|
||||
* // 다중 파일 업로드
|
||||
* FileUploadDto filesResult = fileUtils.uploadFiles(
|
||||
* requestDto.getFiles(),
|
||||
* "게시판 첨부파일: " + board.getTitle()
|
||||
* );
|
||||
* board.setFileGroupId(filesResult.getGroupOid());
|
||||
*/
|
||||
public static String getMimeTypeFromExtension(String fileName) {
|
||||
if (fileName == null) return "application/octet-stream";
|
||||
|
||||
String extension = extractFileExtension(fileName).toLowerCase();
|
||||
switch (extension) {
|
||||
case ".txt": return "text/plain";
|
||||
case ".html": case ".htm": return "text/html";
|
||||
case ".css": return "text/css";
|
||||
case ".js": return "application/javascript";
|
||||
case ".json": return "application/json";
|
||||
case ".xml": return "application/xml";
|
||||
case ".pdf": return "application/pdf";
|
||||
case ".zip": return "application/zip";
|
||||
case ".jpg": case ".jpeg": return "image/jpeg";
|
||||
case ".png": return "image/png";
|
||||
case ".gif": return "image/gif";
|
||||
case ".bmp": return "image/bmp";
|
||||
case ".svg": return "image/svg+xml";
|
||||
case ".mp4": return "video/mp4";
|
||||
case ".avi": return "video/x-msvideo";
|
||||
case ".mp3": return "audio/mpeg";
|
||||
case ".wav": return "audio/wav";
|
||||
default: return "application/octet-stream";
|
||||
}
|
||||
public FileUploadDto uploadFile(MultipartFile file, String description) {
|
||||
// 단일 파일도 List로 감싸서 다중 파일 업로드 방식 사용
|
||||
List<MultipartFile> files = List.of(file);
|
||||
return uploadFiles(files, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* 안전한 파일명 생성 (특수문자 제거)
|
||||
*/
|
||||
public static String createSafeFileName(String originalFileName) {
|
||||
if (originalFileName == null) return "";
|
||||
public FileUploadDto uploadFiles(List<MultipartFile> files, String description) {
|
||||
MultipleFileUploadRequestDto requestDto = MultipleFileUploadRequestDto.builder()
|
||||
.files(files)
|
||||
.description(description)
|
||||
.build();
|
||||
|
||||
// 특수문자 제거 및 공백을 언더스코어로 변경
|
||||
String safeName = originalFileName
|
||||
.replaceAll("[^a-zA-Z0-9가-힣._-]", "_")
|
||||
.replaceAll("_+", "_")
|
||||
.trim();
|
||||
MultipleFileUploadResponseDto response = fileService.uploadMultipleFiles(requestDto);
|
||||
|
||||
// 파일명이 너무 길면 자르기
|
||||
if (safeName.length() > 100) {
|
||||
String extension = extractFileExtension(safeName);
|
||||
safeName = safeName.substring(0, 100 - extension.length()) + extension;
|
||||
}
|
||||
|
||||
return safeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일이 이미지인지 확인
|
||||
*/
|
||||
public static boolean isImageFile(String fileName) {
|
||||
if (fileName == null) return false;
|
||||
|
||||
String extension = extractFileExtension(fileName).toLowerCase();
|
||||
return extension.matches("\\.(jpg|jpeg|png|gif|bmp|svg|webp)$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일이 문서인지 확인
|
||||
*/
|
||||
public static boolean isDocumentFile(String fileName) {
|
||||
if (fileName == null) return false;
|
||||
|
||||
String extension = extractFileExtension(fileName).toLowerCase();
|
||||
return extension.matches("\\.(pdf|doc|docx|xls|xlsx|ppt|pptx|txt|rtf)$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일이 압축파일인지 확인
|
||||
*/
|
||||
public static boolean isArchiveFile(String fileName) {
|
||||
if (fileName == null) return false;
|
||||
|
||||
String extension = extractFileExtension(fileName).toLowerCase();
|
||||
return extension.matches("\\.(zip|rar|7z|tar|gz|bz2)$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 날짜의 년월일 문자열 반환
|
||||
* 예: "2024/01/15"
|
||||
*/
|
||||
public static String getCurrentDatePath() {
|
||||
LocalDate today = LocalDate.now();
|
||||
return today.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 지정된 날짜의 년월일 문자열 반환
|
||||
* 예: "2024/01/15"
|
||||
*/
|
||||
public static String getDatePath(LocalDate date) {
|
||||
return date.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 경로에서 년월일 정보 추출
|
||||
* 예: "uploads/2024/01/15/file.txt" -> "2024/01/15"
|
||||
*/
|
||||
public static String extractDateFromPath(String filePath) {
|
||||
if (filePath == null || filePath.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// 정규식으로 년/월/일 패턴 찾기
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\d{4}/\\d{2}/\\d{2})");
|
||||
java.util.regex.Matcher matcher = pattern.matcher(filePath);
|
||||
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 년월일 폴더 구조가 유효한지 확인
|
||||
* 예: "2024/01/15" -> true, "2024/13/45" -> false
|
||||
*/
|
||||
public static boolean isValidDatePath(String datePath) {
|
||||
if (datePath == null || datePath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] parts = datePath.split("/");
|
||||
if (parts.length != 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int year = Integer.parseInt(parts[0]);
|
||||
int month = Integer.parseInt(parts[1]);
|
||||
int day = Integer.parseInt(parts[2]);
|
||||
|
||||
// 년도 범위 체크 (1900 ~ 2100)
|
||||
if (year < 1900 || year > 2100) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 월 범위 체크 (1 ~ 12)
|
||||
if (month < 1 || month > 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 일 범위 체크 (1 ~ 31)
|
||||
if (day < 1 || day > 31) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 실제 존재하는 날짜인지 확인
|
||||
LocalDate.of(year, month, day);
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
return FileUploadDto.builder()
|
||||
.groupOid(response.getGroupOid())
|
||||
.files(response.getFiles())
|
||||
.totalCount(response.getTotalCount())
|
||||
.successCount(response.getSuccessCount())
|
||||
.failureCount(response.getFailureCount())
|
||||
.errorMessages(response.getErrorMessages())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
@@ -3,11 +3,6 @@
|
||||
# ========================================
|
||||
server.port=8080
|
||||
server.servlet.context-path=/service
|
||||
|
||||
management.endpoint.health.probes.enabled=true
|
||||
management.health.livenessstate.enabled=true
|
||||
management.health.readinessstate.enabled=true
|
||||
|
||||
spring.application.name=bio_backend
|
||||
spring.output.ansi.enabled=always
|
||||
|
||||
@@ -118,8 +113,7 @@ springdoc.default-consumes-media-type=application/json
|
||||
|
||||
# ========================================
|
||||
# 보안 설정 - 허용할 경로
|
||||
# ========================================
|
||||
security.permit-all-paths=/login,/members/register,/swagger-ui/**,/swagger-ui.html,/swagger-ui/index.html,/api-docs,/api-docs/**,/v3/api-docs,/v3/api-docs/**,/ws/**,/actuator/health/**
|
||||
security.permit-all-paths=/login,/members/register,/swagger-ui/**,/swagger-ui.html,/swagger-ui/index.html,/api-docs,/api-docs/**,/v3/api-docs,/v3/api-docs/**,/ws/**,/actuator/**,/actuator/health/**,/actuator/info
|
||||
|
||||
# 파일 업로드 설정
|
||||
# ========================================
|
||||
@@ -130,3 +124,35 @@ spring.servlet.multipart.file-size-threshold=2KB
|
||||
|
||||
# 파일 저장 경로 설정
|
||||
app.file.upload.path=./uploads/
|
||||
|
||||
# ========================================
|
||||
# Spring Boot Actuator 설정
|
||||
# ========================================
|
||||
# Actuator 엔드포인트 활성화
|
||||
management.endpoints.web.exposure.include=health,info,metrics,env,configprops
|
||||
management.endpoint.health.show-details=always
|
||||
management.endpoint.health.show-components=always
|
||||
|
||||
# Health 체크 상세 정보 표시
|
||||
management.health.db.enabled=true
|
||||
management.health.diskspace.enabled=true
|
||||
management.health.defaults.enabled=true
|
||||
|
||||
# Actuator 기본 경로 설정
|
||||
management.endpoints.web.base-path=/actuator
|
||||
|
||||
# Health 체크 타임아웃 설정 (밀리초)
|
||||
management.health.defaults.timeout=10s
|
||||
|
||||
# 커스텀 Health 체크 그룹 설정
|
||||
management.health.groups.readiness.include=db,diskSpace
|
||||
management.health.groups.liveness.include=ping
|
||||
|
||||
# ========================================
|
||||
# 애플리케이션 정보 설정 (Actuator info 엔드포인트용)
|
||||
# ========================================
|
||||
info.app.name=Bio Backend Service
|
||||
info.app.description=생물학 연구를 위한 백엔드 서비스
|
||||
info.app.version=@project.version@
|
||||
info.app.java.version=@java.version@
|
||||
info.app.spring-boot.version=@spring-boot.version@
|
Reference in New Issue
Block a user