회원가입 추가, 역할 추가, 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

@@ -62,7 +62,8 @@ dependencies {
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') {

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,9 +47,7 @@ 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));
} }
@@ -79,24 +65,20 @@ public class MapSheetMngApiController {
@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
@@ -51,8 +48,7 @@ public class FileDto {
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 = "영상관리 오류데이터 검색 요청")

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,15 +45,15 @@ 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 =
stream
// 1. 디렉토리만 필터링 // 1. 디렉토리만 필터링
.filter(Files::isDirectory) .filter(Files::isDirectory)
.filter(p -> !p.toString().equals(dirPath)) .filter(p -> !p.toString().equals(dirPath))
.map(path -> { .map(
path -> {
int depth = path.getNameCount(); int depth = path.getNameCount();
String folderNm = path.getFileName().toString(); String folderNm = path.getFileName().toString();
@@ -79,35 +78,33 @@ public class MapSheetMngService {
String lastModified = dttmFormat.format(new Date(time.toMillis())); String lastModified = dttmFormat.format(new Date(time.toMillis()));
FolderDto folderDto =
FolderDto folderDto = new FolderDto( new FolderDto(
folderNm, folderNm,
parentFolderNm, parentFolderNm,
parentPath, parentPath,
fullPath, fullPath,
depth, depth,
childCnt, childCnt,
lastModified lastModified);
);
return folderDto; return folderDto;
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
folderDtoList.sort(Comparator.comparing( folderDtoList.sort(
FolderDto::getFolderNm, Comparator.comparing(
String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이 FolderDto::getFolderNm, String.CASE_INSENSITIVE_ORDER // 대소문자 구분 없이
).reversed()); )
.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,12 +122,10 @@ 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));
} }
@@ -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,21 +13,14 @@ 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 {
@@ -36,22 +33,27 @@ 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 =
queryFactory
.select( .select(
Projections.constructor( Projections.constructor(
MapSheetMngDto.ErrorDataDto.class, MapSheetMngDto.ErrorDataDto.class,
mapSheetMngHstEntity.hstUid, mapSheetMngHstEntity.hstUid,
rowNum(), rowNum(),
Expressions.stringTemplate("concat({0}, {1})", mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo), Expressions.stringTemplate(
Expressions.stringTemplate("concat({0}, substring({1}, {2}, {3}))", mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8), "concat({0}, {1})",
mapSheetMngHstEntity.mapSheetName, mapInkx50kEntity.mapidcdNo),
Expressions.stringTemplate(
"concat({0}, substring({1}, {2}, {3}))",
mapSheetMngHstEntity.mapSheetName, mapSheetMngHstEntity.mapSheetNum, 6, 8),
mapSheetMngHstEntity.mapSheetCodeSrc, mapSheetMngHstEntity.mapSheetCodeSrc,
Expressions.stringTemplate("to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate), Expressions.stringTemplate(
mapSheetMngHstEntity.dataState "to_char({0}, 'YYYY-MM-DD')", mapSheetMngHstEntity.createdDate),
) mapSheetMngHstEntity.dataState))
)
.from(mapSheetMngHstEntity) .from(mapSheetMngHstEntity)
.innerJoin(mapInkx5kEntity) .innerJoin(mapInkx5kEntity)
.on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid)) .on(mapSheetMngHstEntity.mapSheetCode.eq(mapInkx5kEntity.fid))
@@ -60,14 +62,14 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.where( .where(
mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()),
mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색 mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색
mapSheetErrorSearchValue(searchReq) mapSheetErrorSearchValue(searchReq))
)
.offset(pageable.getOffset()) .offset(pageable.getOffset())
.limit(pageable.getPageSize()) .limit(pageable.getPageSize())
.orderBy(mapSheetMngHstEntity.createdDate.desc()) .orderBy(mapSheetMngHstEntity.createdDate.desc())
.fetch(); .fetch();
Long countQuery = queryFactory Long countQuery =
queryFactory
.select(mapSheetMngHstEntity.hstUid.count()) .select(mapSheetMngHstEntity.hstUid.count())
.from(mapSheetMngHstEntity) .from(mapSheetMngHstEntity)
.innerJoin(mapInkx5kEntity) .innerJoin(mapInkx5kEntity)
@@ -77,15 +79,15 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
.where( .where(
mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()), mapSheetMngHstEntity.mngYyyy.eq(searchReq.getMngYyyy()),
mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색 mapSheetMngHstEntity.dataState.eq(MapSheetMngDto.DataState.FAIL), // 오류만 검색
mapSheetErrorSearchValue(searchReq) 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;
}
}