Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201
# Conflicts: # src/main/java/com/kamco/cd/kamcoback/mapsheet/service/MapSheetMngService.java
This commit is contained in:
@@ -0,0 +1,101 @@
|
|||||||
|
package com.kamco.cd.kamcoback.auth;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
|
import org.springframework.security.authorization.AuthorizationManager;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DB 기반 메뉴 권한 AuthorizationManager
|
||||||
|
*
|
||||||
|
* <p>- Redis 사용 안 함 - ADMIN 예외 없음 (DB 매핑 기준) - 한 계정 = role 1개 - menu_url(prefix) 기반 API 접근 제어
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MenuAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
|
||||||
|
|
||||||
|
private static final Logger log = LogManager.getLogger(MenuAuthorizationManager.class);
|
||||||
|
|
||||||
|
private final MenuRepository menuAuthQueryRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AuthorizationDecision check(
|
||||||
|
Supplier<Authentication> authenticationSupplier, RequestAuthorizationContext context) {
|
||||||
|
|
||||||
|
HttpServletRequest request = context.getRequest();
|
||||||
|
String requestPath = normalizePath(request.getRequestURI());
|
||||||
|
|
||||||
|
Authentication authentication = authenticationSupplier.get();
|
||||||
|
if (authentication == null || !authentication.isAuthenticated()) {
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String role = extractSingleRole(authentication);
|
||||||
|
if (role == null) {
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DB에서 role에 허용된 메뉴 조회
|
||||||
|
List<MenuEntity> allowedMenus = menuAuthQueryRepository.findAllowedMenuUrlsByRole(role);
|
||||||
|
|
||||||
|
if (allowedMenus == null || allowedMenus.isEmpty()) {
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// menu_url(prefix) 기반 접근 허용 판단
|
||||||
|
for (MenuEntity menu : allowedMenus) {
|
||||||
|
String baseUri = menu.getMenuUrl();
|
||||||
|
if (baseUri == null || baseUri.isBlank()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (matchUri(baseUri, requestPath)) {
|
||||||
|
return new AuthorizationDecision(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AuthorizationDecision(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
* role 추출
|
||||||
|
* ========================= */
|
||||||
|
private String extractSingleRole(Authentication authentication) {
|
||||||
|
GrantedAuthority ga = authentication.getAuthorities().stream().findFirst().orElse(null);
|
||||||
|
|
||||||
|
if (ga == null || ga.getAuthority() == null || ga.getAuthority().isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String auth = ga.getAuthority();
|
||||||
|
return auth.startsWith("ROLE_") ? auth.substring(5) : auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
* URI prefix 매칭
|
||||||
|
* ========================= */
|
||||||
|
private boolean matchUri(String baseUri, String requestPath) {
|
||||||
|
String base = normalizePath(baseUri);
|
||||||
|
String req = normalizePath(requestPath);
|
||||||
|
return req.equals(base) || req.startsWith(base + "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* =========================
|
||||||
|
* URI 정규화
|
||||||
|
* ========================= */
|
||||||
|
private String normalizePath(String path) {
|
||||||
|
if (path == null || path.isBlank()) {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
return path.replaceAll("//+", "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,188 +0,0 @@
|
|||||||
package com.kamco.cd.kamcoback.auth;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.kamco.cd.kamcoback.common.enums.RoleType;
|
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
||||||
import org.springframework.security.authorization.AuthorizationDecision;
|
|
||||||
import org.springframework.security.authorization.AuthorizationManager;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/** redis에 등록된 메뉴별 권한 확인 */
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RedisAuthorizationManager
|
|
||||||
implements AuthorizationManager<RequestAuthorizationContext> {
|
|
||||||
|
|
||||||
private static final Logger log = LogManager.getLogger(RedisAuthorizationManager.class);
|
|
||||||
private static final String REDIS_KEY = "auth:api:role";
|
|
||||||
|
|
||||||
private final StringRedisTemplate redisTemplate;
|
|
||||||
private final ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AuthorizationDecision check(
|
|
||||||
Supplier<Authentication> authenticationSupplier, RequestAuthorizationContext context) {
|
|
||||||
|
|
||||||
HttpServletRequest request = context.getRequest();
|
|
||||||
String requestPath = normalizePath(request.getRequestURI());
|
|
||||||
|
|
||||||
Authentication authentication = authenticationSupplier.get();
|
|
||||||
if (authentication == null || !authentication.isAuthenticated()) {
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ADMIN 은 무조건 허용
|
|
||||||
if (hasAdmin(authentication)) {
|
|
||||||
return new AuthorizationDecision(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 사용자 role 목록
|
|
||||||
List<String> userRoles = extractRoles(authentication);
|
|
||||||
if (userRoles.isEmpty()) {
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redis 조회 (1회)
|
|
||||||
String json = redisTemplate.opsForValue().get(REDIS_KEY);
|
|
||||||
if (json == null || json.isBlank()) {
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON 파싱 (1회)
|
|
||||||
List<MenuDto.MenuWithRolesDto> menus = parseMenus(json);
|
|
||||||
if (menus.isEmpty()) {
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// role + prefix URI 매칭
|
|
||||||
for (String role : userRoles) {
|
|
||||||
if (isAllowed(menus, role, requestPath)) {
|
|
||||||
return new AuthorizationDecision(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new AuthorizationDecision(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* 핵심 권한 판별 로직
|
|
||||||
* ========================= */
|
|
||||||
private boolean isAllowed(List<MenuDto.MenuWithRolesDto> menus, String role, String requestPath) {
|
|
||||||
|
|
||||||
for (MenuDto.MenuWithRolesDto menu : menus) {
|
|
||||||
if (menu == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String baseUri = menu.getMenuApiUri();
|
|
||||||
if (baseUri == null || baseUri.isBlank()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// role 포함 여부
|
|
||||||
if (!hasRole(menu.getRoles(), role)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefix URI 허용
|
|
||||||
if (matchUri(baseUri, requestPath)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* URI prefix 매칭
|
|
||||||
* ========================= */
|
|
||||||
private boolean matchUri(String baseUri, String requestPath) {
|
|
||||||
String base = normalizePath(baseUri);
|
|
||||||
String req = normalizePath(requestPath);
|
|
||||||
|
|
||||||
// /api/log/audit → /api/log/audit/**
|
|
||||||
return req.equals(base) || req.startsWith(base + "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* role 문자열 처리
|
|
||||||
* ========================= */
|
|
||||||
private boolean hasRole(String rolesCsv, String targetRole) {
|
|
||||||
if (rolesCsv == null || rolesCsv.isBlank()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (targetRole == null || targetRole.isBlank()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String r : rolesCsv.split(",")) {
|
|
||||||
if (targetRole.equalsIgnoreCase(r.trim())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* Redis JSON 파싱
|
|
||||||
* ========================= */
|
|
||||||
private List<MenuDto.MenuWithRolesDto> parseMenus(String json) {
|
|
||||||
try {
|
|
||||||
return objectMapper.readValue(json, new TypeReference<List<MenuDto.MenuWithRolesDto>>() {});
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Failed to parse redis menu json. key={}", REDIS_KEY, e);
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* ADMIN 판별
|
|
||||||
* ========================= */
|
|
||||||
private boolean hasAdmin(Authentication authentication) {
|
|
||||||
for (GrantedAuthority ga : authentication.getAuthorities()) {
|
|
||||||
if (ga == null || ga.getAuthority() == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String auth = ga.getAuthority();
|
|
||||||
String admin = RoleType.ADMIN.getId();
|
|
||||||
|
|
||||||
if (auth.equals(admin) || auth.equals("ROLE_" + admin)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* ROLE 목록 추출
|
|
||||||
* ========================= */
|
|
||||||
private List<String> extractRoles(Authentication authentication) {
|
|
||||||
return authentication.getAuthorities().stream()
|
|
||||||
.map(GrantedAuthority::getAuthority)
|
|
||||||
.filter(a -> a != null && !a.isBlank())
|
|
||||||
.map(a -> a.startsWith("ROLE_") ? a.substring(5) : a)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* =========================
|
|
||||||
* URI 정규화
|
|
||||||
* ========================= */
|
|
||||||
private String normalizePath(String path) {
|
|
||||||
if (path == null || path.isBlank()) {
|
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
return path.replaceAll("//+", "/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ package com.kamco.cd.kamcoback.config;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.auth.CustomAuthenticationProvider;
|
import com.kamco.cd.kamcoback.auth.CustomAuthenticationProvider;
|
||||||
import com.kamco.cd.kamcoback.auth.JwtAuthenticationFilter;
|
import com.kamco.cd.kamcoback.auth.JwtAuthenticationFilter;
|
||||||
import com.kamco.cd.kamcoback.auth.RedisAuthorizationManager;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -29,7 +28,6 @@ public class SecurityConfig {
|
|||||||
|
|
||||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||||
private final CustomAuthenticationProvider customAuthenticationProvider;
|
private final CustomAuthenticationProvider customAuthenticationProvider;
|
||||||
private final RedisAuthorizationManager redisAuthorizationManager;
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
|||||||
@@ -177,7 +177,8 @@ public class MapSheetMngApiController {
|
|||||||
@RequestPart("tif") MultipartFile tifFile,
|
@RequestPart("tif") MultipartFile tifFile,
|
||||||
@RequestParam(value = "hstUid", required = false) Long hstUid,
|
@RequestParam(value = "hstUid", required = false) Long hstUid,
|
||||||
@RequestParam(value = "overwrite", required = false) boolean overwrite) {
|
@RequestParam(value = "overwrite", required = false) boolean overwrite) {
|
||||||
return ApiResponseDto.createOK(mapSheetMngService.uploadPair(tfwFile, tifFile, hstUid, overwrite));
|
return ApiResponseDto.createOK(
|
||||||
|
mapSheetMngService.uploadPair(tfwFile, tifFile, hstUid, overwrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "영상관리 > 파일조회", description = "영상관리 > 파일조회")
|
@Operation(summary = "영상관리 > 파일조회", description = "영상관리 > 파일조회")
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.kamco.cd.kamcoback.menu;
|
package com.kamco.cd.kamcoback.menu;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
|
||||||
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.menu.dto.MenuDto;
|
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||||
@@ -11,17 +10,14 @@ 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 java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
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.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@Tag(name = "메뉴 관리", description = "메뉴 관리 API")
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RequestMapping("/api/menu")
|
@RequestMapping("/api/menu")
|
||||||
@@ -68,43 +64,4 @@ public class MenuApiController {
|
|||||||
|
|
||||||
return ApiResponseDto.ok(ApiLogFunction.getUriMenuInfo(result, apiUri));
|
return ApiResponseDto.ok(ApiLogFunction.getUriMenuInfo(result, apiUri));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "권한별 메뉴 레디스 저장", description = "권한별 메뉴 레디스 저장")
|
|
||||||
@ApiResponses(
|
|
||||||
value = {
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "201",
|
|
||||||
description = "등록 성공",
|
|
||||||
content =
|
|
||||||
@Content(
|
|
||||||
mediaType = "application/json",
|
|
||||||
schema = @Schema(implementation = MenuDto.Basic.class))),
|
|
||||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
|
||||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
|
||||||
})
|
|
||||||
@PostMapping("/auth")
|
|
||||||
public ApiResponseDto<String> getFindByRoleRedis() {
|
|
||||||
menuService.getFindByRoleRedis();
|
|
||||||
return ApiResponseDto.createOK("ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "권한별 메뉴 조회", description = "로그인 권한별 메뉴 목록")
|
|
||||||
@ApiResponses(
|
|
||||||
value = {
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "200",
|
|
||||||
description = "조회 성공",
|
|
||||||
content =
|
|
||||||
@Content(
|
|
||||||
mediaType = "application/json",
|
|
||||||
schema = @Schema(implementation = MenuDto.Basic.class))),
|
|
||||||
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
|
||||||
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
|
||||||
})
|
|
||||||
@GetMapping("/auth")
|
|
||||||
public ApiResponseDto<List<MenuDto.Basic>> getFindAllByRole() {
|
|
||||||
UserUtil userUtil = new UserUtil();
|
|
||||||
String role = userUtil.getRole();
|
|
||||||
return ApiResponseDto.ok(menuService.getFindByRole(role));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package com.kamco.cd.kamcoback.menu;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||||
|
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
|
||||||
|
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||||
|
import com.kamco.cd.kamcoback.menu.dto.MyMenuDto;
|
||||||
|
import com.kamco.cd.kamcoback.menu.service.MyMenuService;
|
||||||
|
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 java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@Tag(name = "메뉴 조회", description = "메뉴 조회 API")
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/api/my/menus")
|
||||||
|
public class MyMenuApiController {
|
||||||
|
|
||||||
|
private final MyMenuService myMenuService;
|
||||||
|
|
||||||
|
@Operation(summary = "사용자별 메뉴 조회", description = "로그인 사용자별 권한 메뉴 목록")
|
||||||
|
@ApiResponses(
|
||||||
|
value = {
|
||||||
|
@ApiResponse(
|
||||||
|
responseCode = "200",
|
||||||
|
description = "조회 성공",
|
||||||
|
content =
|
||||||
|
@Content(
|
||||||
|
mediaType = "application/json",
|
||||||
|
schema = @Schema(implementation = MenuDto.Basic.class))),
|
||||||
|
@ApiResponse(responseCode = "404", description = "코드를 찾을 수 없음", content = @Content),
|
||||||
|
@ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
|
||||||
|
})
|
||||||
|
@GetMapping
|
||||||
|
public ApiResponseDto<List<MyMenuDto.Basic>> getFindAllByRole() {
|
||||||
|
UserUtil userUtil = new UserUtil();
|
||||||
|
String role = userUtil.getRole();
|
||||||
|
return ApiResponseDto.ok(myMenuService.getFindByRole(role));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,8 +45,7 @@ public class MenuDto {
|
|||||||
Long updatedUid,
|
Long updatedUid,
|
||||||
List<MenuDto.Basic> children,
|
List<MenuDto.Basic> children,
|
||||||
ZonedDateTime createdDttm,
|
ZonedDateTime createdDttm,
|
||||||
ZonedDateTime updatedDttm,
|
ZonedDateTime updatedDttm) {
|
||||||
String menuApiUrl) {
|
|
||||||
this.menuUid = menuUid;
|
this.menuUid = menuUid;
|
||||||
this.menuNm = menuNm;
|
this.menuNm = menuNm;
|
||||||
this.menuUrl = menuUrl;
|
this.menuUrl = menuUrl;
|
||||||
@@ -59,7 +58,6 @@ public class MenuDto {
|
|||||||
this.children = children;
|
this.children = children;
|
||||||
this.createdDttm = createdDttm;
|
this.createdDttm = createdDttm;
|
||||||
this.updatedDttm = updatedDttm;
|
this.updatedDttm = updatedDttm;
|
||||||
this.menuApiUrl = menuApiUrl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +68,6 @@ public class MenuDto {
|
|||||||
private String menuUid;
|
private String menuUid;
|
||||||
private String menuNm;
|
private String menuNm;
|
||||||
private String menuUrl;
|
private String menuUrl;
|
||||||
private String menuApiUri;
|
|
||||||
private String roles; // "ROLE_A,ROLE_B"
|
private String roles; // "ROLE_A,ROLE_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/main/java/com/kamco/cd/kamcoback/menu/dto/MyMenuDto.java
Normal file
29
src/main/java/com/kamco/cd/kamcoback/menu/dto/MyMenuDto.java
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package com.kamco.cd.kamcoback.menu.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
public class MyMenuDto {
|
||||||
|
|
||||||
|
@Schema(name = "My Menu Basic", description = "사용자별 권한 메뉴 목록")
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Basic {
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
private String menuUrl;
|
||||||
|
private Long order;
|
||||||
|
private List<Basic> children = new ArrayList<>();
|
||||||
|
|
||||||
|
public Basic(String menuUid, String menuNm, String menuUrl, Long menuOrder) {
|
||||||
|
this.id = menuUid;
|
||||||
|
this.name = menuNm;
|
||||||
|
this.menuUrl = menuUrl;
|
||||||
|
this.order = menuOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
package com.kamco.cd.kamcoback.menu.service;
|
package com.kamco.cd.kamcoback.menu.service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.kamco.cd.kamcoback.common.enums.RoleType;
|
|
||||||
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
import com.kamco.cd.kamcoback.common.utils.UserUtil;
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.core.MenuCoreService;
|
import com.kamco.cd.kamcoback.postgres.core.MenuCoreService;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
@@ -27,60 +23,4 @@ public class MenuService {
|
|||||||
public List<MenuDto.Basic> getFindAll() {
|
public List<MenuDto.Basic> getFindAll() {
|
||||||
return menuCoreService.getFindAll();
|
return menuCoreService.getFindAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 권한별 메뉴 목록 redis 등록
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public void getFindByRoleRedis() {
|
|
||||||
|
|
||||||
for (RoleType role : RoleType.values()) {
|
|
||||||
List<MenuDto.Basic> menus = menuCoreService.getFindByRole(role.name());
|
|
||||||
|
|
||||||
try {
|
|
||||||
String key = "menu:role:" + role.name();
|
|
||||||
String value = objectMapper.writeValueAsString(menus);
|
|
||||||
redisTemplate.opsForValue().set(key, value);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MenuDto.MenuWithRolesDto> menusWithRoles = menuCoreService.getMenuWithRoles();
|
|
||||||
|
|
||||||
try {
|
|
||||||
String key = "auth:api:role";
|
|
||||||
String value = objectMapper.writeValueAsString(menusWithRoles);
|
|
||||||
redisTemplate.opsForValue().set(key, value);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 권한별 메뉴 목록 조회
|
|
||||||
*
|
|
||||||
* @param role
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public List<MenuDto.Basic> getFindByRole(String role) {
|
|
||||||
String key = "menu:role:" + role;
|
|
||||||
String json = redisTemplate.opsForValue().get(key);
|
|
||||||
if (json == null) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
JavaType type =
|
|
||||||
objectMapper.getTypeFactory().constructCollectionType(List.class, MenuDto.Basic.class);
|
|
||||||
|
|
||||||
List<MenuDto.Basic> cached;
|
|
||||||
|
|
||||||
try {
|
|
||||||
cached = objectMapper.readValue(json, type);
|
|
||||||
} catch (JsonProcessingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.kamco.cd.kamcoback.menu.service;
|
||||||
|
|
||||||
|
import com.kamco.cd.kamcoback.menu.dto.MyMenuDto;
|
||||||
|
import com.kamco.cd.kamcoback.postgres.core.MenuCoreService;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public class MyMenuService {
|
||||||
|
|
||||||
|
private final MenuCoreService menuCoreService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 권한별 메뉴 목록 조회
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<MyMenuDto.Basic> getFindByRole(String role) {
|
||||||
|
return menuCoreService.getFindByRole(role);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,12 @@ import jakarta.transaction.Transactional;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.web.bind.annotation.*;
|
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.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@Tag(name = "모델 관리", description = "모델 관리 API")
|
@Tag(name = "모델 관리", description = "모델 관리 API")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
|||||||
@@ -16,15 +16,34 @@ import org.springframework.data.domain.Sort;
|
|||||||
|
|
||||||
public class ModelMngDto {
|
public class ModelMngDto {
|
||||||
|
|
||||||
|
@CodeExpose
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ModelType implements EnumType {
|
||||||
|
M1("모델 M1"),
|
||||||
|
M2("모델 M2"),
|
||||||
|
M3("모델 M3");
|
||||||
|
|
||||||
|
private final String desc;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText() {
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Schema(name = "ModelMgmtDto Basic", description = "모델관리 엔티티 기본 정보")
|
@Schema(name = "ModelMgmtDto Basic", description = "모델관리 엔티티 기본 정보")
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public static class Basic {
|
public static class Basic {
|
||||||
|
|
||||||
|
private Long modelUid;
|
||||||
private String modelVer;
|
private String modelVer;
|
||||||
private String hyperVer;
|
|
||||||
private String epochVer;
|
|
||||||
private String dockerFileNm;
|
|
||||||
|
|
||||||
@JsonFormatDttm private ZonedDateTime createCompleteDttm;
|
@JsonFormatDttm private ZonedDateTime createCompleteDttm;
|
||||||
@JsonFormatDttm private ZonedDateTime recentUseDttm;
|
@JsonFormatDttm private ZonedDateTime recentUseDttm;
|
||||||
@@ -35,22 +54,27 @@ public class ModelMngDto {
|
|||||||
@JsonFormatDttm private ZonedDateTime updatedDttm;
|
@JsonFormatDttm private ZonedDateTime updatedDttm;
|
||||||
private Long updatedUid;
|
private Long updatedUid;
|
||||||
|
|
||||||
|
private String modelType;
|
||||||
|
private String filePath;
|
||||||
|
private String fileName;
|
||||||
|
private String memo;
|
||||||
|
|
||||||
public Basic(
|
public Basic(
|
||||||
|
Long modelUid,
|
||||||
String modelVer,
|
String modelVer,
|
||||||
String hyperVer,
|
|
||||||
String epochVer,
|
|
||||||
String dockerFileNm,
|
|
||||||
ZonedDateTime createCompleteDttm,
|
ZonedDateTime createCompleteDttm,
|
||||||
ZonedDateTime recentUseDttm,
|
ZonedDateTime recentUseDttm,
|
||||||
Boolean deleted,
|
Boolean deleted,
|
||||||
ZonedDateTime createdDttm,
|
ZonedDateTime createdDttm,
|
||||||
Long createdUid,
|
Long createdUid,
|
||||||
ZonedDateTime updatedDttm,
|
ZonedDateTime updatedDttm,
|
||||||
Long updatedUid) {
|
Long updatedUid,
|
||||||
|
String modelType,
|
||||||
|
String filePath,
|
||||||
|
String fileName,
|
||||||
|
String memo) {
|
||||||
|
this.modelUid = modelUid;
|
||||||
this.modelVer = modelVer;
|
this.modelVer = modelVer;
|
||||||
this.hyperVer = hyperVer;
|
|
||||||
this.epochVer = epochVer;
|
|
||||||
this.dockerFileNm = dockerFileNm;
|
|
||||||
this.createCompleteDttm = createCompleteDttm;
|
this.createCompleteDttm = createCompleteDttm;
|
||||||
this.recentUseDttm = recentUseDttm;
|
this.recentUseDttm = recentUseDttm;
|
||||||
this.deleted = deleted;
|
this.deleted = deleted;
|
||||||
@@ -58,6 +82,10 @@ public class ModelMngDto {
|
|||||||
this.createdUid = createdUid;
|
this.createdUid = createdUid;
|
||||||
this.updatedDttm = updatedDttm;
|
this.updatedDttm = updatedDttm;
|
||||||
this.updatedUid = updatedUid;
|
this.updatedUid = updatedUid;
|
||||||
|
this.modelType = modelType;
|
||||||
|
this.filePath = filePath;
|
||||||
|
this.fileName = fileName;
|
||||||
|
this.memo = memo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,17 +95,18 @@ public class ModelMngDto {
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class ModelList {
|
public static class ModelList {
|
||||||
|
|
||||||
private Integer rowNum;
|
private Integer rowNum;
|
||||||
private String modelVer;
|
private String modelVer;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private String modelType;
|
private String modelType;
|
||||||
private String createCompleteDttm;
|
private String createCompleteDttm;
|
||||||
private String recentUseDttm;
|
|
||||||
private BigDecimal f1Score;
|
private BigDecimal f1Score;
|
||||||
private BigDecimal precision;
|
private BigDecimal precision;
|
||||||
private BigDecimal recall;
|
private BigDecimal recall;
|
||||||
private BigDecimal accuracy;
|
private BigDecimal accuracy;
|
||||||
private BigDecimal iou;
|
private BigDecimal iou;
|
||||||
|
private String memo;
|
||||||
private Boolean deleted;
|
private Boolean deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,25 +147,4 @@ public class ModelMngDto {
|
|||||||
return PageRequest.of(page, size);
|
return PageRequest.of(page, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CodeExpose
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum ModelType implements EnumType {
|
|
||||||
M1("모델 M1"),
|
|
||||||
M2("모델 M2"),
|
|
||||||
M3("모델 M3");
|
|
||||||
|
|
||||||
private final String desc;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return name();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getText() {
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.core;
|
package com.kamco.cd.kamcoback.postgres.core;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||||
|
import com.kamco.cd.kamcoback.menu.dto.MyMenuDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
|
import com.kamco.cd.kamcoback.postgres.repository.menu.MenuRepository;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -23,16 +25,50 @@ public class MenuCoreService {
|
|||||||
* @param role
|
* @param role
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public List<MenuDto.Basic> getFindByRole(String role) {
|
public List<MyMenuDto.Basic> getFindByRole(String role) {
|
||||||
return menuRepository.getFindByRole(role).stream().map(MenuEntity::toDto).toList();
|
List<MenuEntity> entities = menuRepository.getFindByRole(role);
|
||||||
|
|
||||||
|
return entities.stream()
|
||||||
|
.map(
|
||||||
|
parent -> {
|
||||||
|
MyMenuDto.Basic p =
|
||||||
|
new MyMenuDto.Basic(
|
||||||
|
parent.getMenuUid(),
|
||||||
|
parent.getMenuNm(),
|
||||||
|
parent.getMenuUrl(),
|
||||||
|
parent.getMenuOrder());
|
||||||
|
|
||||||
|
parent.getChildren().stream()
|
||||||
|
.filter(
|
||||||
|
c ->
|
||||||
|
Boolean.TRUE.equals(c.getIsUse()) && Boolean.FALSE.equals(c.getDeleted()))
|
||||||
|
.sorted(
|
||||||
|
Comparator.comparing(
|
||||||
|
MenuEntity::getMenuOrder, Comparator.nullsLast(Long::compareTo)))
|
||||||
|
.map(
|
||||||
|
c ->
|
||||||
|
new MyMenuDto.Basic(
|
||||||
|
c.getMenuUid(), c.getMenuNm(), c.getMenuUrl(), c.getMenuOrder()))
|
||||||
|
.forEach(childDto -> p.getChildren().add(childDto));
|
||||||
|
|
||||||
|
return p;
|
||||||
|
})
|
||||||
|
.sorted(
|
||||||
|
Comparator.comparing(MyMenuDto.Basic::getOrder, Comparator.nullsLast(Long::compareTo)))
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 메뉴별 권한 조회
|
* 사용자 role 기준으로 접근 가능한 메뉴 URL 목록 조회
|
||||||
*
|
*
|
||||||
|
* @param role
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public List<MenuDto.MenuWithRolesDto> getMenuWithRoles() {
|
public List<String> findAllowedMenuUrlsByRole(String role) {
|
||||||
return menuRepository.getFindByMenuWithRoles();
|
return menuRepository.findAllowedMenuUrlsByRole(role).stream()
|
||||||
|
.map(MenuEntity::getMenuUrl)
|
||||||
|
.filter(url -> url != null && !url.isBlank())
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,15 @@ package com.kamco.cd.kamcoback.postgres.entity;
|
|||||||
|
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
import com.kamco.cd.kamcoback.menu.dto.MenuDto;
|
||||||
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.CascadeType;
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.OneToMany;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -15,6 +23,7 @@ import lombok.NoArgsConstructor;
|
|||||||
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
@Table(name = "tb_menu")
|
@Table(name = "tb_menu")
|
||||||
public class MenuEntity extends CommonDateEntity {
|
public class MenuEntity extends CommonDateEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "menu_uid")
|
@Column(name = "menu_uid")
|
||||||
private String menuUid;
|
private String menuUid;
|
||||||
@@ -49,9 +58,6 @@ public class MenuEntity extends CommonDateEntity {
|
|||||||
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||||
private List<MenuEntity> children = new ArrayList<>();
|
private List<MenuEntity> children = new ArrayList<>();
|
||||||
|
|
||||||
@Column(name = "menu_api_uri")
|
|
||||||
private String menuApiUri;
|
|
||||||
|
|
||||||
public MenuDto.Basic toDto() {
|
public MenuDto.Basic toDto() {
|
||||||
return new MenuDto.Basic(
|
return new MenuDto.Basic(
|
||||||
this.menuUid,
|
this.menuUid,
|
||||||
@@ -65,7 +71,6 @@ public class MenuEntity extends CommonDateEntity {
|
|||||||
this.updatedUid,
|
this.updatedUid,
|
||||||
this.children.stream().map(MenuEntity::toDto).toList(),
|
this.children.stream().map(MenuEntity::toDto).toList(),
|
||||||
this.getCreatedDate(),
|
this.getCreatedDate(),
|
||||||
this.getModifiedDate(),
|
this.getModifiedDate());
|
||||||
this.menuApiUri);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.entity;
|
package com.kamco.cd.kamcoback.postgres.entity;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.GenerationType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -11,6 +16,7 @@ import lombok.Setter;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "tb_model_mng")
|
@Table(name = "tb_model_mng")
|
||||||
public class ModelMngEntity extends CommonDateEntity {
|
public class ModelMngEntity extends CommonDateEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column(name = "model_uid")
|
@Column(name = "model_uid")
|
||||||
@@ -43,6 +49,9 @@ public class ModelMngEntity extends CommonDateEntity {
|
|||||||
@Column(name = "file_name")
|
@Column(name = "file_name")
|
||||||
private String fileName;
|
private String fileName;
|
||||||
|
|
||||||
|
@Column(name = "memo")
|
||||||
|
private String memo;
|
||||||
|
|
||||||
public void deleted() {
|
public void deleted() {
|
||||||
this.deleted = true;
|
this.deleted = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.kamco.cd.kamcoback.postgres.repository.menu;
|
package com.kamco.cd.kamcoback.postgres.repository.menu;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto.MenuWithRolesDto;
|
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -17,9 +16,10 @@ public interface MenuRepositoryCustom {
|
|||||||
List<MenuEntity> getFindByRole(String role);
|
List<MenuEntity> getFindByRole(String role);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 메뉴별 권한 조회
|
* 사용자 role 기준으로 접근 가능한 메뉴 URL 목록 조회
|
||||||
*
|
*
|
||||||
|
* @param role
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<MenuWithRolesDto> getFindByMenuWithRoles();
|
List<MenuEntity> findAllowedMenuUrlsByRole(String role);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,8 @@ package com.kamco.cd.kamcoback.postgres.repository.menu;
|
|||||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
import static com.kamco.cd.kamcoback.postgres.entity.QMenuEntity.menuEntity;
|
||||||
import static com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity.menuMappEntity;
|
import static com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity.menuMappEntity;
|
||||||
|
|
||||||
import com.kamco.cd.kamcoback.menu.dto.MenuDto.MenuWithRolesDto;
|
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.MenuEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
|
import com.kamco.cd.kamcoback.postgres.entity.QMenuEntity;
|
||||||
import com.kamco.cd.kamcoback.postgres.entity.QMenuMappEntity;
|
|
||||||
import com.querydsl.core.types.Expression;
|
|
||||||
import com.querydsl.core.types.Projections;
|
|
||||||
import com.querydsl.core.types.dsl.Expressions;
|
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -34,12 +29,14 @@ public class MenuRepositoryImpl implements MenuRepositoryCustom {
|
|||||||
@Override
|
@Override
|
||||||
public List<MenuEntity> getFindByRole(String role) {
|
public List<MenuEntity> getFindByRole(String role) {
|
||||||
|
|
||||||
|
QMenuEntity parent = QMenuEntity.menuEntity;
|
||||||
QMenuEntity child = new QMenuEntity("child");
|
QMenuEntity child = new QMenuEntity("child");
|
||||||
|
|
||||||
List<MenuEntity> content =
|
List<MenuEntity> content =
|
||||||
queryFactory
|
queryFactory
|
||||||
.selectDistinct(menuEntity)
|
.selectDistinct(parent)
|
||||||
.from(menuEntity)
|
.from(parent)
|
||||||
.leftJoin(menuEntity.children, child)
|
.leftJoin(parent.children, child)
|
||||||
.fetchJoin()
|
.fetchJoin()
|
||||||
.leftJoin(menuMappEntity)
|
.leftJoin(menuMappEntity)
|
||||||
.on(
|
.on(
|
||||||
@@ -47,43 +44,39 @@ public class MenuRepositoryImpl implements MenuRepositoryCustom {
|
|||||||
.roleCode
|
.roleCode
|
||||||
.eq(role)
|
.eq(role)
|
||||||
.and(menuMappEntity.deleted.isFalse())
|
.and(menuMappEntity.deleted.isFalse())
|
||||||
.and(
|
.and(menuMappEntity.menuUid.eq(child)))
|
||||||
menuMappEntity.menuUid.eq(menuEntity).or(menuMappEntity.menuUid.eq(child))))
|
|
||||||
.where(
|
.where(
|
||||||
menuEntity.parent.isNull(),
|
parent.parent.isNull(),
|
||||||
|
parent.deleted.isFalse(),
|
||||||
|
parent.isUse.isTrue(),
|
||||||
|
menuMappEntity.id.isNotNull())
|
||||||
|
.orderBy(parent.menuOrder.asc().nullsLast(), child.menuOrder.asc().nullsLast())
|
||||||
|
.fetch();
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 사용자 role 기준으로 접근 가능한 메뉴 URL 목록 조회
|
||||||
|
*
|
||||||
|
* @param role
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<MenuEntity> findAllowedMenuUrlsByRole(String role) {
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.selectDistinct(menuEntity)
|
||||||
|
.from(menuMappEntity)
|
||||||
|
.join(menuMappEntity.menuUid, menuEntity)
|
||||||
|
.where(
|
||||||
|
menuMappEntity.roleCode.eq(role),
|
||||||
|
menuMappEntity.deleted.isFalse(),
|
||||||
menuEntity.deleted.isFalse(),
|
menuEntity.deleted.isFalse(),
|
||||||
menuEntity.isUse.isTrue(),
|
menuEntity.isUse.isTrue(),
|
||||||
menuMappEntity.id.isNotNull())
|
menuEntity.menuUrl.isNotNull(),
|
||||||
.orderBy(menuEntity.menuOrder.asc().nullsLast(), child.menuOrder.asc().nullsLast())
|
menuEntity.menuUrl.isNotEmpty())
|
||||||
|
.orderBy(menuEntity.menuOrder.asc().nullsLast())
|
||||||
.fetch();
|
.fetch();
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<MenuWithRolesDto> getFindByMenuWithRoles() {
|
|
||||||
QMenuEntity tm = menuEntity;
|
|
||||||
QMenuMappEntity tmm = menuMappEntity;
|
|
||||||
|
|
||||||
Expression<String> roleAgg =
|
|
||||||
Expressions.stringTemplate("string_agg({0}, {1})", tmm.roleCode, Expressions.constant(","));
|
|
||||||
|
|
||||||
List<MenuWithRolesDto> content =
|
|
||||||
queryFactory
|
|
||||||
.select(
|
|
||||||
Projections.constructor(
|
|
||||||
MenuWithRolesDto.class,
|
|
||||||
tm.menuUid,
|
|
||||||
tm.menuNm,
|
|
||||||
tm.menuUrl,
|
|
||||||
tm.menuApiUri,
|
|
||||||
roleAgg))
|
|
||||||
.from(tm)
|
|
||||||
.leftJoin(tmm)
|
|
||||||
.on(tmm.menuUid.eq(tm).and(tmm.deleted.isFalse()))
|
|
||||||
.where(tm.deleted.isFalse())
|
|
||||||
.groupBy(tm.menuUid, tm.menuNm, tm.menuUrl, tm.menuApiUri)
|
|
||||||
.fetch();
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import com.kamco.cd.kamcoback.postgres.entity.ModelMngEntity;
|
|||||||
import com.querydsl.core.BooleanBuilder;
|
import com.querydsl.core.BooleanBuilder;
|
||||||
import com.querydsl.core.types.Expression;
|
import com.querydsl.core.types.Expression;
|
||||||
import com.querydsl.core.types.Projections;
|
import com.querydsl.core.types.Projections;
|
||||||
import com.querydsl.core.types.dsl.*;
|
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||||
|
import com.querydsl.core.types.dsl.Expressions;
|
||||||
|
import com.querydsl.core.types.dsl.NumberPath;
|
||||||
|
import com.querydsl.core.types.dsl.StringExpression;
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -71,13 +74,12 @@ public class ModelMngRepositoryImpl extends QuerydslRepositorySupport
|
|||||||
modelMngEntity.modelType,
|
modelMngEntity.modelType,
|
||||||
Expressions.stringTemplate(
|
Expressions.stringTemplate(
|
||||||
"to_char({0}, 'YYYY-MM-DD')", modelMngEntity.createCompleteDttm),
|
"to_char({0}, 'YYYY-MM-DD')", modelMngEntity.createCompleteDttm),
|
||||||
Expressions.stringTemplate(
|
|
||||||
"to_char({0}, 'YYYY-MM-DD')", modelMngEntity.recentUseDttm),
|
|
||||||
roundNumericToPercent(modelResultMetricEntity.f1Score),
|
roundNumericToPercent(modelResultMetricEntity.f1Score),
|
||||||
roundNumericToPercent(modelResultMetricEntity.precision),
|
roundNumericToPercent(modelResultMetricEntity.precision),
|
||||||
roundNumericToPercent(modelResultMetricEntity.recall),
|
roundNumericToPercent(modelResultMetricEntity.recall),
|
||||||
roundNumericToPercent(modelResultMetricEntity.loss),
|
roundNumericToPercent(modelResultMetricEntity.loss),
|
||||||
roundNumericToPercent(modelResultMetricEntity.iou),
|
roundNumericToPercent(modelResultMetricEntity.iou),
|
||||||
|
modelMngEntity.memo,
|
||||||
modelMngEntity.deleted))
|
modelMngEntity.deleted))
|
||||||
.from(modelMngEntity)
|
.from(modelMngEntity)
|
||||||
.innerJoin(modelResultMetricEntity)
|
.innerJoin(modelResultMetricEntity)
|
||||||
|
|||||||
Reference in New Issue
Block a user