From 715349701662744fc5a583ab52f55f22c6e0b4fc Mon Sep 17 00:00:00 2001 From: teddy Date: Tue, 2 Dec 2025 18:27:12 +0900 Subject: [PATCH] =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20=EC=97=AD=ED=95=A0=20=EC=B6=94=EA=B0=80,?= =?UTF-8?q?=20spotlessApply=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 81 +++++----- .../kamcoback/auth/service/AuthService.java | 7 +- .../kamcoback/common/utils/EnumValidator.java | 26 ++++ .../common/utils/interfaces/EnumValid.java | 23 +++ .../kamcoback/config/BCryptSaltGenerator.java | 22 +++ .../config/GlobalExceptionHandler.java | 59 +++++++ .../cd/kamcoback/config/PasswordConfig.java | 15 -- .../mapsheet/MapSheetMngApiController.java | 48 ++---- .../cd/kamcoback/mapsheet/dto/FileDto.java | 35 ++--- .../mapsheet/dto/MapSheetMngDto.java | 6 +- .../mapsheet/service/MapSheetMngService.java | 122 +++++++-------- .../kamcoback/members/AdminApiController.java | 117 ++++++++++++++ .../members/MembersApiController.java | 45 ++++++ .../cd/kamcoback/members/dto/MembersDto.java | 133 ++++++++++++++++ .../cd/kamcoback/members/dto/RoleType.java | 25 +++ .../members/exception/MemberException.java | 39 +++++ .../members/service/AdminService.java | 53 +++++++ .../members/service/MembersService.java | 27 ++++ .../postgres/core/MapSheetMngCoreService.java | 5 +- .../postgres/core/MembersCoreService.java | 108 +++++++++++++ .../postgres/entity/MapSheetMngEntity.java | 3 +- .../postgres/entity/MapSheetMngHstEntity.java | 3 +- .../postgres/entity/MemberArchivedEntity.java | 60 ++++++++ .../postgres/entity/MemberEntity.java | 65 ++++++++ .../postgres/entity/MemberRoleEntity.java | 37 +++++ .../postgres/entity/MemberRoleEntityId.java | 47 ++++++ .../mapsheet/MapSheetMngRepository.java | 3 +- .../mapsheet/MapSheetMngRepositoryCustom.java | 6 +- .../mapsheet/MapSheetMngRepositoryImpl.java | 116 +++++++------- .../repository/members/MembersRepository.java | 7 + .../members/MembersRepositoryCustom.java | 19 +++ .../members/MembersRepositoryImpl.java | 145 ++++++++++++++++++ .../members/MembersRoleRepository.java | 7 + .../members/MembersRoleRepositoryCutom.java | 8 + .../members/MembersRoleRepositoryImpl.java | 30 ++++ 35 files changed, 1293 insertions(+), 259 deletions(-) create mode 100644 src/main/java/com/kamco/cd/kamcoback/common/utils/EnumValidator.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/common/utils/interfaces/EnumValid.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/config/BCryptSaltGenerator.java delete mode 100644 src/main/java/com/kamco/cd/kamcoback/config/PasswordConfig.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/AdminApiController.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/dto/RoleType.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/service/AdminService.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/members/service/MembersService.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberArchivedEntity.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntity.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntityId.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepository.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryCustom.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryImpl.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepository.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryCutom.java create mode 100644 src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryImpl.java diff --git a/build.gradle b/build.gradle index 2b409379..78660681 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,8 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.5.7' - id 'io.spring.dependency-management' version '1.1.7' - id 'com.diffplug.spotless' version '6.25.0' + id 'java' + id 'org.springframework.boot' version '3.5.7' + id 'io.spring.dependency-management' version '1.1.7' + id 'com.diffplug.spotless' version '6.25.0' } group = 'com.kamco.cd' @@ -10,68 +10,69 @@ version = '0.0.1-SNAPSHOT' description = 'kamco-back' java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'org.postgresql:postgresql' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'org.postgresql:postgresql' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' implementation 'org.springframework.boot:spring-boot-starter-validation' - //geometry - implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'org.locationtech.jts.io:jts-io-common:1.20.0' - implementation 'org.locationtech.jts:jts-core:1.19.0' + //geometry + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'org.locationtech.jts.io:jts-io-common:1.20.0' + implementation 'org.locationtech.jts:jts-core:1.19.0' implementation 'org.hibernate:hibernate-spatial:6.2.7.Final' - // QueryDSL JPA - implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + // QueryDSL JPA + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' - // Q클래스 생성용 annotationProcessor - annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' - annotationProcessor 'jakarta.annotation:jakarta.annotation-api' - annotationProcessor 'jakarta.persistence:jakarta.persistence-api' + // Q클래스 생성용 annotationProcessor + annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' + annotationProcessor 'jakarta.annotation:jakarta.annotation-api' + annotationProcessor 'jakarta.persistence:jakarta.persistence-api' - // actuator - implementation 'org.springframework.boot:spring-boot-starter-actuator' + // actuator + implementation 'org.springframework.boot:spring-boot-starter-actuator' - // Redis - implementation 'org.springframework.boot:spring-boot-starter-data-redis' + // Redis + implementation 'org.springframework.boot:spring-boot-starter-data-redis' - // SpringDoc OpenAPI (Swagger) - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' + // SpringDoc OpenAPI (Swagger) + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' - // Apache Commons Compress for archive handling - implementation 'org.apache.commons:commons-compress:1.26.0' + // Apache Commons Compress for archive handling + implementation 'org.apache.commons:commons-compress:1.26.0' // crypto - implementation 'org.springframework.security:spring-security-crypto' + implementation 'org.mindrot:jbcrypt:0.4' + } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } bootJar { - archiveFileName = 'ROOT.jar' + archiveFileName = 'ROOT.jar' } // Spotless configuration for code formatting (2-space indent) @@ -86,5 +87,5 @@ spotless { // Run spotlessCheck before build tasks.named('build') { - dependsOn 'spotlessCheck' + dependsOn 'spotlessCheck' } diff --git a/src/main/java/com/kamco/cd/kamcoback/auth/service/AuthService.java b/src/main/java/com/kamco/cd/kamcoback/auth/service/AuthService.java index bf2e3366..232df4bd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/auth/service/AuthService.java +++ b/src/main/java/com/kamco/cd/kamcoback/auth/service/AuthService.java @@ -6,7 +6,6 @@ import com.kamco.cd.kamcoback.postgres.core.AuthCoreService; import com.kamco.cd.kamcoback.postgres.entity.UserEntity; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional; public class AuthService { private final AuthCoreService authCoreService; - private final PasswordEncoder passwordEncoder; /** * 관리자 등록 @@ -26,7 +24,6 @@ public class AuthService { */ @Transactional public UserEntity save(AuthDto.SaveReq saveReq) { - saveReq.setUserPw(passwordEncoder.encode(saveReq.getUserPw())); return authCoreService.save(saveReq); } @@ -38,9 +35,7 @@ public class AuthService { * @return */ public UserEntity update(Long id, AuthDto.SaveReq saveReq) { - if (saveReq.getUserPw() != null) { - saveReq.setUserPw(passwordEncoder.encode(saveReq.getUserPw())); - } + if (saveReq.getUserPw() != null) {} return authCoreService.update(id, saveReq); } diff --git a/src/main/java/com/kamco/cd/kamcoback/common/utils/EnumValidator.java b/src/main/java/com/kamco/cd/kamcoback/common/utils/EnumValidator.java new file mode 100644 index 00000000..02dd3d16 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/common/utils/EnumValidator.java @@ -0,0 +1,26 @@ +package com.kamco.cd.kamcoback.common.utils; + +import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class EnumValidator implements ConstraintValidator { + + private Set acceptedValues; + + @Override + public void initialize(EnumValid constraintAnnotation) { + acceptedValues = + Arrays.stream(constraintAnnotation.enumClass().getEnumConstants()) + .map(Enum::name) + .collect(Collectors.toSet()); + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + return value != null && acceptedValues.contains(value); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/common/utils/interfaces/EnumValid.java b/src/main/java/com/kamco/cd/kamcoback/common/utils/interfaces/EnumValid.java new file mode 100644 index 00000000..c6d80b35 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/common/utils/interfaces/EnumValid.java @@ -0,0 +1,23 @@ +package com.kamco.cd.kamcoback.common.utils.interfaces; + +import com.kamco.cd.kamcoback.common.utils.EnumValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = EnumValidator.class) +public @interface EnumValid { + + String message() default "올바르지 않은 값입니다."; + + Class[] groups() default {}; + + Class[] payload() default {}; + + Class> enumClass(); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/config/BCryptSaltGenerator.java b/src/main/java/com/kamco/cd/kamcoback/config/BCryptSaltGenerator.java new file mode 100644 index 00000000..1e479da5 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/config/BCryptSaltGenerator.java @@ -0,0 +1,22 @@ +package com.kamco.cd.kamcoback.config; + +import java.security.SecureRandom; +import java.util.Base64; + +public class BCryptSaltGenerator { + + public static String generateSaltWithEmployeeNo(String employeeNo) { + + // bcrypt salt는 16바이트(128비트) 필요 + byte[] randomBytes = new byte[16]; + new SecureRandom().nextBytes(randomBytes); + + String base64 = Base64.getEncoder().encodeToString(randomBytes); + + // 사번을 포함 (22자 제한 → 잘라내기) + String mixedSalt = (employeeNo + base64).substring(0, 22); + + // bcrypt 포맷에 맞게 구성 + return "$2a$10$" + mixedSalt; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java index dfe79551..76e349c1 100644 --- a/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java +++ b/src/main/java/com/kamco/cd/kamcoback/config/GlobalExceptionHandler.java @@ -4,6 +4,7 @@ import com.kamco.cd.kamcoback.config.api.ApiLogFunction; import com.kamco.cd.kamcoback.config.api.ApiResponseDto; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.log.dto.ErrorLogDto; +import com.kamco.cd.kamcoback.members.exception.MemberException; import com.kamco.cd.kamcoback.postgres.entity.ErrorLogEntity; import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository; import jakarta.persistence.EntityNotFoundException; @@ -226,6 +227,64 @@ public class GlobalExceptionHandler { errorLog.getId()); } + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MemberException.DuplicateMemberException.class) + public ApiResponseDto handlerDuplicateMemberException( + MemberException.DuplicateMemberException e, HttpServletRequest request) { + log.warn("[DuplicateMemberException] resource :{} ", e.getMessage()); + + String codeName = ""; + + switch (e.getField()) { + case EMPLOYEE_NO -> { + codeName = "DUPLICATE_EMPLOYEEID"; + } + case EMAIL -> { + codeName = "DUPLICATE_EMAIL"; + } + default -> { + codeName = "DUPLICATE_DATA"; + } + } + + ErrorLogEntity errorLog = + saveErrerLogData( + request, + ApiResponseCode.getCode(codeName), + HttpStatus.valueOf("BAD_REQUEST"), + ErrorLogDto.LogErrorLevel.WARNING, + e.getStackTrace()); + + return ApiResponseDto.createException( + ApiResponseCode.getCode(codeName), + ApiResponseCode.getMessage(codeName), + HttpStatus.valueOf("BAD_REQUEST"), + errorLog.getId()); + } + + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(MemberException.MemberNotFoundException.class) + public ApiResponseDto handlerMemberNotFoundException( + MemberException.MemberNotFoundException e, HttpServletRequest request) { + log.warn("[MemberNotFoundException] resource :{} ", e.getMessage()); + + String codeName = "NOT_FOUND_USER"; + + ErrorLogEntity errorLog = + saveErrerLogData( + request, + ApiResponseCode.getCode(codeName), + HttpStatus.valueOf("BAD_REQUEST"), + ErrorLogDto.LogErrorLevel.WARNING, + e.getStackTrace()); + + return ApiResponseDto.createException( + ApiResponseCode.getCode(codeName), + ApiResponseCode.getMessage(codeName), + HttpStatus.valueOf("BAD_REQUEST"), + errorLog.getId()); + } + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(RuntimeException.class) public ApiResponseDto handlerRuntimeException( diff --git a/src/main/java/com/kamco/cd/kamcoback/config/PasswordConfig.java b/src/main/java/com/kamco/cd/kamcoback/config/PasswordConfig.java deleted file mode 100644 index 6805d5b7..00000000 --- a/src/main/java/com/kamco/cd/kamcoback/config/PasswordConfig.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.kamco.cd.kamcoback.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; - -@Configuration -public class PasswordConfig { - @Bean - public PasswordEncoder passwordEncoder() { - // strength 기본값 10, 필요하면 조절 가능 - return new BCryptPasswordEncoder(); - } -} diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java index 4c92bf0c..1d3160a5 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/MapSheetMngApiController.java @@ -10,30 +10,18 @@ import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; -import org.springframework.web.bind.annotation.DeleteMapping; -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.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Tag(name = "영상 관리", description = "영상 관리 API") @@ -59,44 +47,38 @@ public class MapSheetMngApiController { @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) }) @PostMapping("/getFolders") - public ApiResponseDto> getDir( - @RequestBody SrchFoldersDto srchDto - ) { + public ApiResponseDto> getDir(@RequestBody SrchFoldersDto srchDto) { return ApiResponseDto.createOK(mapSheetMngService.getFolderAll(srchDto)); } @Operation(summary = "파일목록 조회", description = "파일목록 조회") @ApiResponses( - value = { - @ApiResponse( - responseCode = "200", - description = "조회 성공", - content = - @Content( - mediaType = "application/json", - schema = @Schema(implementation = CommonCodeDto.Basic.class))), - @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), - @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) - }) + value = { + @ApiResponse( + responseCode = "200", + description = "조회 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = CommonCodeDto.Basic.class))), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) @PostMapping("/getFiles") - public ApiResponseDto getFiles( - @RequestBody SrchFilesDto srchDto - ) { + public ApiResponseDto getFiles(@RequestBody SrchFilesDto srchDto) { return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto)); } /** * 오류데이터 목록 조회 + * * @param searchReq * @return */ @PostMapping("/error-list") public ApiResponseDto> findMapSheetErrorList( - @RequestBody - @Valid - MapSheetMngDto.searchReq searchReq - ){ + @RequestBody @Valid MapSheetMngDto.searchReq searchReq) { return ApiResponseDto.ok(mapSheetMngService.findMapSheetErrorList(searchReq)); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java index a011c49b..b200f360 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/FileDto.java @@ -2,17 +2,14 @@ package com.kamco.cd.kamcoback.mapsheet.dto; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; -import java.util.ArrayList; import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; - public class FileDto { - @Getter @Setter @NoArgsConstructor @@ -45,14 +42,13 @@ public class FileDto { private final String lastModified; public FolderDto( - String folderNm, - String parentFolderNm, - String parentPath, - String fullPath, - int depth, - long childCnt, - String lastModified - ) { + String folderNm, + String parentFolderNm, + String parentPath, + String fullPath, + int depth, + long childCnt, + String lastModified) { this.folderNm = folderNm; this.parentFolderNm = parentFolderNm; this.parentPath = parentPath; @@ -61,7 +57,6 @@ public class FileDto { this.childCnt = childCnt; this.lastModified = lastModified; } - } @Schema(name = "File Basic", description = "파일 기본 정보") @@ -75,12 +70,7 @@ public class FileDto { private final String lastModified; public Basic( - String fileNm, - String filePath, - String extension, - long fileSize, - String lastModified - ) { + String fileNm, String filePath, String extension, long fileSize, String lastModified) { this.fileNm = fileNm; this.filePath = filePath; this.extension = extension; @@ -97,19 +87,12 @@ public class FileDto { private final long fileTotSize; private final List files; - public FilesDto( - String dirPath, - int fileTotCnt, - long fileTotSize, - List files + public FilesDto(String dirPath, int fileTotCnt, long fileTotSize, List files) { - ) { this.dirPath = dirPath; this.fileTotCnt = fileTotCnt; this.fileTotSize = fileTotSize; this.files = files; } } - - } diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java index 14b788e0..d6568051 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/dto/MapSheetMngDto.java @@ -10,8 +10,6 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import java.time.ZonedDateTime; - public class MapSheetMngDto { @Schema(name = "searchReq", description = "영상관리 오류데이터 검색 요청") @@ -33,7 +31,7 @@ public class MapSheetMngDto { String[] sortParams = sort.split(","); String property = sortParams[0]; Sort.Direction direction = - sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; + sortParams.length > 1 ? Sort.Direction.fromString(sortParams[1]) : Sort.Direction.ASC; return PageRequest.of(page, size, Sort.by(direction, property)); } return PageRequest.of(page, size); @@ -45,7 +43,7 @@ public class MapSheetMngDto { @Setter @NoArgsConstructor @AllArgsConstructor - public static class ErrorDataDto{ + public static class ErrorDataDto { private Long hstUid; private Integer rowNum; private String map50kName; diff --git a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java index 9b6ce149..458b91da 100644 --- a/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java +++ b/src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java @@ -5,6 +5,9 @@ import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FilesDto; import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.FolderDto; import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDto; import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFoldersDto; +import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; +import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService; +import jakarta.validation.Valid; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -19,10 +22,6 @@ import java.util.Date; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; - -import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; -import com.kamco.cd.kamcoback.postgres.core.MapSheetMngCoreService; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.apache.commons.io.FilenameUtils; import org.springframework.data.domain.Page; @@ -46,68 +45,66 @@ public class MapSheetMngService { List folderDtoList = List.of(); SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - try (Stream stream = Files.walk(startPath, maxDepth)) { - folderDtoList = stream - // 1. 디렉토리만 필터링 - .filter(Files::isDirectory) - .filter(p -> !p.toString().equals(dirPath)) - .map(path -> { + folderDtoList = + stream + // 1. 디렉토리만 필터링 + .filter(Files::isDirectory) + .filter(p -> !p.toString().equals(dirPath)) + .map( + path -> { + int depth = path.getNameCount(); - int depth = path.getNameCount(); + String folderNm = path.getFileName().toString(); + String parentFolderNm = path.getParent().getFileName().toString(); + String parentPath = path.getParent().toString(); + String fullPath = path.toAbsolutePath().toString(); - String folderNm = path.getFileName().toString(); - String parentFolderNm = path.getParent().getFileName().toString(); - String parentPath = path.getParent().toString(); - String fullPath = path.toAbsolutePath().toString(); + File directory = new File(fullPath); + File[] childFolders = directory.listFiles(File::isDirectory); - File directory = new File(fullPath); - File[] childFolders = directory.listFiles(File::isDirectory); + long childCnt = 0; + if (childFolders != null) { + childCnt = childFolders.length; + } - long childCnt = 0; - if (childFolders != null) { - childCnt = childFolders.length; - } + FileTime time = null; + try { + time = Files.getLastModifiedTime(path); + } catch (IOException e) { + throw new RuntimeException(e); + } - FileTime time = null; - try { - time = Files.getLastModifiedTime(path); - } catch (IOException e) { - throw new RuntimeException(e); - } + String lastModified = dttmFormat.format(new Date(time.toMillis())); - String lastModified = dttmFormat.format(new Date(time.toMillis())); + FolderDto folderDto = + new FolderDto( + folderNm, + parentFolderNm, + parentPath, + fullPath, + depth, + childCnt, + lastModified); + return folderDto; + }) + .collect(Collectors.toList()); - FolderDto folderDto = new FolderDto( - folderNm, - parentFolderNm, - parentPath, - fullPath, - depth, - childCnt, - lastModified - ); - - return folderDto; - }) - .collect(Collectors.toList()); - - folderDtoList.sort(Comparator.comparing( - FolderDto::getFolderNm, - String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이 - ).reversed()); + folderDtoList.sort( + Comparator.comparing( + FolderDto::getFolderNm, String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이 + ) + .reversed()); } catch (IOException e) { throw new RuntimeException(e); } return folderDtoList; - } - public FilesDto getFilesAll(SrchFilesDto srchDto) { String dirPath = srchDto.getDirPath(); @@ -125,22 +122,20 @@ public class MapSheetMngService { int fileTotCnt = 0; long fileTotSize = 0; - if( fileList != null ) - { - if( sortType.equals("name")){ + if (fileList != null) { + if (sortType.equals("name")) { Arrays.sort(fileList); - } - else if( sortType.equals("date")){ + } else if (sortType.equals("date")) { Arrays.sort(fileList, Comparator.comparingLong(File::lastModified)); } for (File file : fileList) { - if (file.isFile() ) { // 파일인 경우만 - if( extension.equals("*") || file.getName().endsWith("."+extension) ) { + if (file.isFile()) { // 파일인 경우만 + if (extension.equals("*") || file.getName().endsWith("." + extension)) { fileListPos = fileListPos + 1; - if( startPos <= fileListPos && endPos >= fileListPos ) { + if (startPos <= fileListPos && endPos >= fileListPos) { // 생성자를 통해 객체를 만들고 리스트에 추가 String fileName = file.getName(); @@ -153,28 +148,19 @@ public class MapSheetMngService { fileTotCnt = fileTotCnt + 1; fileTotSize = fileTotSize + fileSize; - } } } } - } - - FilesDto filesDto = new FilesDto( - dirPath, - fileTotCnt, - fileTotSize, - files); - - + FilesDto filesDto = new FilesDto(dirPath, fileTotCnt, fileTotSize, files); return filesDto; - } - public Page findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { + public Page findMapSheetErrorList( + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngCoreService.findMapSheetErrorList(searchReq); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/members/AdminApiController.java b/src/main/java/com/kamco/cd/kamcoback/members/AdminApiController.java new file mode 100644 index 00000000..effa1199 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/AdminApiController.java @@ -0,0 +1,117 @@ +package com.kamco.cd.kamcoback.members; + +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.service.AdminService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "회원정보 관리자 관리", description = "회원정보 관리자 관리 API") +@RestController +@RequestMapping("/api/admin") +@RequiredArgsConstructor +public class AdminApiController { + + private final AdminService adminService; + + @Operation(summary = "회원가입", description = "회원가입") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "회원가입 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Long.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/members/join") + public ApiResponseDto saveMember( + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "회원가입", + required = true, + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MembersDto.AddReq.class))) + @RequestBody + @Valid + MembersDto.AddReq addReq) { + + return ApiResponseDto.createOK(adminService.saveMember(addReq)); + } + + @Operation(summary = "역할 저장", description = "역할 저장") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "역할 추가", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = UUID.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/roles/add") + public ApiResponseDto saveRoles( + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "역할 추가", + required = true, + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MembersDto.RolesDto.class))) + @RequestBody + @Valid + MembersDto.RolesDto rolesDto) { + adminService.saveRoles(rolesDto); + return ApiResponseDto.createOK(rolesDto.getUuid()); + } + + @Operation(summary = "역할 삭제", description = "역할 삭제") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "201", + description = "역할 삭제", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = UUID.class))), + @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content), + @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/roles/rm") + public ApiResponseDto deleteRoles( + @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "역할 삭제", + required = true, + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = MembersDto.RolesDto.class))) + @RequestBody + @Valid + MembersDto.RolesDto rolesDto) { + adminService.deleteRoles(rolesDto); + return ApiResponseDto.createOK(rolesDto.getUuid()); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java new file mode 100644 index 00000000..2127f4ed --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/MembersApiController.java @@ -0,0 +1,45 @@ +package com.kamco.cd.kamcoback.members; + +import com.kamco.cd.kamcoback.config.api.ApiResponseDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; +import com.kamco.cd.kamcoback.members.service.MembersService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "회원정보 관리", description = "회원정보 관리 API") +@RestController +@RequestMapping("/api/members") +@RequiredArgsConstructor +public class MembersApiController { + + private final MembersService membersService; + + @Operation(summary = "회원정보 목록", description = "회원정보 조회") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "검색 성공", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = Page.class))), + @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content), + @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) + }) + @PostMapping("/list") + public ApiResponseDto> getMemberList(@RequestBody MembersDto.SearchReq searchReq) { + return ApiResponseDto.ok(membersService.findByMembers(searchReq)); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java new file mode 100644 index 00000000..c5e94ea9 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/dto/MembersDto.java @@ -0,0 +1,133 @@ +package com.kamco.cd.kamcoback.members.dto; + +import com.kamco.cd.kamcoback.common.utils.interfaces.EnumValid; +import com.kamco.cd.kamcoback.common.utils.interfaces.JsonFormatDttm; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.UUID; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +public class MembersDto { + + @Getter + @Setter + public static class Basic { + + private Long id; + private UUID uuid; + private String employeeNo; + private String name; + private String email; + private String status; + private String roleName; + @JsonFormatDttm private ZonedDateTime createdDttm; + @JsonFormatDttm private ZonedDateTime updatedDttm; + + public Basic( + Long id, + UUID uuid, + String employeeNo, + String name, + String email, + String status, + String roleName, + ZonedDateTime createdDttm, + ZonedDateTime updatedDttm) { + this.id = id; + this.uuid = uuid; + this.employeeNo = employeeNo; + this.name = name; + this.email = email; + this.status = status; + this.roleName = roleName; + this.createdDttm = createdDttm; + this.updatedDttm = updatedDttm; + } + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + public static class SearchReq { + + @Schema(description = "이름(name), 이메일(email), 사번(employeeNo)", example = "name") + private String field; + + @Schema(description = "키워드", example = "홍길동") + private String keyword; + + @Schema(description = "라벨러 포함 여부", example = "true") + private boolean labeler = true; + + @Schema(description = "검수자 포함 여부", example = "true") + private boolean reviewer = true; + + @Schema(description = "운영자 포함 여부", example = "true") + private boolean admin = true; + + // 페이징 파라미터 + @Schema(description = "페이지 번호 (0부터 시작) ", example = "0") + private int page = 0; + + @Schema(description = "페이지 크기", example = "20") + private int size = 20; + + public Pageable toPageable() { + return PageRequest.of(page, size); + } + } + + @Getter + @Setter + public static class AddReq { + + @Schema(description = "사번", example = "11111") + @NotBlank + @Size(max = 50) + private String employeeNo; + + @Schema(description = "이름", example = "홍길동") + @NotBlank + @Size(min = 2, max = 100) + private String name; + + @Schema(description = "패스워드", example = "") + @NotBlank + @Size(max = 255) + private String password; + + @Schema(description = "이메일", example = "gildong@daum.net") + @Size(max = 100) + private String email; + + public AddReq(String employeeNo, String name, String password, String email) { + this.employeeNo = employeeNo; + this.name = name; + this.password = password; + this.email = email; + } + } + + @Getter + @Setter + public static class RolesDto { + + private UUID uuid; + + @EnumValid(enumClass = RoleType.class) + private String roleName; + + public RolesDto(UUID uuid, String roleName) { + this.uuid = uuid; + this.roleName = roleName; + } + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/dto/RoleType.java b/src/main/java/com/kamco/cd/kamcoback/members/dto/RoleType.java new file mode 100644 index 00000000..59535f39 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/dto/RoleType.java @@ -0,0 +1,25 @@ +package com.kamco.cd.kamcoback.members.dto; + +import com.kamco.cd.kamcoback.config.enums.EnumType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum RoleType implements EnumType { + ROLE_ADMIN("시스템 관리자"), + ROLE_LABELER("라벨러"), + ROLE_REVIEWER("검수자"); + + private final String desc; + + @Override + public String getId() { + return name(); + } + + @Override + public String getText() { + return desc; + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java b/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java new file mode 100644 index 00000000..55c83419 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/exception/MemberException.java @@ -0,0 +1,39 @@ +package com.kamco.cd.kamcoback.members.exception; + +import lombok.Getter; + +@Getter +public class MemberException { + + // *** Duplicate Member Exception *** + @Getter + public static class DuplicateMemberException extends RuntimeException { + + public enum Field { + EMPLOYEE_NO, + EMAIL, + DEFAULT + } + + private final Field field; + private final String value; + + public DuplicateMemberException(Field field, String value) { + super(field.name() + " duplicate: " + value); + this.field = field; + this.value = value; + } + } + + // *** Member Not Found Exception *** + public static class MemberNotFoundException extends RuntimeException { + + public MemberNotFoundException() { + super("Member not found"); + } + + public MemberNotFoundException(String message) { + super(message); + } + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/service/AdminService.java b/src/main/java/com/kamco/cd/kamcoback/members/service/AdminService.java new file mode 100644 index 00000000..50b57d13 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/service/AdminService.java @@ -0,0 +1,53 @@ +package com.kamco.cd.kamcoback.members.service; + +import com.kamco.cd.kamcoback.config.BCryptSaltGenerator; +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; +import lombok.RequiredArgsConstructor; +import org.mindrot.jbcrypt.BCrypt; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class AdminService { + + private final MembersCoreService membersCoreService; + + /** + * 회원가입 + * + * @param addReq + * @return + */ + @Transactional + public Long saveMember(MembersDto.AddReq addReq) { + // salt 생성 + String salt = BCryptSaltGenerator.generateSaltWithEmployeeNo(addReq.getEmployeeNo()); + + // 패스워드 암호화 + String hashedPassword = BCrypt.hashpw(addReq.getPassword(), salt); + addReq.setPassword(hashedPassword); + return membersCoreService.saveMembers(addReq); + } + + /** + * 역할 추가 + * + * @param rolesDto + */ + @Transactional + public void saveRoles(MembersDto.RolesDto rolesDto) { + membersCoreService.saveRoles(rolesDto); + } + + /** + * 역할 삭제 + * + * @param rolesDto + */ + public void deleteRoles(MembersDto.RolesDto rolesDto) { + membersCoreService.deleteRoles(rolesDto); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/members/service/MembersService.java b/src/main/java/com/kamco/cd/kamcoback/members/service/MembersService.java new file mode 100644 index 00000000..332c1e44 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/members/service/MembersService.java @@ -0,0 +1,27 @@ +package com.kamco.cd.kamcoback.members.service; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; +import com.kamco.cd.kamcoback.postgres.core.MembersCoreService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class MembersService { + + private final MembersCoreService membersCoreService; + + /** + * 회원목록 조회 + * + * @param searchReq + * @return + */ + public Page findByMembers(MembersDto.SearchReq searchReq) { + return membersCoreService.findByMembers(searchReq); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java index 9bf0578a..a8d0ebdc 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MapSheetMngCoreService.java @@ -7,15 +7,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor public class MapSheetMngCoreService { private final MapSheetMngRepository mapSheetMngRepository; - public Page findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { + public Page findMapSheetErrorList( + MapSheetMngDto.@Valid searchReq searchReq) { return mapSheetMngRepository.findMapSheetErrorList(searchReq); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java new file mode 100644 index 00000000..2e7bf462 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/core/MembersCoreService.java @@ -0,0 +1,108 @@ +package com.kamco.cd.kamcoback.postgres.core; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.exception.MemberException; +import com.kamco.cd.kamcoback.members.exception.MemberException.MemberNotFoundException; +import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; +import com.kamco.cd.kamcoback.postgres.entity.MemberRoleEntity; +import com.kamco.cd.kamcoback.postgres.entity.MemberRoleEntityId; +import com.kamco.cd.kamcoback.postgres.repository.members.MembersRepository; +import com.kamco.cd.kamcoback.postgres.repository.members.MembersRoleRepository; +import java.time.ZonedDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MembersCoreService { + + private final MembersRepository membersRepository; + private final MembersRoleRepository memberRoleRepository; + + /** + * 회원가입 + * + * @param addReq + * @return + */ + public Long saveMembers(MembersDto.AddReq addReq) { + if (membersRepository.findByEmployeeNo(addReq.getEmployeeNo())) { + throw new MemberException.DuplicateMemberException( + MemberException.DuplicateMemberException.Field.EMPLOYEE_NO, addReq.getEmployeeNo()); + } + + if (membersRepository.findByEmail(addReq.getEmail())) { + throw new MemberException.DuplicateMemberException( + MemberException.DuplicateMemberException.Field.EMAIL, addReq.getEmail()); + } + + MemberEntity memberEntity = new MemberEntity(); + memberEntity.setEmployeeNo(addReq.getEmployeeNo()); + memberEntity.setName(addReq.getName()); + memberEntity.setPassword(addReq.getPassword()); + memberEntity.setEmail(addReq.getEmail()); + + return membersRepository.save(memberEntity).getId(); + } + + /** + * 역할 추가 + * + * @param rolesDto + */ + public void saveRoles(MembersDto.RolesDto rolesDto) { + + MemberEntity memberEntity = + membersRepository + .findByUUID(rolesDto.getUuid()) + .orElseThrow(() -> new MemberNotFoundException()); + + if (memberRoleRepository.findByUuidAndRoleName(rolesDto)) { + throw new MemberException.DuplicateMemberException( + MemberException.DuplicateMemberException.Field.DEFAULT, "중복된 역할이 있습니다."); + } + + MemberRoleEntityId memberRoleEntityId = new MemberRoleEntityId(); + memberRoleEntityId.setMemberUuid(rolesDto.getUuid()); + memberRoleEntityId.setRoleName(rolesDto.getRoleName()); + + MemberRoleEntity memberRoleEntity = new MemberRoleEntity(); + memberRoleEntity.setId(memberRoleEntityId); + memberRoleEntity.setMemberUuid(memberEntity); + memberRoleEntity.setCreatedDttm(ZonedDateTime.now()); + memberRoleRepository.save(memberRoleEntity); + } + + /** + * 역할 삭제 + * + * @param rolesDto + */ + public void deleteRoles(MembersDto.RolesDto rolesDto) { + MemberEntity memberEntity = + membersRepository + .findByUUID(rolesDto.getUuid()) + .orElseThrow(() -> new MemberNotFoundException()); + + MemberRoleEntityId memberRoleEntityId = new MemberRoleEntityId(); + memberRoleEntityId.setMemberUuid(rolesDto.getUuid()); + memberRoleEntityId.setRoleName(rolesDto.getRoleName()); + + MemberRoleEntity memberRoleEntity = new MemberRoleEntity(); + memberRoleEntity.setId(memberRoleEntityId); + memberRoleEntity.setMemberUuid(memberEntity); + + memberRoleRepository.delete(memberRoleEntity); + } + + /** + * 회원목록 조회 + * + * @param searchReq + * @return + */ + public Page findByMembers(MembersDto.SearchReq searchReq) { + return membersRepository.findByMembers(searchReq); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngEntity.java index b39df12c..72685afd 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngEntity.java @@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.entity; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import jakarta.persistence.*; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; -import java.time.ZonedDateTime; - @Getter @Setter @Entity diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java index d84fc41d..6b8f778c 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngHstEntity.java @@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.entity; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import jakarta.persistence.*; +import java.time.ZonedDateTime; import lombok.Getter; import lombok.Setter; -import java.time.ZonedDateTime; - @Getter @Setter @Entity diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberArchivedEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberArchivedEntity.java new file mode 100644 index 00000000..1f10b518 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberArchivedEntity.java @@ -0,0 +1,60 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.OffsetDateTime; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "tb_member_archived") +public class MemberArchivedEntity { + + @Id + @Column(name = "uuid", nullable = false) + private UUID id; + + @NotNull + @Column(name = "id", nullable = false) + private Long id1; + + @Size(max = 50) + @Column(name = "employee_no", length = 50) + private String employeeNo; + + @Size(max = 100) + @NotNull + @Column(name = "name", nullable = false, length = 100) + private String name; + + @Size(max = 255) + @NotNull + @Column(name = "password", nullable = false) + private String password; + + @Size(max = 100) + @NotNull + @Column(name = "email", nullable = false, length = 100) + private String email; + + @Size(max = 20) + @Column(name = "status", length = 20) + private String status; + + @NotNull + @Column(name = "created_dttm", nullable = false) + private OffsetDateTime createdDttm; + + @NotNull + @ColumnDefault("now()") + @Column(name = "archived_dttm", nullable = false) + private OffsetDateTime archivedDttm; +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java new file mode 100644 index 00000000..861c4ab7 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberEntity.java @@ -0,0 +1,65 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.time.ZonedDateTime; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; + +@Getter +@Setter +@Entity +@Table(name = "tb_member") +public class MemberEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + + @Column(name = "uuid", nullable = false, insertable = false) + private UUID uuid; + + @Size(max = 50) + @Column(name = "employee_no", length = 50) + private String employeeNo; + + @Size(max = 100) + @NotNull + @Column(name = "name", nullable = false, length = 100) + private String name; + + @Size(max = 255) + @NotNull + @Column(name = "password", nullable = false) + private String password; + + @Size(max = 100) + @Column(name = "email", length = 100) + private String email; + + @Size(max = 20) + @ColumnDefault("'ACTIVE'") + @Column(name = "status", length = 20) + private String status = "ACTIVE"; + + @Column(name = "created_dttm", nullable = false, insertable = false) + private ZonedDateTime createdDttm; + + @Column(name = "updated_dttm", nullable = false, insertable = false) + private ZonedDateTime updatedDttm; + + @OneToMany(mappedBy = "memberUuid") + private Set tbMemberRoles = new LinkedHashSet<>(); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntity.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntity.java new file mode 100644 index 00000000..8f5e98af --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntity.java @@ -0,0 +1,37 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import java.time.ZonedDateTime; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.ColumnDefault; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +@Getter +@Setter +@Entity +@Table(name = "tb_member_role") +public class MemberRoleEntity { + + @EmbeddedId private MemberRoleEntityId id; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @OnDelete(action = OnDeleteAction.CASCADE) + @JoinColumn( + name = "member_uuid", + referencedColumnName = "uuid", + insertable = false, + updatable = false) + private MemberEntity memberUuid; + + @ColumnDefault("now()") + @Column(name = "created_dttm") + private ZonedDateTime createdDttm; +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntityId.java b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntityId.java new file mode 100644 index 00000000..9d23c936 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/entity/MemberRoleEntityId.java @@ -0,0 +1,47 @@ +package com.kamco.cd.kamcoback.postgres.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.Hibernate; + +@Getter +@Setter +@Embeddable +public class MemberRoleEntityId implements Serializable { + + private static final long serialVersionUID = 9130416001060414347L; + + @NotNull + @Column(name = "member_uuid", nullable = false) + private UUID memberUuid; + + @Size(max = 50) + @NotNull + @Column(name = "role_name", nullable = false, length = 50) + private String roleName; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || Hibernate.getClass(this) != Hibernate.getClass(o)) { + return false; + } + MemberRoleEntityId entity = (MemberRoleEntityId) o; + return Objects.equals(this.memberUuid, entity.memberUuid) + && Objects.equals(this.roleName, entity.roleName); + } + + @Override + public int hashCode() { + return Objects.hash(memberUuid, roleName); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepository.java index f8b09f92..5be9c839 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepository.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepository.java @@ -3,4 +3,5 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface MapSheetMngRepository extends JpaRepository, MapSheetMngRepositoryCustom {} +public interface MapSheetMngRepository + extends JpaRepository, MapSheetMngRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java index d2403684..b7cc19a8 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryCustom.java @@ -1,12 +1,10 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; -import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity; import jakarta.validation.Valid; import org.springframework.data.domain.Page; -import java.util.List; - public interface MapSheetMngRepositoryCustom { - Page findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq); + Page findMapSheetErrorList( + MapSheetMngDto.@Valid searchReq searchReq); } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java index 85cda867..21d09980 100644 --- a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/mapsheet/MapSheetMngRepositoryImpl.java @@ -1,5 +1,9 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet; +import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx50kEntity.mapInkx50kEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity; +import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSheetMngHstEntity; + import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity; import com.querydsl.core.types.Projections; @@ -9,23 +13,16 @@ import com.querydsl.core.types.dsl.NumberExpression; import com.querydsl.core.types.dsl.StringExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.validation.Valid; -import jdk.jfr.Experimental; +import java.util.List; +import java.util.Objects; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; -import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngHstEntity.mapSheetMngHstEntity; -import static com.kamco.cd.kamcoback.postgres.entity.QMapSheetMngEntity.mapSheetMngEntity; -import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx5kEntity.mapInkx5kEntity; -import static com.kamco.cd.kamcoback.postgres.entity.QMapInkx50kEntity.mapInkx50kEntity; - -import java.util.List; -import java.util.Objects; - public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport - implements MapSheetMngRepositoryCustom { + implements MapSheetMngRepositoryCustom { private final JPAQueryFactory queryFactory; private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)"); @@ -36,56 +33,61 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport } @Override - public Page findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { + public Page findMapSheetErrorList( + MapSheetMngDto.@Valid searchReq searchReq) { Pageable pageable = PageRequest.of(searchReq.getPage(), searchReq.getSize()); - List foundContent = queryFactory - .select( - Projections.constructor( - MapSheetMngDto.ErrorDataDto.class, - mapSheetMngHstEntity.hstUid, - rowNum(), - Expressions.stringTemplate("concat({0}, {1})", mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo), - Expressions.stringTemplate("concat({0}, substring({1}, {2}, {3}))", mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8), - mapSheetMngHstEntity.mapSheetCodeSrc, - Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate), - mapSheetMngHstEntity.dataState - ) - ) - .from(mapSheetMngHstEntity) - .innerJoin(mapInkx5kEntity) - .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) - .leftJoin(mapInkx50kEntity) - .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) - .where( - mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), - mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), //오류만 검색 - mapSheetErrorSearchValue(searchReq) - ) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()) - .orderBy(mapSheetMngHstEntity.createdDate.desc()) - .fetch(); + List foundContent = + queryFactory + .select( + Projections.constructor( + MapSheetMngDto.ErrorDataDto.class, + mapSheetMngHstEntity.hstUid, + rowNum(), + Expressions.stringTemplate( + "concat({0}, {1})", + mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo), + Expressions.stringTemplate( + "concat({0}, substring({1}, {2}, {3}))", + mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8), + mapSheetMngHstEntity.mapSheetCodeSrc, + Expressions.stringTemplate( + "to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate), + mapSheetMngHstEntity.dataState)) + .from(mapSheetMngHstEntity) + .innerJoin(mapInkx5kEntity) + .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) + .leftJoin(mapInkx50kEntity) + .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) + .where( + mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), + mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색 + mapSheetErrorSearchValue(searchReq)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .orderBy(mapSheetMngHstEntity.createdDate.desc()) + .fetch(); - Long countQuery = queryFactory - .select(mapSheetMngHstEntity.hstUid.count()) - .from(mapSheetMngHstEntity) - .innerJoin(mapInkx5kEntity) - .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) - .leftJoin(mapInkx50kEntity) - .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) - .where( - mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), - mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), //오류만 검색 - mapSheetErrorSearchValue(searchReq) - ) - .fetchOne(); + Long countQuery = + queryFactory + .select(mapSheetMngHstEntity.hstUid.count()) + .from(mapSheetMngHstEntity) + .innerJoin(mapInkx5kEntity) + .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) + .leftJoin(mapInkx50kEntity) + .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) + .where( + mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), + mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색 + mapSheetErrorSearchValue(searchReq)) + .fetchOne(); return new PageImpl<>(foundContent, pageable, countQuery); } - private NumberExpression rowNum(){ - return Expressions.numberTemplate(Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate); + private NumberExpression rowNum() { + return Expressions.numberTemplate( + Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate); } private BooleanExpression mapSheetErrorSearchValue(MapSheetMngDto.searchReq searchReq) { @@ -94,7 +96,11 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport } // 검색어 1개 값이 도엽명 or 도엽번호 like 검색 - return Expressions.booleanTemplate("{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetName) - .or(Expressions.booleanTemplate("{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetNum)); + return Expressions.booleanTemplate( + "{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetName) + .or( + Expressions.booleanTemplate( + "{0} like '%" + searchReq.getSearchValue() + "%'", + mapSheetMngHstEntity.mapSheetNum)); } } diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepository.java new file mode 100644 index 00000000..a882f769 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MembersRepository + extends JpaRepository, MembersRepositoryCustom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryCustom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryCustom.java new file mode 100644 index 00000000..3d4152ab --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryCustom.java @@ -0,0 +1,19 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; +import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.domain.Page; + +public interface MembersRepositoryCustom { + + boolean findByEmployeeNo(String employeeNo); + + boolean findByEmail(String email); + + Page findByMembers(MembersDto.SearchReq searchReq); + + Optional findByUUID(UUID uuid); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryImpl.java new file mode 100644 index 00000000..9fe15eff --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRepositoryImpl.java @@ -0,0 +1,145 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic; +import com.kamco.cd.kamcoback.members.dto.RoleType; +import com.kamco.cd.kamcoback.postgres.entity.MemberEntity; +import com.kamco.cd.kamcoback.postgres.entity.QMemberEntity; +import com.kamco.cd.kamcoback.postgres.entity.QMemberRoleEntity; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class MembersRepositoryImpl implements MembersRepositoryCustom { + + private final JPAQueryFactory queryFactory; + private final QMemberEntity memberEntity = QMemberEntity.memberEntity; + private final QMemberRoleEntity memberRoleEntity = QMemberRoleEntity.memberRoleEntity; + + /** + * 사원번호 조회 + * + * @param employeeNo + * @return + */ + @Override + public boolean findByEmployeeNo(String employeeNo) { + return queryFactory + .selectOne() + .from(memberEntity) + .where(memberEntity.employeeNo.eq(employeeNo)) + .fetchFirst() + != null; + } + + /** + * 이메일 조회 + * + * @param email + * @return + */ + @Override + public boolean findByEmail(String email) { + return queryFactory + .selectOne() + .from(memberEntity) + .where(memberEntity.email.eq(email)) + .fetchFirst() + != null; + } + + /** + * 회원정보 목록 조회 + * + * @param searchReq + * @return + */ + @Override + public Page findByMembers(MembersDto.SearchReq searchReq) { + Pageable pageable = searchReq.toPageable(); + BooleanBuilder builder = new BooleanBuilder(); + BooleanBuilder leftBuilder = new BooleanBuilder(); + + if (searchReq.getField() != null && !searchReq.getField().isEmpty()) { + switch (searchReq.getField()) { + case "name" -> + builder.and(memberEntity.name.containsIgnoreCase(searchReq.getKeyword().trim())); + case "email" -> + builder.and(memberEntity.email.containsIgnoreCase(searchReq.getKeyword().trim())); + case "employeeNo" -> + builder.and(memberEntity.employeeNo.containsIgnoreCase(searchReq.getKeyword().trim())); + } + } + + List roles = new ArrayList<>(); + // 라벨러 + if (searchReq.isLabeler()) { + roles.add(RoleType.ROLE_LABELER.getId()); + } + + // 시스템 전체 관리자 + if (searchReq.isAdmin()) { + roles.add(RoleType.ROLE_ADMIN.getId()); + } + + // 검수자 + if (searchReq.isReviewer()) { + roles.add(RoleType.ROLE_REVIEWER.getId()); + } + + // 역할 in 조건 추가 + if (!roles.isEmpty()) { + leftBuilder.and(memberRoleEntity.id.roleName.in(roles)); + } + + List content = + queryFactory + .select( + Projections.constructor( + MembersDto.Basic.class, + memberEntity.id, + memberEntity.uuid, + memberEntity.employeeNo, + memberEntity.name, + memberEntity.email, + memberEntity.status, + memberRoleEntity.id.roleName, + memberEntity.createdDttm, + memberEntity.updatedDttm)) + .from(memberEntity) + .leftJoin(memberRoleEntity) + .on(memberRoleEntity.memberUuid.uuid.eq(memberEntity.uuid).and(leftBuilder)) + .where(builder) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .orderBy(memberEntity.createdDttm.desc()) + .fetch(); + + long total = + queryFactory + .select(memberEntity) + .from(memberEntity) + .leftJoin(memberRoleEntity) + .on(memberRoleEntity.memberUuid.uuid.eq(memberEntity.uuid).and(leftBuilder)) + .fetchCount(); + + return new PageImpl<>(content, pageable, total); + } + + @Override + public Optional findByUUID(UUID uuid) { + return Optional.ofNullable( + queryFactory.selectFrom(memberEntity).where(memberEntity.uuid.eq(uuid)).fetchOne()); + } +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepository.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepository.java new file mode 100644 index 00000000..172cb312 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepository.java @@ -0,0 +1,7 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.postgres.entity.MemberRoleEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface MembersRoleRepository + extends JpaRepository, MembersRoleRepositoryCutom {} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryCutom.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryCutom.java new file mode 100644 index 00000000..fd13d1d8 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryCutom.java @@ -0,0 +1,8 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; + +public interface MembersRoleRepositoryCutom { + + boolean findByUuidAndRoleName(MembersDto.RolesDto rolesDto); +} diff --git a/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryImpl.java b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryImpl.java new file mode 100644 index 00000000..571f41c7 --- /dev/null +++ b/src/main/java/com/kamco/cd/kamcoback/postgres/repository/members/MembersRoleRepositoryImpl.java @@ -0,0 +1,30 @@ +package com.kamco.cd.kamcoback.postgres.repository.members; + +import com.kamco.cd.kamcoback.members.dto.MembersDto; +import com.kamco.cd.kamcoback.postgres.entity.QMemberRoleEntity; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@RequiredArgsConstructor +@Repository +public class MembersRoleRepositoryImpl implements MembersRoleRepositoryCutom { + + private final JPAQueryFactory queryFactory; + private final QMemberRoleEntity memberRoleEntity = QMemberRoleEntity.memberRoleEntity; + + @Override + public boolean findByUuidAndRoleName(MembersDto.RolesDto rolesDto) { + return queryFactory + .select(memberRoleEntity) + .from(memberRoleEntity) + .where( + memberRoleEntity + .id + .memberUuid + .eq(rolesDto.getUuid()) + .and(memberRoleEntity.id.roleName.eq(rolesDto.getRoleName()))) + .fetchOne() + != null; + } +}