회원가입 추가, 역할 추가, spotlessApply 실행

This commit is contained in:
2025-12-02 18:27:12 +09:00
parent 2377f471d2
commit 7153497016
35 changed files with 1293 additions and 259 deletions

View File

@@ -1,8 +1,8 @@
plugins { plugins {
id 'java' id 'java'
id 'org.springframework.boot' version '3.5.7' id 'org.springframework.boot' version '3.5.7'
id 'io.spring.dependency-management' version '1.1.7' id 'io.spring.dependency-management' version '1.1.7'
id 'com.diffplug.spotless' version '6.25.0' id 'com.diffplug.spotless' version '6.25.0'
} }
group = 'com.kamco.cd' group = 'com.kamco.cd'
@@ -10,68 +10,69 @@ version = '0.0.1-SNAPSHOT'
description = 'kamco-back' description = 'kamco-back'
java { java {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(21) languageVersion = JavaLanguageVersion.of(21)
} }
} }
configurations { configurations {
compileOnly { compileOnly {
extendsFrom annotationProcessor extendsFrom annotationProcessor
} }
} }
repositories { repositories {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok' compileOnly 'org.projectlombok:lombok'
runtimeOnly 'org.postgresql:postgresql' runtimeOnly 'org.postgresql:postgresql'
annotationProcessor 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher' testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-validation'
//geometry //geometry
implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.locationtech.jts.io:jts-io-common:1.20.0' implementation 'org.locationtech.jts.io:jts-io-common:1.20.0'
implementation 'org.locationtech.jts:jts-core:1.19.0' implementation 'org.locationtech.jts:jts-core:1.19.0'
implementation 'org.hibernate:hibernate-spatial:6.2.7.Final' implementation 'org.hibernate:hibernate-spatial:6.2.7.Final'
// QueryDSL JPA // QueryDSL JPA
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
// Q클래스 생성용 annotationProcessor // Q클래스 생성용 annotationProcessor
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta' annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api' annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api' annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
// actuator // actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-actuator'
// Redis // Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-data-redis'
// SpringDoc OpenAPI (Swagger) // SpringDoc OpenAPI (Swagger)
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0'
// Apache Commons Compress for archive handling // Apache Commons Compress for archive handling
implementation 'org.apache.commons:commons-compress:1.26.0' implementation 'org.apache.commons:commons-compress:1.26.0'
// crypto // crypto
implementation 'org.springframework.security:spring-security-crypto' implementation 'org.mindrot:jbcrypt:0.4'
} }
tasks.named('test') { tasks.named('test') {
useJUnitPlatform() useJUnitPlatform()
} }
bootJar { bootJar {
archiveFileName = 'ROOT.jar' archiveFileName = 'ROOT.jar'
} }
// Spotless configuration for code formatting (2-space indent) // Spotless configuration for code formatting (2-space indent)
@@ -86,5 +87,5 @@ spotless {
// Run spotlessCheck before build // Run spotlessCheck before build
tasks.named('build') { tasks.named('build') {
dependsOn 'spotlessCheck' dependsOn 'spotlessCheck'
} }

View File

@@ -6,7 +6,6 @@ import com.kamco.cd.kamcoback.postgres.core.AuthCoreService;
import com.kamco.cd.kamcoback.postgres.entity.UserEntity; import com.kamco.cd.kamcoback.postgres.entity.UserEntity;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -16,7 +15,6 @@ import org.springframework.transaction.annotation.Transactional;
public class AuthService { public class AuthService {
private final AuthCoreService authCoreService; private final AuthCoreService authCoreService;
private final PasswordEncoder passwordEncoder;
/** /**
* 관리자 등록 * 관리자 등록
@@ -26,7 +24,6 @@ public class AuthService {
*/ */
@Transactional @Transactional
public UserEntity save(AuthDto.SaveReq saveReq) { public UserEntity save(AuthDto.SaveReq saveReq) {
saveReq.setUserPw(passwordEncoder.encode(saveReq.getUserPw()));
return authCoreService.save(saveReq); return authCoreService.save(saveReq);
} }
@@ -38,9 +35,7 @@ public class AuthService {
* @return * @return
*/ */
public UserEntity update(Long id, AuthDto.SaveReq saveReq) { public UserEntity update(Long id, AuthDto.SaveReq saveReq) {
if (saveReq.getUserPw() != null) { if (saveReq.getUserPw() != null) {}
saveReq.setUserPw(passwordEncoder.encode(saveReq.getUserPw()));
}
return authCoreService.update(id, saveReq); return authCoreService.update(id, saveReq);
} }

View File

@@ -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<EnumValid, String> {
private Set<String> 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);
}
}

View File

@@ -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<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
}

View File

@@ -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;
}
}

