Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201
# Conflicts: # src/main/java/com/kamco/cd/kamcoback/postgres/entity/MapSheetMngFileEntity.java
This commit is contained in:
@@ -30,8 +30,8 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
.findByUserId(username)
|
.findByUserId(username)
|
||||||
.orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
|
.orElseThrow(() -> new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND));
|
||||||
|
|
||||||
// 삭제 상태
|
// 미사용 상태
|
||||||
if (member.getStatus().equals(StatusType.DELETED.getId())) {
|
if (member.getStatus().equals(StatusType.INACTIVE.getId())) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND);
|
throw new CustomApiException(AuthErrorCode.LOGIN_ID_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,15 +39,12 @@ public class CustomAuthenticationProvider implements AuthenticationProvider {
|
|||||||
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
if (!BCrypt.checkpw(rawPassword, member.getPassword())) {
|
||||||
// 실패 카운트 저장
|
// 실패 카운트 저장
|
||||||
int cnt = member.getLoginFailCount() + 1;
|
int cnt = member.getLoginFailCount() + 1;
|
||||||
if (cnt >= 5) {
|
|
||||||
member.setStatus(StatusType.INACTIVE.getId());
|
|
||||||
}
|
|
||||||
member.setLoginFailCount(cnt);
|
member.setLoginFailCount(cnt);
|
||||||
membersRepository.save(member);
|
membersRepository.save(member);
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 패스워드 실패 횟수 체크
|
// 로그인 실패 체크
|
||||||
if (member.getLoginFailCount() >= 5) {
|
if (member.getLoginFailCount() >= 5) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_EXCEEDED);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
||||||
String path = request.getServletPath();
|
String path = request.getServletPath();
|
||||||
|
|
||||||
// 여기에 JWT 필터를 타지 않게 할 URL 패턴들 작성
|
// JWT 필터를 타지 않게 할 URL 패턴들
|
||||||
return path.startsWith("/api/auth/signin") || path.startsWith("/api/auth/refresh");
|
return path.startsWith("/api/auth/signin") || path.startsWith("/api/auth/refresh");
|
||||||
// 필요하면 "/api/auth/logout" 도 추가
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveToken(HttpServletRequest request) {
|
private String resolveToken(HttpServletRequest request) {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
|
||||||
public class CommonCodeDto {
|
public class CommonCodeDto {
|
||||||
|
|
||||||
@@ -132,6 +135,33 @@ public class CommonCodeDto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Schema(name = "SearchReq", description = "검색 요청")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class SearchReq {
|
||||||
|
|
||||||
|
// 검색 조건
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
// 페이징 파라미터
|
||||||
|
private int page = 0;
|
||||||
|
private int size = 20;
|
||||||
|
private String sort;
|
||||||
|
|
||||||
|
public Pageable toPageable() {
|
||||||
|
if (sort != null && !sort.isEmpty()) {
|
||||||
|
String[] sortParams = sort.split(",");
|
||||||
|
String property = sortParams[0];
|
||||||
|
Sort.Direction direction =
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public static class Clazzes {
|
public static class Clazzes {
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import lombok.Getter;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum StatusType implements EnumType {
|
public enum StatusType implements EnumType {
|
||||||
ACTIVE("활성"),
|
ACTIVE("활성"),
|
||||||
INACTIVE("비활성"),
|
INACTIVE("미사용"),
|
||||||
DELETED("삭제");
|
PENDING("보류");
|
||||||
|
|
||||||
private final String desc;
|
private final String desc;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.exception;
|
||||||
|
|
||||||
|
public class DuplicateFileException extends RuntimeException {
|
||||||
|
public DuplicateFileException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.exception;
|
||||||
|
|
||||||
|
public class ValidationException extends RuntimeException {
|
||||||
|
public ValidationException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.kamco.cd.kamcoback.common.utils;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class CommonStringUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
||||||
|
*
|
||||||
|
* @param password
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean isValidPassword(String password) {
|
||||||
|
String passwordPattern =
|
||||||
|
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
||||||
|
return Pattern.matches(passwordPattern, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.config;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.auth.CustomUserDetails;
|
import com.kamco.cd.kamcoback.auth.CustomUserDetails;
|
||||||
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.DuplicateFileException;
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.ValidationException;
|
||||||
import com.kamco.cd.kamcoback.config.api.ApiLogFunction;
|
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;
|
||||||
@@ -42,6 +44,60 @@ public class GlobalExceptionHandler {
|
|||||||
this.errorLogRepository = errorLogRepository;
|
this.errorLogRepository = errorLogRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.CONFLICT)
|
||||||
|
@ExceptionHandler(DuplicateFileException.class)
|
||||||
|
public ApiResponseDto<String> handleDuplicateFileException(
|
||||||
|
DuplicateFileException e, HttpServletRequest request) {
|
||||||
|
log.warn("[DuplicateFileException] resource :{} ", e.getMessage());
|
||||||
|
ApiResponseCode code = ApiResponseCode.CONFLICT;
|
||||||
|
ErrorLogEntity errorLog =
|
||||||
|
saveErrorLogData(
|
||||||
|
request,
|
||||||
|
code,
|
||||||
|
HttpStatus.CONFLICT,
|
||||||
|
ErrorLogDto.LogErrorLevel.WARNING,
|
||||||
|
e.getStackTrace());
|
||||||
|
|
||||||
|
return ApiResponseDto.createException(
|
||||||
|
code, e.getMessage(), HttpStatus.CONFLICT, errorLog.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||||
|
@ExceptionHandler(ValidationException.class)
|
||||||
|
public ApiResponseDto<String> handleValidationException(
|
||||||
|
ValidationException e, HttpServletRequest request) {
|
||||||
|
log.warn("[ValidationException] resource :{} ", e.getMessage());
|
||||||
|
ApiResponseCode code = ApiResponseCode.UNPROCESSABLE_ENTITY;
|
||||||
|
ErrorLogEntity errorLog =
|
||||||
|
saveErrorLogData(
|
||||||
|
request,
|
||||||
|
code,
|
||||||
|
HttpStatus.UNPROCESSABLE_ENTITY,
|
||||||
|
ErrorLogDto.LogErrorLevel.WARNING,
|
||||||
|
e.getStackTrace());
|
||||||
|
|
||||||
|
return ApiResponseDto.createException(
|
||||||
|
code, e.getMessage(), HttpStatus.UNPROCESSABLE_ENTITY, errorLog.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
@ExceptionHandler(IllegalArgumentException.class)
|
||||||
|
public ApiResponseDto<String> handleIllegalArgumentException(
|
||||||
|
IllegalArgumentException e, HttpServletRequest request) {
|
||||||
|
log.warn("[IllegalArgumentException] resource :{} ", e.getMessage());
|
||||||
|
ApiResponseCode code = ApiResponseCode.BAD_REQUEST;
|
||||||
|
ErrorLogEntity errorLog =
|
||||||
|
saveErrorLogData(
|
||||||
|
request,
|
||||||
|
code,
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
ErrorLogDto.LogErrorLevel.WARNING,
|
||||||
|
e.getStackTrace());
|
||||||
|
|
||||||
|
return ApiResponseDto.createException(
|
||||||
|
code, e.getMessage(), HttpStatus.BAD_REQUEST, errorLog.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||||
@ExceptionHandler(EntityNotFoundException.class)
|
@ExceptionHandler(EntityNotFoundException.class)
|
||||||
public ApiResponseDto<String> handlerEntityNotFoundException(
|
public ApiResponseDto<String> handlerEntityNotFoundException(
|
||||||
@@ -105,26 +161,7 @@ public class GlobalExceptionHandler {
|
|||||||
errorLog.getId());
|
errorLog.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
@ExceptionHandler(IllegalArgumentException.class)
|
|
||||||
public ApiResponseDto<String> handlerIllegalArgumentException(
|
|
||||||
IllegalArgumentException e, HttpServletRequest request) {
|
|
||||||
log.warn("[handlerIllegalArgumentException] resource :{} ", e.getMessage());
|
|
||||||
String codeName = "BAD_REQUEST";
|
|
||||||
ErrorLogEntity errorLog =
|
|
||||||
saveErrorLogData(
|
|
||||||
request,
|
|
||||||
ApiResponseCode.getCode(codeName),
|
|
||||||
HttpStatus.valueOf(codeName),
|
|
||||||
ErrorLogDto.LogErrorLevel.WARNING,
|
|
||||||
e.getStackTrace());
|
|
||||||
|
|
||||||
return ApiResponseDto.createException(
|
|
||||||
ApiResponseCode.getCode(codeName),
|
|
||||||
ApiResponseCode.getMessage(codeName),
|
|
||||||
HttpStatus.valueOf(codeName),
|
|
||||||
errorLog.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
|
||||||
@ExceptionHandler(DataIntegrityViolationException.class)
|
@ExceptionHandler(DataIntegrityViolationException.class)
|
||||||
@@ -435,23 +472,38 @@ public class GlobalExceptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(CustomApiException.class)
|
@ExceptionHandler(CustomApiException.class)
|
||||||
public ResponseEntity<ApiResponseDto<String>> handleCustomApiException(
|
public ApiResponseDto<String> handleCustomApiException(
|
||||||
CustomApiException e, HttpServletRequest request) {
|
CustomApiException e, HttpServletRequest request) {
|
||||||
log.warn("[CustomApiException] resource : {}", e.getMessage());
|
log.warn("[CustomApiException] resource : {}", e.getMessage());
|
||||||
|
|
||||||
String codeName = e.getCodeName();
|
String codeName = e.getCodeName();
|
||||||
HttpStatus status = e.getStatus();
|
HttpStatus status = e.getStatus();
|
||||||
String message = e.getMessage() == null ? ApiResponseCode.getMessage(codeName) : e.getMessage();
|
// String message = e.getMessage() == null ? ApiResponseCode.getMessage(codeName) :
|
||||||
|
// e.getMessage();
|
||||||
ApiResponseCode apiCode = ApiResponseCode.getCode(codeName);
|
//
|
||||||
|
// ApiResponseCode apiCode = ApiResponseCode.getCode(codeName);
|
||||||
|
//
|
||||||
|
// ErrorLogEntity errorLog =
|
||||||
|
// saveErrorLogData(
|
||||||
|
// request, apiCode, status, ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
||||||
|
//
|
||||||
|
// ApiResponseDto<String> body =
|
||||||
|
// ApiResponseDto.createException(apiCode, message, status, errorLog.getId());
|
||||||
|
|
||||||
ErrorLogEntity errorLog =
|
ErrorLogEntity errorLog =
|
||||||
saveErrorLogData(
|
saveErrorLogData(
|
||||||
request, apiCode, status, ErrorLogDto.LogErrorLevel.WARNING, e.getStackTrace());
|
request,
|
||||||
|
ApiResponseCode.getCode(codeName),
|
||||||
|
HttpStatus.valueOf(status.value()),
|
||||||
|
ErrorLogDto.LogErrorLevel.WARNING,
|
||||||
|
e.getStackTrace());
|
||||||
|
|
||||||
ApiResponseDto<String> body =
|
return ApiResponseDto.createException(
|
||||||
ApiResponseDto.createException(apiCode, message, status, errorLog.getId());
|
ApiResponseCode.getCode(codeName),
|
||||||
|
ApiResponseCode.getMessage(codeName),
|
||||||
|
HttpStatus.valueOf(status.value()),
|
||||||
|
errorLog.getId());
|
||||||
|
|
||||||
return new ResponseEntity<>(body, status);
|
// return new ResponseEntity<>(body, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,13 @@ import org.springframework.security.authentication.AuthenticationManager;
|
|||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
|
import org.springframework.security.web.firewall.HttpFirewall;
|
||||||
|
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||||
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.web.cors.CorsConfiguration;
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
@@ -30,19 +34,23 @@ public class SecurityConfig {
|
|||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
|
||||||
.csrf(csrf -> csrf.disable()) // CSRF 보안 기능 비활성화
|
.csrf(csrf -> csrf.disable())
|
||||||
.sessionManagement(
|
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
sm ->
|
.formLogin(form -> form.disable())
|
||||||
sm.sessionCreationPolicy(
|
.httpBasic(basic -> basic.disable())
|
||||||
SessionCreationPolicy.STATELESS)) // 서버 세션 만들지 않음, 요청은 JWT 인증
|
.logout(logout -> logout.disable())
|
||||||
.formLogin(form -> form.disable()) // react에서 로그인 요청 관리
|
.authenticationProvider(customAuthenticationProvider)
|
||||||
.httpBasic(basic -> basic.disable()) // 기본 basic 인증 비활성화 JWT 인증사용
|
|
||||||
.logout(logout -> logout.disable()) // 기본 로그아웃 비활성화 JWT는 서버 상태가 없으므로 로그아웃 처리 필요 없음
|
|
||||||
.authenticationProvider(
|
|
||||||
customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
|
|
||||||
.authorizeHttpRequests(
|
.authorizeHttpRequests(
|
||||||
auth ->
|
auth ->
|
||||||
auth
|
auth
|
||||||
|
// 맵시트 영역 전체 허용 (우선순위 최상단)
|
||||||
|
.requestMatchers("/api/mapsheet/**")
|
||||||
|
.permitAll()
|
||||||
|
|
||||||
|
// 업로드 명시적 허용
|
||||||
|
.requestMatchers(HttpMethod.POST, "/api/mapsheet/upload")
|
||||||
|
.permitAll()
|
||||||
|
|
||||||
// ADMIN만 접근
|
// ADMIN만 접근
|
||||||
.requestMatchers("/api/test/admin")
|
.requestMatchers("/api/test/admin")
|
||||||
.hasRole("ADMIN")
|
.hasRole("ADMIN")
|
||||||
@@ -54,6 +62,8 @@ public class SecurityConfig {
|
|||||||
// ADMIN, REVIEWER 접근
|
// ADMIN, REVIEWER 접근
|
||||||
.requestMatchers("/api/test/review")
|
.requestMatchers("/api/test/review")
|
||||||
.hasAnyRole("ADMIN", "REVIEWER")
|
.hasAnyRole("ADMIN", "REVIEWER")
|
||||||
|
.requestMatchers("/error")
|
||||||
|
.permitAll()
|
||||||
.requestMatchers(HttpMethod.OPTIONS, "/**")
|
.requestMatchers(HttpMethod.OPTIONS, "/**")
|
||||||
.permitAll() // preflight 허용
|
.permitAll() // preflight 허용
|
||||||
.requestMatchers(
|
.requestMatchers(
|
||||||
@@ -98,4 +108,19 @@ public class SecurityConfig {
|
|||||||
source.registerCorsConfiguration("/**", config); // CORS 정책을 등록
|
source.registerCorsConfiguration("/**", config); // CORS 정책을 등록
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HttpFirewall httpFirewall() {
|
||||||
|
StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||||
|
firewall.setAllowUrlEncodedSlash(true);
|
||||||
|
firewall.setAllowUrlEncodedDoubleSlash(true);
|
||||||
|
firewall.setAllowUrlEncodedPercent(true);
|
||||||
|
firewall.setAllowSemicolon(true);
|
||||||
|
return firewall;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public WebSecurityCustomizer webSecurityCustomizer() {
|
||||||
|
return (web) -> web.ignoring().requestMatchers(new AntPathRequestMatcher("/api/mapsheet/**"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,37 +56,38 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
|
|||||||
ServerHttpResponse response) {
|
ServerHttpResponse response) {
|
||||||
|
|
||||||
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
|
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
|
||||||
ContentCachingRequestWrapper contentWrapper = (ContentCachingRequestWrapper) servletRequest;
|
ContentCachingRequestWrapper contentWrapper = null;
|
||||||
|
if (servletRequest instanceof ContentCachingRequestWrapper wrapper) {
|
||||||
|
contentWrapper = wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
if (body instanceof ApiResponseDto<?> apiResponse) {
|
if (body instanceof ApiResponseDto<?> apiResponse) {
|
||||||
// ApiResponseDto에 설정된 httpStatus를 실제 HTTP 응답에 적용
|
|
||||||
response.setStatusCode(apiResponse.getHttpStatus());
|
response.setStatusCode(apiResponse.getHttpStatus());
|
||||||
|
|
||||||
String ip = ApiLogFunction.getClientIp(servletRequest);
|
String ip = ApiLogFunction.getClientIp(servletRequest);
|
||||||
|
|
||||||
Long userid = null;
|
Long userid = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth 이 요청이
|
|
||||||
* JWT 인증을 통과한 요청인가? 그리고 Spring Security Authentication 객체가
|
|
||||||
* UsernamePasswordAuthenticationToken 타입인가? 체크
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* auth.getPrincipal() instanceof CustomUserDetails customUserDetails principal 안에 들어있는 객체가 내가
|
|
||||||
* 만든 CustomUserDetails 타입인가? 체크
|
|
||||||
*/
|
|
||||||
if (servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth
|
if (servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth
|
||||||
&& auth.getPrincipal() instanceof CustomUserDetails customUserDetails) {
|
&& auth.getPrincipal() instanceof CustomUserDetails customUserDetails) {
|
||||||
|
|
||||||
// audit 에는 long 타입 user_id가 들어가지만 토큰 sub은 uuid여서 user_id 가져오기
|
|
||||||
userid = customUserDetails.getMember().getId();
|
userid = customUserDetails.getMember().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
String requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper);
|
String requestBody;
|
||||||
requestBody = maskSensitiveFields(requestBody); // 로그 저장전에 중요정보 마스킹
|
// 멀티파트 요청은 바디 로깅을 생략 (파일 바이너리로 인한 문제 예방)
|
||||||
|
MediaType reqContentType = null;
|
||||||
|
try {
|
||||||
|
String ct = servletRequest.getContentType();
|
||||||
|
reqContentType = ct != null ? MediaType.valueOf(ct) : null;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
if (reqContentType != null && MediaType.MULTIPART_FORM_DATA.includes(reqContentType)) {
|
||||||
|
requestBody = "(multipart omitted)";
|
||||||
|
} else {
|
||||||
|
requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper);
|
||||||
|
requestBody = maskSensitiveFields(requestBody);
|
||||||
|
}
|
||||||
|
|
||||||
List<?> list = menuService.getFindAll();
|
List<?> list = menuService.getFindAll();
|
||||||
|
|
||||||
List<MenuDto.Basic> result =
|
List<MenuDto.Basic> result =
|
||||||
list.stream()
|
list.stream()
|
||||||
.map(
|
.map(
|
||||||
@@ -111,7 +112,6 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
|
|||||||
servletRequest.getRequestURI(),
|
servletRequest.getRequestURI(),
|
||||||
requestBody,
|
requestBody,
|
||||||
apiResponse.getErrorLogUid());
|
apiResponse.getErrorLogUid());
|
||||||
// tb_audit_log 테이블 저장
|
|
||||||
auditLogRepository.save(log);
|
auditLogRepository.save(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,9 @@ public class MapSheetMngFileCheckerApiController {
|
|||||||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
public ApiResponseDto<String> uploadFile(
|
public ApiResponseDto<String> uploadFile(
|
||||||
@RequestPart("file") MultipartFile file,
|
@RequestPart("file") MultipartFile file,
|
||||||
@RequestParam("targetPath") String targetPath) {
|
@RequestParam("targetPath") String targetPath,
|
||||||
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.uploadFile(file, targetPath));
|
@RequestParam(value = "overwrite", required = false, defaultValue = "false") boolean overwrite) {
|
||||||
|
return ApiResponseDto.createOK(mapSheetMngFileCheckerService.uploadFile(file, targetPath, overwrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
@Operation(summary = "파일 삭제", description = "중복 파일 등 파일 삭제")
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.mapsheet.service;
|
|||||||
|
|
||||||
import static java.lang.String.CASE_INSENSITIVE_ORDER;
|
import static java.lang.String.CASE_INSENSITIVE_ORDER;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.DuplicateFileException;
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.ValidationException;
|
||||||
import com.kamco.cd.kamcoback.common.utils.FIleChecker;
|
import com.kamco.cd.kamcoback.common.utils.FIleChecker;
|
||||||
import com.kamco.cd.kamcoback.common.utils.NameValidator;
|
import com.kamco.cd.kamcoback.common.utils.NameValidator;
|
||||||
import com.kamco.cd.kamcoback.config.FileConfig;
|
import com.kamco.cd.kamcoback.config.FileConfig;
|
||||||
@@ -14,6 +16,8 @@ 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.ImageryDto;
|
import com.kamco.cd.kamcoback.mapsheet.dto.ImageryDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngFileCheckerCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MapSheetMngFileCheckerCoreService;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngFileEntity;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.repository.mapsheet.MapSheetMngFileRepository;
|
||||||
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;
|
||||||
@@ -31,6 +35,7 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@@ -42,6 +47,10 @@ public class MapSheetMngFileCheckerService {
|
|||||||
|
|
||||||
private final MapSheetMngFileCheckerCoreService mapSheetMngFileCheckerCoreService;
|
private final MapSheetMngFileCheckerCoreService mapSheetMngFileCheckerCoreService;
|
||||||
private final FileConfig fileConfig;
|
private final FileConfig fileConfig;
|
||||||
|
private final MapSheetMngFileRepository mapSheetMngFileRepository;
|
||||||
|
|
||||||
|
@Value("${mapsheet.upload.skipGdalValidation:false}")
|
||||||
|
private boolean skipGdalValidation;
|
||||||
|
|
||||||
public FoldersDto getFolderAll(SrchFoldersDto srchDto) {
|
public FoldersDto getFolderAll(SrchFoldersDto srchDto) {
|
||||||
|
|
||||||
@@ -308,41 +317,145 @@ public class MapSheetMngFileCheckerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public String uploadFile(MultipartFile file, String targetPath) {
|
public String uploadFile(MultipartFile file, String targetPath, boolean overwrite) {
|
||||||
try {
|
try {
|
||||||
Path path = Paths.get(targetPath);
|
Path path = Paths.get(targetPath);
|
||||||
// If targetPath is a directory, append the original filename
|
|
||||||
if (Files.isDirectory(path)) {
|
if (Files.isDirectory(path)) {
|
||||||
path = path.resolve(file.getOriginalFilename());
|
path = path.resolve(file.getOriginalFilename());
|
||||||
} else if (Files.notExists(path) && Files.isDirectory(path.getParent())) {
|
|
||||||
// If path doesn't exist but parent is a directory, assume it's the full path
|
|
||||||
// (No change needed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure parent directory exists
|
|
||||||
if (path.getParent() != null) {
|
if (path.getParent() != null) {
|
||||||
Files.createDirectories(path.getParent());
|
Files.createDirectories(path.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save file
|
String filename = path.getFileName().toString();
|
||||||
|
String ext = FilenameUtils.getExtension(filename).toLowerCase();
|
||||||
|
String baseName = FilenameUtils.getBaseName(filename);
|
||||||
|
Path tfwPath =
|
||||||
|
path.getParent() == null
|
||||||
|
? Paths.get(baseName + ".tfw")
|
||||||
|
: path.getParent().resolve(baseName + ".tfw");
|
||||||
|
Path tifPath =
|
||||||
|
path.getParent() == null
|
||||||
|
? Paths.get(baseName + ".tif")
|
||||||
|
: path.getParent().resolve(baseName + ".tif");
|
||||||
|
|
||||||
|
// 이미 존재하는 경우 처리
|
||||||
|
if (Files.exists(path) && !overwrite) {
|
||||||
|
throw new DuplicateFileException("동일한 파일이 이미 존재합니다: " + path.getFileName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 업로드 파일 저장(덮어쓰기 허용 시 replace)
|
||||||
file.transferTo(path.toFile());
|
file.transferTo(path.toFile());
|
||||||
|
|
||||||
// Check TIF using Gdal functionality
|
if ("tfw".equals(ext)) {
|
||||||
String ext = FilenameUtils.getExtension(path.getFileName().toString());
|
// TFW 검증
|
||||||
if ("tif".equalsIgnoreCase(ext) || "tiff".equalsIgnoreCase(ext)) {
|
boolean tfwOk = FIleChecker.checkTfw(path.toString());
|
||||||
boolean isValid = FIleChecker.cmmndGdalInfo(path.toString());
|
if (!tfwOk) {
|
||||||
if (!isValid) {
|
Files.deleteIfExists(path);
|
||||||
Files.delete(path); // Delete invalid file
|
throw new ValidationException(
|
||||||
throw new RuntimeException("유효하지 않은 TIF 파일입니다 (Gdal 검증 실패).");
|
"유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + path.getFileName());
|
||||||
}
|
}
|
||||||
|
// 안내: 같은 베이스의 TIF가 없으면 추후 TIF 업로드 필요
|
||||||
|
if (!Files.exists(tifPath)) {
|
||||||
|
// DB 메타 저장은 진행 (향후 쌍 검증 위해)
|
||||||
|
saveUploadMeta(path);
|
||||||
|
return "TFW 업로드 성공 (매칭되는 TIF가 아직 없습니다).";
|
||||||
|
}
|
||||||
|
// TIF가 존재하면 쌍 요건 충족
|
||||||
|
saveUploadMeta(path);
|
||||||
|
return "TFW 업로드 성공";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("tif".equals(ext) || "tiff".equals(ext)) {
|
||||||
|
// GDAL 검증 (플래그에 따라 스킵)
|
||||||
|
if (!skipGdalValidation) {
|
||||||
|
boolean isValidTif = FIleChecker.cmmndGdalInfo(path.toString());
|
||||||
|
if (!isValidTif) {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
throw new ValidationException("유효하지 않은 TIF 파일입니다 (GDAL 검증 실패): " + path.getFileName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TFW 존재/검증
|
||||||
|
if (!Files.exists(tfwPath)) {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
throw new ValidationException("TFW 파일이 존재하지 않습니다: " + tfwPath.getFileName());
|
||||||
|
}
|
||||||
|
boolean tfwOk = FIleChecker.checkTfw(tfwPath.toString());
|
||||||
|
if (!tfwOk) {
|
||||||
|
Files.deleteIfExists(path);
|
||||||
|
throw new ValidationException(
|
||||||
|
"유효하지 않은 TFW 파일입니다 (6줄 숫자 형식 검증 실패): " + tfwPath.getFileName());
|
||||||
|
}
|
||||||
|
saveUploadMeta(path);
|
||||||
|
return skipGdalValidation ? "TIF 업로드 성공(GDAL 검증 스킵)" : "TIF 업로드 성공";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기타 확장자: 저장만 하고 메타 기록
|
||||||
|
saveUploadMeta(path);
|
||||||
|
|
||||||
return "업로드 성공";
|
return "업로드 성공";
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException("파일 업로드 실패: " + e.getMessage());
|
throw new IllegalArgumentException("파일 I/O 처리 실패: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void saveUploadMeta(Path savedPath) {
|
||||||
|
String fullPath = savedPath.toAbsolutePath().toString();
|
||||||
|
String fileName = savedPath.getFileName().toString();
|
||||||
|
String ext = FilenameUtils.getExtension(fileName);
|
||||||
|
|
||||||
|
// 연도(mng_yyyy) 추출: 경로 내의 연도 폴더명을 찾음 (예: .../original-images/2022/2022_25cm/...)
|
||||||
|
Integer mngYyyy = extractYearFromPath(fullPath);
|
||||||
|
|
||||||
|
// 도엽번호(map_sheet_num) 추정: 파일명 내 숫자 연속 부분을 추출해 정수화
|
||||||
|
String mapSheetNum = extractMapSheetNumFromFileName(fileName);
|
||||||
|
|
||||||
|
// ref_map_sheet_num: 1000으로 나눈 값(파일명 규칙에 따라 추정)
|
||||||
|
String refMapSheetNum = null;
|
||||||
|
if (mapSheetNum != null && !mapSheetNum.isEmpty()) {
|
||||||
|
try {
|
||||||
|
long num = Long.parseLong(mapSheetNum);
|
||||||
|
refMapSheetNum = String.valueOf(num / 1000);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MapSheetMngFileEntity entity = new MapSheetMngFileEntity();
|
||||||
|
entity.setMngYyyy(mngYyyy);
|
||||||
|
entity.setMapSheetNum(mapSheetNum);
|
||||||
|
entity.setRefMapSheetNum(refMapSheetNum);
|
||||||
|
entity.setFilePath(savedPath.getParent() != null ? savedPath.getParent().toString() : "");
|
||||||
|
entity.setFileName(fileName);
|
||||||
|
entity.setFileExt(ext);
|
||||||
|
|
||||||
|
mapSheetMngFileRepository.save(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer extractYearFromPath(String fullPath) {
|
||||||
|
// 경로에서 4자리 연도를 찾아 가장 근접한 값을 사용
|
||||||
|
// 예시 경로: /Users/.../original-images/2022/2022_25cm/1/34602
|
||||||
|
String[] parts = fullPath.split("/");
|
||||||
|
for (String p : parts) {
|
||||||
|
if (p.matches("\\d{4}")) {
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(p);
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractMapSheetNumFromFileName(String fileName) {
|
||||||
|
// 파일명에서 연속된 숫자를 최대한 찾아 사용 (예: 34602027.tif -> 34602027)
|
||||||
|
String base = FilenameUtils.getBaseName(fileName);
|
||||||
|
String digits = base.replaceAll("[^0-9]", "");
|
||||||
|
if (!digits.isEmpty()) {
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Boolean deleteFile(String filePath) {
|
public Boolean deleteFile(String filePath) {
|
||||||
try {
|
try {
|
||||||
@@ -352,4 +465,22 @@ public class MapSheetMngFileCheckerService {
|
|||||||
throw new RuntimeException("파일 삭제 실패: " + e.getMessage());
|
throw new RuntimeException("파일 삭제 실패: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public List<MapSheetMngFileEntity> findRecentFiles(int limit) {
|
||||||
|
// 간단히 전체를 불러 정렬/제한 (운영에선 Page 요청으로 변경 권장)
|
||||||
|
List<MapSheetMngFileEntity> all = new ArrayList<>();
|
||||||
|
mapSheetMngFileRepository.findAll().forEach(all::add);
|
||||||
|
all.sort(
|
||||||
|
(a, b) -> {
|
||||||
|
// fileUid 기준 내림차순
|
||||||
|
long av = a.getFileUid() == null ? 0L : a.getFileUid();
|
||||||
|
long bv = b.getFileUid() == null ? 0L : b.getFileUid();
|
||||||
|
return Long.compare(bv, av);
|
||||||
|
});
|
||||||
|
if (all.size() > limit) {
|
||||||
|
return all.subList(0, limit);
|
||||||
|
}
|
||||||
|
return all;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.apache.commons.io.FilenameUtils;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
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.PutMapping;
|
||||||
@@ -87,24 +86,4 @@ public class AdminApiController {
|
|||||||
adminService.updateMembers(uuid, updateReq);
|
adminService.updateMembers(uuid, updateReq);
|
||||||
return ApiResponseDto.createOK(UUID.randomUUID());
|
return ApiResponseDto.createOK(UUID.randomUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@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)
|
|
||||||
})
|
|
||||||
@DeleteMapping("/delete/{uuid}")
|
|
||||||
public ApiResponseDto<UUID> deleteAccount(@PathVariable UUID uuid) {
|
|
||||||
adminService.deleteAccount(uuid);
|
|
||||||
return ApiResponseDto.createOK(uuid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ public class AuthController {
|
|||||||
MembersDto.Member member = new MembersDto.Member();
|
MembersDto.Member member = new MembersDto.Member();
|
||||||
|
|
||||||
// 비활성 상태면 임시패스워드를 비교함
|
// 비활성 상태면 임시패스워드를 비교함
|
||||||
if (StatusType.INACTIVE.getId().equals(status)) {
|
if (StatusType.PENDING.getId().equals(status)) {
|
||||||
if (!authService.isTempPasswordValid(request)) {
|
if (!authService.isTempPasswordValid(request)) {
|
||||||
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
}
|
}
|
||||||
@@ -124,8 +124,9 @@ public class AuthController {
|
|||||||
request.getUsername(), request.getPassword()));
|
request.getUsername(), request.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// INACTIVE 비활성 상태(새로운 패스워드 입력 해야함), DELETED 탈퇴
|
// PENDING 비활성 상태(새로운 패스워드 입력 해야함)
|
||||||
if (!StatusType.ACTIVE.getId().equals(status)) {
|
if (StatusType.PENDING.getId().equals(status)) {
|
||||||
|
member.setEmployeeNo(request.getUsername());
|
||||||
return ApiResponseDto.ok(new TokenResponse(status, null, null, member));
|
return ApiResponseDto.ok(new TokenResponse(status, null, null, member));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springdoc.core.annotations.ParameterObject;
|
import org.springdoc.core.annotations.ParameterObject;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PatchMapping;
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@@ -70,10 +69,6 @@ public class MembersApiController {
|
|||||||
@PatchMapping("/{memberId}/password")
|
@PatchMapping("/{memberId}/password")
|
||||||
public ApiResponseDto<String> resetPassword(
|
public ApiResponseDto<String> resetPassword(
|
||||||
@PathVariable String memberId, @RequestBody @Valid MembersDto.InitReq initReq) {
|
@PathVariable String memberId, @RequestBody @Valid MembersDto.InitReq initReq) {
|
||||||
|
|
||||||
authenticationManager.authenticate(
|
|
||||||
new UsernamePasswordAuthenticationToken(memberId, initReq.getTempPassword()));
|
|
||||||
|
|
||||||
membersService.resetPassword(memberId, initReq);
|
membersService.resetPassword(memberId, initReq);
|
||||||
return ApiResponseDto.createOK(memberId);
|
return ApiResponseDto.createOK(memberId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,32 +108,26 @@ public class MembersDto {
|
|||||||
|
|
||||||
@Schema(description = "관리자 유형", example = "ADMIN")
|
@Schema(description = "관리자 유형", example = "ADMIN")
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER만 가능합니다.")
|
@EnumValid(enumClass = RoleType.class, message = "userRole은 ADMIN, LABELER, REVIEWER 만 가능합니다.")
|
||||||
private String userRole;
|
private String userRole;
|
||||||
|
|
||||||
|
@Schema(description = "사번", example = "K20251212001")
|
||||||
|
@Size(max = 50)
|
||||||
|
private String employeeNo;
|
||||||
|
|
||||||
@Schema(description = "이름", example = "홍길동")
|
@Schema(description = "이름", example = "홍길동")
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Schema(description = "ID", example = "gildong")
|
|
||||||
@NotBlank
|
|
||||||
@Size(min = 2, max = 50)
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
@Schema(description = "임시 비밀번호", example = "q!w@e#r4")
|
@Schema(description = "임시 비밀번호", example = "q!w@e#r4")
|
||||||
private String tempPassword;
|
private String tempPassword;
|
||||||
|
|
||||||
@Schema(description = "사번", example = "123456")
|
public AddReq(String userRole, String employeeNo, String name, String tempPassword) {
|
||||||
private String employeeNo;
|
|
||||||
|
|
||||||
public AddReq(
|
|
||||||
String userRole, String name, String userId, String tempPassword, String employeeNo) {
|
|
||||||
this.userRole = userRole;
|
this.userRole = userRole;
|
||||||
this.name = name;
|
|
||||||
this.userId = userId;
|
|
||||||
this.tempPassword = tempPassword;
|
|
||||||
this.employeeNo = employeeNo;
|
this.employeeNo = employeeNo;
|
||||||
|
this.name = name;
|
||||||
|
this.tempPassword = tempPassword;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +135,6 @@ public class MembersDto {
|
|||||||
@Setter
|
@Setter
|
||||||
public static class UpdateReq {
|
public static class UpdateReq {
|
||||||
|
|
||||||
@Schema(description = "사번, 패스워드 변경시 필수 값", example = "11111")
|
|
||||||
@Size(max = 50)
|
|
||||||
private String employeeNo;
|
|
||||||
|
|
||||||
@Schema(description = "이름", example = "홍길동")
|
@Schema(description = "이름", example = "홍길동")
|
||||||
@Size(min = 2, max = 100)
|
@Size(min = 2, max = 100)
|
||||||
private String name;
|
private String name;
|
||||||
@@ -157,8 +147,7 @@ public class MembersDto {
|
|||||||
@EnumValid(enumClass = StatusType.class, message = "status는 ACTIVE, INACTIVE, DELETED 만 가능합니다.")
|
@EnumValid(enumClass = StatusType.class, message = "status는 ACTIVE, INACTIVE, DELETED 만 가능합니다.")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
public UpdateReq(String employeeNo, String name, String tempPassword, String status) {
|
public UpdateReq(String name, String tempPassword, String status) {
|
||||||
this.employeeNo = employeeNo;
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.tempPassword = tempPassword;
|
this.tempPassword = tempPassword;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class MemberException {
|
|||||||
|
|
||||||
public enum Field {
|
public enum Field {
|
||||||
USER_ID,
|
USER_ID,
|
||||||
|
EMPLOYEE_NO,
|
||||||
DEFAULT
|
DEFAULT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package com.kamco.cd.kamcoback.members.service;
|
package com.kamco.cd.kamcoback.members.service;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
||||||
|
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@@ -22,6 +26,10 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public Long saveMember(MembersDto.AddReq addReq) {
|
public Long saveMember(MembersDto.AddReq addReq) {
|
||||||
|
if (!CommonStringUtils.isValidPassword(addReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
return membersCoreService.saveMembers(addReq);
|
return membersCoreService.saveMembers(addReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,16 +41,12 @@ public class AdminService {
|
|||||||
*/
|
*/
|
||||||
@Transactional
|
@Transactional
|
||||||
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
public void updateMembers(UUID uuid, MembersDto.UpdateReq updateReq) {
|
||||||
membersCoreService.updateMembers(uuid, updateReq);
|
if (StatusType.INACTIVE.getId().equals(updateReq.getStatus())) {
|
||||||
}
|
// 미사용 처리
|
||||||
|
membersCoreService.deleteMember(uuid);
|
||||||
/**
|
} else {
|
||||||
* 관리자 계정 미사용 처리
|
// 수정
|
||||||
*
|
membersCoreService.updateMembers(uuid, updateReq);
|
||||||
* @param uuid
|
}
|
||||||
*/
|
|
||||||
@Transactional
|
|
||||||
public void deleteAccount(UUID uuid) {
|
|
||||||
membersCoreService.deleteAccount(uuid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package com.kamco.cd.kamcoback.members.service;
|
package com.kamco.cd.kamcoback.members.service;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
||||||
|
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto.Basic;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MembersCoreService;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -37,21 +37,9 @@ public class MembersService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
||||||
|
|
||||||
if (!isValidPassword(initReq.getPassword())) {
|
if (!CommonStringUtils.isValidPassword(initReq.getPassword())) {
|
||||||
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
membersCoreService.resetPassword(id, initReq);
|
membersCoreService.resetPassword(id, initReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 영문, 숫자, 특수문자를 모두 포함하여 8~20자 이내의 비밀번호
|
|
||||||
*
|
|
||||||
* @param password
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isValidPassword(String password) {
|
|
||||||
String passwordPattern =
|
|
||||||
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[!@#$%^&*()_+\\-\\[\\]{};':\"\\\\|,.<>/?]).{8,20}$";
|
|
||||||
return Pattern.matches(passwordPattern, password);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ApiResponseCode;
|
|||||||
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto.ResponseObj;
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.CommonCodeEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.repository.code.CommonCodeRepository;
|
import com.kamco.cd.kamcoback.postgres.repository.code.CommonCodeRepository;
|
||||||
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.SearchReq;
|
import com.kamco.cd.kamcoback.code.dto.CommonCodeDto.SearchReq;
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ package com.kamco.cd.kamcoback.postgres.core;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
|
import com.kamco.cd.kamcoback.auth.BCryptSaltGenerator;
|
||||||
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
import com.kamco.cd.kamcoback.common.enums.StatusType;
|
||||||
|
import com.kamco.cd.kamcoback.common.enums.error.AuthErrorCode;
|
||||||
|
import com.kamco.cd.kamcoback.common.exception.CustomApiException;
|
||||||
|
import com.kamco.cd.kamcoback.common.utils.CommonStringUtils;
|
||||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto;
|
||||||
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
|
import com.kamco.cd.kamcoback.members.dto.MembersDto.AddReq;
|
||||||
@@ -18,6 +21,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.mindrot.jbcrypt.BCrypt;
|
import org.mindrot.jbcrypt.BCrypt;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -34,8 +38,8 @@ public class MembersCoreService {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Long saveMembers(AddReq addReq) {
|
public Long saveMembers(AddReq addReq) {
|
||||||
if (membersRepository.existsByUserId(addReq.getUserId())) {
|
if (membersRepository.existsByEmployeeNo(addReq.getEmployeeNo())) {
|
||||||
throw new DuplicateMemberException(Field.USER_ID, addReq.getUserId());
|
throw new DuplicateMemberException(Field.EMPLOYEE_NO, addReq.getEmployeeNo());
|
||||||
}
|
}
|
||||||
|
|
||||||
// salt 생성, 사번이 salt
|
// salt 생성, 사번이 salt
|
||||||
@@ -44,7 +48,7 @@ public class MembersCoreService {
|
|||||||
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
|
String hashedPassword = BCrypt.hashpw(addReq.getTempPassword(), salt);
|
||||||
|
|
||||||
MemberEntity memberEntity = new MemberEntity();
|
MemberEntity memberEntity = new MemberEntity();
|
||||||
memberEntity.setUserId(addReq.getUserId());
|
memberEntity.setUserId(addReq.getEmployeeNo());
|
||||||
memberEntity.setUserRole(addReq.getUserRole());
|
memberEntity.setUserRole(addReq.getUserRole());
|
||||||
memberEntity.setTempPassword(addReq.getTempPassword().trim()); // 임시 패스워드는 암호화 하지 않음
|
memberEntity.setTempPassword(addReq.getTempPassword().trim()); // 임시 패스워드는 암호화 하지 않음
|
||||||
memberEntity.setPassword(hashedPassword);
|
memberEntity.setPassword(hashedPassword);
|
||||||
@@ -71,41 +75,35 @@ public class MembersCoreService {
|
|||||||
|
|
||||||
// 임시 패스워드는 암호화 하지 않음
|
// 임시 패스워드는 암호화 하지 않음
|
||||||
if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
|
if (StringUtils.isNotBlank(updateReq.getTempPassword())) {
|
||||||
// 임시 패스워드가 기존과 다르면 패스워드 변경으로 처리함
|
/**
|
||||||
// 상태 INACTIVE로 변경하여 사용자가 로그인할때 패스워드 변경하게함
|
* 임시 패스워드가 기존과 다르면 패스워드 변경으로 처리함 상태 PENDING 으로 변경하여 사용자가 로그인할때 패스워드 변경하게함 패스워드 리셋이므로 로그인
|
||||||
// 패스워드 리셋이므로 로그인 실패카운트 초기화처리함
|
* 실패카운트 초기화처리함
|
||||||
|
*/
|
||||||
if (!memberEntity.getTempPassword().equals(updateReq.getTempPassword().trim())) {
|
if (!memberEntity.getTempPassword().equals(updateReq.getTempPassword().trim())) {
|
||||||
memberEntity.setStatus(StatusType.INACTIVE.getId());
|
// 패스워드 유효성 검사
|
||||||
|
if (!CommonStringUtils.isValidPassword(updateReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException("WRONG_PASSWORD", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
memberEntity.setStatus(StatusType.PENDING.getId());
|
||||||
memberEntity.setLoginFailCount(0);
|
memberEntity.setLoginFailCount(0);
|
||||||
}
|
}
|
||||||
memberEntity.setTempPassword(updateReq.getTempPassword().trim());
|
memberEntity.setTempPassword(updateReq.getTempPassword().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(updateReq.getEmployeeNo())) {
|
|
||||||
memberEntity.setEmployeeNo(updateReq.getEmployeeNo());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(updateReq.getStatus())) {
|
|
||||||
memberEntity.setStatus(updateReq.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
memberEntity.setUpdtrUid(userUtil.getId());
|
memberEntity.setUpdtrUid(userUtil.getId());
|
||||||
|
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 관리자 계정 삭제 처리
|
* 미사용 처리
|
||||||
*
|
*
|
||||||
* @param uuid
|
* @param uuid
|
||||||
*/
|
*/
|
||||||
public void deleteAccount(UUID uuid) {
|
public void deleteMember(UUID uuid) {
|
||||||
MemberEntity memberEntity =
|
MemberEntity memberEntity =
|
||||||
membersRepository.findByUUID(uuid).orElseThrow(() -> new MemberNotFoundException());
|
membersRepository.findByUUID(uuid).orElseThrow(MemberNotFoundException::new);
|
||||||
|
memberEntity.setStatus(StatusType.INACTIVE.getId());
|
||||||
memberEntity.setStatus(StatusType.DELETED.getId());
|
|
||||||
memberEntity.setUpdatedDttm(ZonedDateTime.now());
|
|
||||||
memberEntity.setUpdtrUid(userUtil.getId());
|
|
||||||
membersRepository.save(memberEntity);
|
membersRepository.save(memberEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +114,12 @@ public class MembersCoreService {
|
|||||||
*/
|
*/
|
||||||
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
public void resetPassword(String id, MembersDto.InitReq initReq) {
|
||||||
MemberEntity memberEntity =
|
MemberEntity memberEntity =
|
||||||
membersRepository.findByUserId(id).orElseThrow(() -> new MemberNotFoundException());
|
membersRepository.findByEmployeeNo(id).orElseThrow(() -> new MemberNotFoundException());
|
||||||
|
|
||||||
|
// 임시 패스워드 확인
|
||||||
|
if (!memberEntity.getTempPassword().equals(initReq.getTempPassword())) {
|
||||||
|
throw new CustomApiException(AuthErrorCode.LOGIN_PASSWORD_MISMATCH);
|
||||||
|
}
|
||||||
|
|
||||||
String salt =
|
String salt =
|
||||||
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
|
BCryptSaltGenerator.generateSaltWithEmployeeNo(memberEntity.getEmployeeNo().trim());
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class MemberEntity {
|
|||||||
@Size(max = 20)
|
@Size(max = 20)
|
||||||
@ColumnDefault("'INACTIVE'")
|
@ColumnDefault("'INACTIVE'")
|
||||||
@Column(name = "status", length = 20)
|
@Column(name = "status", length = 20)
|
||||||
private String status = StatusType.INACTIVE.getId();
|
private String status = StatusType.PENDING.getId();
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@ColumnDefault("now()")
|
@ColumnDefault("now()")
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package com.kamco.cd.kamcoback.postgres.repository.mapsheet;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.postgres.entity.MapSheetMngFileEntity;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
public interface MapSheetMngFileRepository extends JpaRepository<MapSheetMngFileEntity, Long> {}
|
||||||
@@ -170,48 +170,53 @@ public class MapSheetMngRepositoryImpl extends QuerydslRepositorySupport
|
|||||||
@Override
|
@Override
|
||||||
public void deleteByMngYyyyMngAll(int mngYyyy) {
|
public void deleteByMngYyyyMngAll(int mngYyyy) {
|
||||||
|
|
||||||
long deletedFileCount = queryFactory
|
long deletedFileCount =
|
||||||
.delete(mapSheetMngFileEntity)
|
queryFactory
|
||||||
.where(mapSheetMngFileEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngFileEntity)
|
||||||
.execute();
|
.where(mapSheetMngFileEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
|
|
||||||
long deletedHisCount = queryFactory
|
long deletedHisCount =
|
||||||
.delete(mapSheetMngHstEntity)
|
queryFactory
|
||||||
.where(mapSheetMngHstEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngHstEntity)
|
||||||
.execute();
|
.where(mapSheetMngHstEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
|
|
||||||
long deletedMngCount = queryFactory
|
long deletedMngCount =
|
||||||
.delete(mapSheetMngEntity)
|
queryFactory
|
||||||
.where(mapSheetMngEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngEntity)
|
||||||
.execute();
|
.where(mapSheetMngEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteByMngYyyyMng(int mngYyyy) {
|
public void deleteByMngYyyyMng(int mngYyyy) {
|
||||||
|
|
||||||
long deletedMngCount = queryFactory
|
long deletedMngCount =
|
||||||
.delete(mapSheetMngEntity)
|
queryFactory
|
||||||
.where(mapSheetMngEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngEntity)
|
||||||
.execute();
|
.where(mapSheetMngEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteByMngYyyyMngHst(int mngYyyy) {
|
public void deleteByMngYyyyMngHst(int mngYyyy) {
|
||||||
|
|
||||||
long deletedHisCount = queryFactory
|
long deletedHisCount =
|
||||||
.delete(mapSheetMngHstEntity)
|
queryFactory
|
||||||
.where(mapSheetMngHstEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngHstEntity)
|
||||||
.execute();
|
.where(mapSheetMngHstEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteByMngYyyyMngFile(int mngYyyy) {
|
public void deleteByMngYyyyMngFile(int mngYyyy) {
|
||||||
|
|
||||||
long deletedFileCount = queryFactory
|
long deletedFileCount =
|
||||||
.delete(mapSheetMngFileEntity)
|
queryFactory
|
||||||
.where(mapSheetMngFileEntity.mngYyyy.eq(mngYyyy))
|
.delete(mapSheetMngFileEntity)
|
||||||
.execute();
|
.where(mapSheetMngFileEntity.mngYyyy.eq(mngYyyy))
|
||||||
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public interface MembersRepositoryCustom {
|
|||||||
|
|
||||||
boolean existsByUserId(String userId);
|
boolean existsByUserId(String userId);
|
||||||
|
|
||||||
|
boolean existsByEmployeeNo(String employeeNo);
|
||||||
|
|
||||||
|
Optional<MemberEntity> findByEmployeeNo(String employeeNo);
|
||||||
|
|
||||||
Optional<MemberEntity> findByUserId(String userId);
|
Optional<MemberEntity> findByUserId(String userId);
|
||||||
|
|
||||||
Optional<MemberEntity> findByUUID(UUID uuid);
|
Optional<MemberEntity> findByUUID(UUID uuid);
|
||||||
|
|||||||
@@ -40,6 +40,22 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
|||||||
!= null;
|
!= null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사용자 사번 조회
|
||||||
|
*
|
||||||
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean existsByEmployeeNo(String employeeNo) {
|
||||||
|
return queryFactory
|
||||||
|
.selectOne()
|
||||||
|
.from(memberEntity)
|
||||||
|
.where(memberEntity.employeeNo.eq(employeeNo))
|
||||||
|
.fetchFirst()
|
||||||
|
!= null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 사용자 조회 user id
|
* 사용자 조회 user id
|
||||||
*
|
*
|
||||||
@@ -52,6 +68,21 @@ public class MembersRepositoryImpl implements MembersRepositoryCustom {
|
|||||||
queryFactory.selectFrom(memberEntity).where(memberEntity.userId.eq(userId)).fetchOne());
|
queryFactory.selectFrom(memberEntity).where(memberEntity.userId.eq(userId)).fetchOne());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사용자 조회 employeed no
|
||||||
|
*
|
||||||
|
* @param employeeNo
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<MemberEntity> findByEmployeeNo(String employeeNo) {
|
||||||
|
return Optional.ofNullable(
|
||||||
|
queryFactory
|
||||||
|
.selectFrom(memberEntity)
|
||||||
|
.where(memberEntity.employeeNo.eq(employeeNo))
|
||||||
|
.fetchOne());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 회원정보 목록 조회
|
* 회원정보 목록 조회
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -35,6 +35,16 @@ spring:
|
|||||||
port: 6379
|
port: 6379
|
||||||
password: kamco
|
password: kamco
|
||||||
|
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
enabled: true
|
||||||
|
max-file-size: 1024MB
|
||||||
|
max-request-size: 2048MB
|
||||||
|
file-size-threshold: 10MB
|
||||||
|
|
||||||
|
server:
|
||||||
|
tomcat:
|
||||||
|
max-swallow-size: 2097152000 # 약 2GB
|
||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
secret: "kamco_token_9b71e778-19a3-4c1d-97bf-2d687de17d5b"
|
||||||
@@ -47,3 +57,15 @@ token:
|
|||||||
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
|
refresh-cookie-name: kamco-dev # 개발용 쿠키 이름
|
||||||
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
refresh-cookie-secure: false # 로컬 http 테스트면 false
|
||||||
|
|
||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org:
|
||||||
|
springframework:
|
||||||
|
security: DEBUG
|
||||||
|
org.springframework.security: DEBUG
|
||||||
|
|
||||||
|
mapsheet:
|
||||||
|
upload:
|
||||||
|
skipGdalValidation: true
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ logging:
|
|||||||
web: DEBUG
|
web: DEBUG
|
||||||
security: DEBUG
|
security: DEBUG
|
||||||
root: INFO
|
root: INFO
|
||||||
|
org.springframework.security: DEBUG
|
||||||
# actuator
|
# actuator
|
||||||
management:
|
management:
|
||||||
health:
|
health:
|
||||||
@@ -77,4 +78,3 @@ geojson:
|
|||||||
- tar.gz
|
- tar.gz
|
||||||
- tgz
|
- tgz
|
||||||
max-file-size: 104857600 # 100MB
|
max-file-size: 104857600 # 100MB
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user