View File

@@ -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;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode; import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
import com.kamco.cd.kamcoback.log.dto.ErrorLogDto; 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.entity.ErrorLogEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository; import com.kamco.cd.kamcoback.postgres.repository.log.ErrorLogRepository;
import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.EntityNotFoundException;
@@ -226,6 +227,64 @@ public class GlobalExceptionHandler {
errorLog.getId()); errorLog.getId());
} }
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MemberException.DuplicateMemberException.class)
public ApiResponseDto<String> 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<String> 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) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(RuntimeException.class) @ExceptionHandler(RuntimeException.class)
public ApiResponseDto<String> handlerRuntimeException( public ApiResponseDto<String> handlerRuntimeException(

View File

@@ -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();
}
}

View File

@@ -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.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService; import com.kamco.cd.kamcoback.mapsheet.service.MapSheetMngService;
import io.swagger.v3.oas.annotations.Operation; 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.Content;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; 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.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; 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.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@Tag(name = "영상 관리", description = "영상 관리 API") @Tag(name = "영상 관리", description = "영상 관리 API")
@@ -59,44 +47,38 @@ public class MapSheetMngApiController {
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/getFolders") @PostMapping("/getFolders")
public ApiResponseDto<List<FileDto.FolderDto>> getDir( public ApiResponseDto<List<FileDto.FolderDto>> getDir(@RequestBody SrchFoldersDto srchDto) {
@RequestBody SrchFoldersDto srchDto
) {
return ApiResponseDto.createOK(mapSheetMngService.getFolderAll(srchDto)); return ApiResponseDto.createOK(mapSheetMngService.getFolderAll(srchDto));
} }
@Operation(summary = "파일목록 조회", description = "파일목록 조회") @Operation(summary = "파일목록 조회", description = "파일목록 조회")
@ApiResponses( @ApiResponses(
value = { value = {
@ApiResponse( @ApiResponse(
responseCode = "200", responseCode = "200",
description = "조회 성공", description = "조회 성공",
content = content =
@Content( @Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = CommonCodeDto.Basic.class))), schema = @Schema(implementation = CommonCodeDto.Basic.class))),
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content), @ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content) @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
}) })
@PostMapping("/getFiles") @PostMapping("/getFiles")
public ApiResponseDto<FilesDto> getFiles( public ApiResponseDto<FilesDto> getFiles(@RequestBody SrchFilesDto srchDto) {
@RequestBody SrchFilesDto srchDto
) {
return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto)); return ApiResponseDto.createOK(mapSheetMngService.getFilesAll(srchDto));
} }
/** /**
* 오류데이터 목록 조회 * 오류데이터 목록 조회
*
* @param searchReq * @param searchReq
* @return * @return
*/ */
@PostMapping("/error-list") @PostMapping("/error-list")
public ApiResponseDto<Page<MapSheetMngDto.ErrorDataDto>> findMapSheetErrorList( public ApiResponseDto<Page<MapSheetMngDto.ErrorDataDto>> findMapSheetErrorList(
@RequestBody @RequestBody @Valid MapSheetMngDto.searchReq searchReq) {
@Valid
MapSheetMngDto.searchReq searchReq
){
return ApiResponseDto.ok(mapSheetMngService.findMapSheetErrorList(searchReq)); return ApiResponseDto.ok(mapSheetMngService.findMapSheetErrorList(searchReq));
} }
} }

View File

@@ -2,17 +2,14 @@ package com.kamco.cd.kamcoback.mapsheet.dto;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
public class FileDto { public class FileDto {
@Getter @Getter
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@@ -45,14 +42,13 @@ public class FileDto {
private final String lastModified; private final String lastModified;
public FolderDto( public FolderDto(
String folderNm, String folderNm,
String parentFolderNm, String parentFolderNm,
String parentPath, String parentPath,
String fullPath, String fullPath,
int depth, int depth,
long childCnt, long childCnt,
String lastModified String lastModified) {
) {
this.folderNm = folderNm; this.folderNm = folderNm;
this.parentFolderNm = parentFolderNm; this.parentFolderNm = parentFolderNm;
this.parentPath = parentPath; this.parentPath = parentPath;
@@ -61,7 +57,6 @@ public class FileDto {
this.childCnt = childCnt; this.childCnt = childCnt;
this.lastModified = lastModified; this.lastModified = lastModified;
} }
} }
@Schema(name = "File Basic", description = "파일 기본 정보") @Schema(name = "File Basic", description = "파일 기본 정보")
@@ -75,12 +70,7 @@ public class FileDto {
private final String lastModified; private final String lastModified;
public Basic( public Basic(
String fileNm, String fileNm, String filePath, String extension, long fileSize, String lastModified) {
String filePath,
String extension,
long fileSize,
String lastModified
) {
this.fileNm = fileNm; this.fileNm = fileNm;
this.filePath = filePath; this.filePath = filePath;
this.extension = extension; this.extension = extension;
@@ -97,19 +87,12 @@ public class FileDto {
private final long fileTotSize; private final long fileTotSize;
private final List<Basic> files; private final List<Basic> files;
public FilesDto( public FilesDto(String dirPath, int fileTotCnt, long fileTotSize, List<Basic> files) {
String dirPath,
int fileTotCnt,
long fileTotSize,
List<Basic> files
) {
this.dirPath = dirPath; this.dirPath = dirPath;
this.fileTotCnt = fileTotCnt; this.fileTotCnt = fileTotCnt;
this.fileTotSize = fileTotSize; this.fileTotSize = fileTotSize;
this.files = files; this.files = files;
} }
} }
} }

View File

@@ -10,8 +10,6 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import java.time.ZonedDateTime;
public class MapSheetMngDto { public class MapSheetMngDto {
@Schema(name = "searchReq", description = "영상관리 오류데이터 검색 요청") @Schema(name = "searchReq", description = "영상관리 오류데이터 검색 요청")
@@ -33,7 +31,7 @@ public class MapSheetMngDto {
String[] sortParams = sort.split(","); String[] sortParams = sort.split(",");
String property = sortParams[0]; String property = sortParams[0];
Sort.Direction direction = 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, Sort.by(direction, property));
} }
return PageRequest.of(page, size); return PageRequest.of(page, size);
@@ -45,7 +43,7 @@ public class MapSheetMngDto {
@Setter @Setter
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
public static class ErrorDataDto{ public static class ErrorDataDto {
private Long hstUid; private Long hstUid;
private Integer rowNum; private Integer rowNum;
private String map50kName; private String map50kName;

View File

@@ -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.FolderDto;
import com.kamco.cd.kamcoback.mapsheet.dto.FileDto.SrchFilesDto; 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.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.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
@@ -19,10 +22,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; 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 lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.FilenameUtils;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
@@ -46,68 +45,66 @@ public class MapSheetMngService {
List<FolderDto> folderDtoList = List.of(); List<FolderDto> folderDtoList = List.of();
SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat dttmFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try (Stream<Path> stream = Files.walk(startPath, maxDepth)) { try (Stream<Path> stream = Files.walk(startPath, maxDepth)) {
folderDtoList = stream folderDtoList =
// 1. 디렉토리만 필터링 stream
.filter(Files::isDirectory) // 1. 디렉토리만 필터링
.filter(p -> !p.toString().equals(dirPath)) .filter(Files::isDirectory)
.map(path -> { .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(); File directory = new File(fullPath);
String parentFolderNm = path.getParent().getFileName().toString(); File[] childFolders = directory.listFiles(File::isDirectory);
String parentPath = path.getParent().toString();
String fullPath = path.toAbsolutePath().toString();
File directory = new File(fullPath); long childCnt = 0;
File[] childFolders = directory.listFiles(File::isDirectory); if (childFolders != null) {
childCnt = childFolders.length;
}
long childCnt = 0; FileTime time = null;
if (childFolders != null) { try {
childCnt = childFolders.length; time = Files.getLastModifiedTime(path);
} } catch (IOException e) {
throw new RuntimeException(e);
}
FileTime time = null; String lastModified = dttmFormat.format(new Date(time.toMillis()));
try {
time = Files.getLastModifiedTime(path);
} catch (IOException e) {
throw new RuntimeException(e);
}
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( folderDtoList.sort(
folderNm, Comparator.comparing(
parentFolderNm, FolderDto::getFolderNm, String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이
parentPath, )
fullPath, .reversed());
depth,
childCnt,
lastModified
);
return folderDto;
})
.collect(Collectors.toList());
folderDtoList.sort(Comparator.comparing(
FolderDto::getFolderNm,
String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이
).reversed());
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return folderDtoList; return folderDtoList;
} }
public FilesDto getFilesAll(SrchFilesDto srchDto) { public FilesDto getFilesAll(SrchFilesDto srchDto) {
String dirPath = srchDto.getDirPath(); String dirPath = srchDto.getDirPath();
@@ -125,22 +122,20 @@ public class MapSheetMngService {
int fileTotCnt = 0; int fileTotCnt = 0;
long fileTotSize = 0; long fileTotSize = 0;
if( fileList != null ) if (fileList != null) {
{ if (sortType.equals("name")) {
if( sortType.equals("name")){
Arrays.sort(fileList); Arrays.sort(fileList);
} } else if (sortType.equals("date")) {
else if( sortType.equals("date")){
Arrays.sort(fileList, Comparator.comparingLong(File::lastModified)); Arrays.sort(fileList, Comparator.comparingLong(File::lastModified));
} }
for (File file : fileList) { for (File file : fileList) {
if (file.isFile() ) { // 파일인 경우만 if (file.isFile()) { // 파일인 경우만
if( extension.equals("*") || file.getName().endsWith("."+extension) ) { if (extension.equals("*") || file.getName().endsWith("." + extension)) {
fileListPos = fileListPos + 1; fileListPos = fileListPos + 1;
if( startPos <= fileListPos && endPos >= fileListPos ) { if (startPos <= fileListPos && endPos >= fileListPos) {
// 생성자를 통해 객체를 만들고 리스트에 추가 // 생성자를 통해 객체를 만들고 리스트에 추가
String fileName = file.getName(); String fileName = file.getName();
@@ -153,28 +148,19 @@ public class MapSheetMngService {
fileTotCnt = fileTotCnt + 1; fileTotCnt = fileTotCnt + 1;
fileTotSize = fileTotSize + fileSize; fileTotSize = fileTotSize + fileSize;
} }
} }
} }
} }
} }
FilesDto filesDto = new FilesDto(dirPath, fileTotCnt, fileTotSize, files);
FilesDto filesDto = new FilesDto(
dirPath,
fileTotCnt,
fileTotSize,
files);
return filesDto; return filesDto;
} }
public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
MapSheetMngDto.@Valid searchReq searchReq) {
return mapSheetMngCoreService.findMapSheetErrorList(searchReq); return mapSheetMngCoreService.findMapSheetErrorList(searchReq);
} }
} }

View File

@@ -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<Long> 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<UUID> 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<UUID> 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());
}
}

View File

@@ -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<Page<Basic>> getMemberList(@RequestBody MembersDto.SearchReq searchReq) {
return ApiResponseDto.ok(membersService.findByMembers(searchReq));
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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<Basic> findByMembers(MembersDto.SearchReq searchReq) {
return membersCoreService.findByMembers(searchReq);
}
}

View File

@@ -7,15 +7,14 @@ import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class MapSheetMngCoreService { public class MapSheetMngCoreService {
private final MapSheetMngRepository mapSheetMngRepository; private final MapSheetMngRepository mapSheetMngRepository;
public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
MapSheetMngDto.@Valid searchReq searchReq) {
return mapSheetMngRepository.findMapSheetErrorList(searchReq); return mapSheetMngRepository.findMapSheetErrorList(searchReq);
} }
} }

View File

@@ -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<MembersDto.Basic> findByMembers(MembersDto.SearchReq searchReq) {
return membersRepository.findByMembers(searchReq);
}
}

View File

@@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.ZonedDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.time.ZonedDateTime;
@Getter @Getter
@Setter @Setter
@Entity @Entity

View File

@@ -3,11 +3,10 @@ package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.postgres.CommonDateEntity; import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
import jakarta.persistence.*; import jakarta.persistence.*;
import java.time.ZonedDateTime;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import java.time.ZonedDateTime;
@Getter @Getter
@Setter @Setter
@Entity @Entity

View File

@@ -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;
}

View File

@@ -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<MemberRoleEntity> tbMemberRoles = new LinkedHashSet<>();
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -3,4 +3,5 @@ package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
public interface MapSheetMngRepository extends JpaRepository<MapSheetMngEntity, Long>, MapSheetMngRepositoryCustom {} public interface MapSheetMngRepository
extends JpaRepository<MapSheetMngEntity, Long>, MapSheetMngRepositoryCustom {}

View File

@@ -1,12 +1,10 @@
package com.kamco.cd.kamcoback.postgres.repository.mapsheet; package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto; import com.kamco.cd.kamcoback.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngEntity;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import java.util.List;
public interface MapSheetMngRepositoryCustom { public interface MapSheetMngRepositoryCustom {
Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq); Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
MapSheetMngDto.@Valid searchReq searchReq);
} }

View File

@@ -1,5 +1,9 @@
package com.kamco.cd.kamcoback.postgres.repository.mapsheet; 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.mapsheet.dto.MapSheetMngDto;
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity; import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngHstEntity;
import com.querydsl.core.types.Projections; 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.core.types.dsl.StringExpression;
import com.querydsl.jpa.impl.JPAQueryFactory; import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.validation.Valid; 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.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport; 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 public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
implements MapSheetMngRepositoryCustom { implements MapSheetMngRepositoryCustom {
private final JPAQueryFactory queryFactory; private final JPAQueryFactory queryFactory;
private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)"); private final StringExpression NULL_STRING = Expressions.stringTemplate("cast(null as text)");
@@ -36,56 +33,61 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
} }
@Override @Override
public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(MapSheetMngDto.@Valid searchReq searchReq) { public Page<MapSheetMngDto.ErrorDataDto> findMapSheetErrorList(
MapSheetMngDto.@Valid searchReq searchReq) {
Pageable pageable = PageRequest.of(searchReq.getPage(), searchReq.getSize()); Pageable pageable = PageRequest.of(searchReq.getPage(), searchReq.getSize());
List<MapSheetMngDto.ErrorDataDto> foundContent = queryFactory List<MapSheetMngDto.ErrorDataDto> foundContent =
.select( queryFactory
Projections.constructor( .select(
MapSheetMngDto.ErrorDataDto.class, Projections.constructor(
mapSheetMngHstEntity.hstUid, MapSheetMngDto.ErrorDataDto.class,
rowNum(), mapSheetMngHstEntity.hstUid,
Expressions.stringTemplate("concat({0}, {1})", mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo), rowNum(),
Expressions.stringTemplate("concat({0}, substring({1}, {2}, {3}))", mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8), Expressions.stringTemplate(
mapSheetMngHstEntity.mapSheetCodeSrc, "concat({0}, {1})",
Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate), mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo),
mapSheetMngHstEntity.dataState Expressions.stringTemplate(
) "concat({0}, substring({1}, {2}, {3}))",
) mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8),
.from(mapSheetMngHstEntity) mapSheetMngHstEntity.mapSheetCodeSrc,
.innerJoin(mapInkx5kEntity) Expressions.stringTemplate(
.on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) "to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate),
.leftJoin(mapInkx50kEntity) mapSheetMngHstEntity.dataState))
.on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) .from(mapSheetMngHstEntity)
.where( .innerJoin(mapInkx5kEntity)
mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid))
mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), //오류만 검색 .leftJoin(mapInkx50kEntity)
mapSheetErrorSearchValue(searchReq) .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue()))
) .where(
.offset(pageable.getOffset()) mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()),
.limit(pageable.getPageSize()) mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색
.orderBy(mapSheetMngHstEntity.createdDate.desc()) mapSheetErrorSearchValue(searchReq))
.fetch(); .offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(mapSheetMngHstEntity.createdDate.desc())
.fetch();
Long countQuery = queryFactory Long countQuery =
.select(mapSheetMngHstEntity.hstUid.count()) queryFactory
.from(mapSheetMngHstEntity) .select(mapSheetMngHstEntity.hstUid.count())
.innerJoin(mapInkx5kEntity) .from(mapSheetMngHstEntity)
.on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) .innerJoin(mapInkx5kEntity)
.leftJoin(mapInkx50kEntity) .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid))
.on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue())) .leftJoin(mapInkx50kEntity)
.where( .on(mapInkx5kEntity.fidK50.eq(mapInkx50kEntity.fid.longValue()))
mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), .where(
mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), //오류만 검색 mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()),
mapSheetErrorSearchValue(searchReq) mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색
) mapSheetErrorSearchValue(searchReq))
.fetchOne(); .fetchOne();
return new PageImpl<>(foundContent, pageable, countQuery); return new PageImpl<>(foundContent, pageable, countQuery);
} }
private NumberExpression<Integer> rowNum(){ private NumberExpression<Integer> rowNum() {
return Expressions.numberTemplate(Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate); return Expressions.numberTemplate(
Integer.class, "row_number() over(order by {0} desc)", mapSheetMngHstEntity.createdDate);
} }
private BooleanExpression mapSheetErrorSearchValue(MapSheetMngDto.searchReq searchReq) { private BooleanExpression mapSheetErrorSearchValue(MapSheetMngDto.searchReq searchReq) {
@@ -94,7 +96,11 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
} }
// 검색어 1개 값이 도엽명 or 도엽번호 like 검색 // 검색어 1개 값이 도엽명 or 도엽번호 like 검색
return Expressions.booleanTemplate("{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetName) return Expressions.booleanTemplate(
.or(Expressions.booleanTemplate("{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetNum)); "{0} like '%" + searchReq.getSearchValue() + "%'", mapSheetMngHstEntity.mapSheetName)
.or(
Expressions.booleanTemplate(
"{0} like '%" + searchReq.getSearchValue() + "%'",
mapSheetMngHstEntity.mapSheetNum));
} }
} }

View File

@@ -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<MemberEntity, Long>, MembersRepositoryCustom {}

View File

@@ -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<Basic> findByMembers(MembersDto.SearchReq searchReq);
Optional<MemberEntity> findByUUID(UUID uuid);
}

View File

@@ -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<Basic> 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<String> 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<MembersDto.Basic> 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<MemberEntity> findByUUID(UUID uuid) {
return Optional.ofNullable(
queryFactory.selectFrom(memberEntity).where(memberEntity.uuid.eq(uuid)).fetchOne());
}
}

View File

@@ -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<MemberRoleEntity, Long>, MembersRoleRepositoryCutom {}

View File

@@ -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);
}

View File

@@ -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;
}
}