diff --git a/WebContent/jsp/common/acl/sitemap/sitemapMan.jsp b/WebContent/jsp/common/acl/sitemap/sitemapMan.jsp new file mode 100644 index 0000000..62f174c --- /dev/null +++ b/WebContent/jsp/common/acl/sitemap/sitemapMan.jsp @@ -0,0 +1,120 @@ +<%@ page language="java" contentType="text/html; charset=utf-8"%> +<%@ page import="java.util.List"%> +<%@ page import="com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%! + private void printNodeLabel(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException { + String url = node.getMenuUrl(); + boolean hasLink = url != null && !url.trim().isEmpty() && !"NAN".equalsIgnoreCase(url.trim()); + if (hasLink) { + out.print("" + + escapeHtml(node.getMenuName()) + ""); + } else { + out.print("" + escapeHtml(node.getMenuName()) + ""); + } + } + + private void printSitemapNode(javax.servlet.jsp.JspWriter out, SitemapNode node) throws java.io.IOException { + out.print("
  • "); + printNodeLabel(out, node); + + List children = node.getChildren(); + if (children != null && !children.isEmpty()) { + out.print(""); + } + out.print("
  • "); + } + + private String escapeHtml(String value) { + if (value == null) { + return ""; + } + return value.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """); + } + + private String escapeJs(String value) { + if (value == null) { + return ""; + } + return value.replace("\\", "\\\\").replace("'", "\\'"); + } +%> +<% + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Expires", "0"); + + List sitemapTree = (List) request.getAttribute("sitemapTree"); +%> + + + + + + + + + + +
    +
    + +
    +
    +
    사이트맵
    +
    +<% + for (SitemapNode category : sitemapTree) { +%> +
    +
    +<% + printNodeLabel(out, category); +%> +
    +
      +<% + List children = category.getChildren(); + if (children != null) { + for (SitemapNode child : children) { + printSitemapNode(out, child); + } + } +%> +
    +
    +<% + } +%> +
    +
    +
    + + diff --git a/WebContent/jsp/common/screen/top_04.jsp b/WebContent/jsp/common/screen/top_04.jsp index 382e376..60769b2 100644 --- a/WebContent/jsp/common/screen/top_04.jsp +++ b/WebContent/jsp/common/screen/top_04.jsp @@ -9,6 +9,8 @@ <%@page import="com.eactive.eai.rms.common.util.StringUtils" %> <%@page import="com.eactive.eai.rms.common.datasource.DataSourceType" %> <%@page import="com.eactive.eai.rms.common.datasource.DataSourceTypeManager" %> +<%@page import="com.eactive.eai.common.util.ApplicationContextProvider" %> +<%@page import="com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %> <%@ include file="/jsp/common/include/localemessage.jsp" %> @@ -16,6 +18,12 @@ <% String serviceKey = SessionManager.getServiceTypeKey(request); String serviceText = DataSourceTypeManager.getDataSourceType(serviceKey).getText(); + + final String SITEMAP_MENU_ID = "0510013"; + RoleMenuAuthService roleMenuAuthService = ApplicationContextProvider.getContext().getBean(RoleMenuAuthService.class); + String sitemapMenuAuth = roleMenuAuthService.getRoleList(SessionManager.getUserId(request), SITEMAP_MENU_ID, serviceKey); + boolean showSitemapLink = "R".equals(sitemapMenuAuth) || "W".equals(sitemapMenuAuth); + String roleScreenId = (String) request.getAttribute("roleScreenId"); String mainPage = (String) request.getAttribute("mainPage"); String menuId = (String) request.getAttribute("menuId"); @@ -240,6 +248,12 @@ "/> "/> + @@ -303,11 +317,11 @@ } //왼쪽메뉴, 메인 페이지 이동 - function goPage2(page1, page2, page2_id) { + function goPage2(page1, page2, page2_id) { parent.leftFrame.location.href = goNavUrl(page1); parent.mainFrame.location.href = goNavUrl(page2); } - + var sessionAjax = createAjaxRequest(); function getAjaxData() { @@ -529,6 +543,12 @@ console.log("selectLocaleValue : " + selectLocaleValue); parent.changeLocale($(this).val()); }); + + $('.sitemap-link').on('mouseenter', function () { + $(this).closest('.gnb').addClass('sitemap-hover'); + }).on('mouseleave', function () { + $(this).closest('.gnb').removeClass('sitemap-hover'); + }); }); $(function() { @@ -610,6 +630,9 @@ <%=subLayer.toString()%> + <% if (showSitemapLink) { %> + " target="mainFrame" class="sitemap-link">사이트맵 + <% } %>
    diff --git a/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapController.java b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapController.java new file mode 100644 index 0000000..2ce545e --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapController.java @@ -0,0 +1,23 @@ +package com.eactive.eai.rms.common.acl.sitemap; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import com.eactive.eai.rms.common.base.BaseAnnotationController; + +@Controller +@RequiredArgsConstructor +public class SitemapController extends BaseAnnotationController { + + private final SitemapService sitemapService; + + @GetMapping(value = "/common/acl/sitemap/sitemapMan.view") + public String view(@RequestParam(value = "serviceType", required = false) String serviceType, Model model) { + model.addAttribute("sitemapTree", sitemapService.getSitemapTree(serviceType)); + return "/common/acl/sitemap/sitemapMan"; + } + +} diff --git a/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapService.java b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapService.java new file mode 100644 index 0000000..a5e12d2 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapService.java @@ -0,0 +1,11 @@ +package com.eactive.eai.rms.common.acl.sitemap; + +import java.util.List; + +import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode; + +public interface SitemapService { + + public List getSitemapTree(String serviceType); + +} diff --git a/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapServiceImpl.java b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapServiceImpl.java new file mode 100644 index 0000000..178f198 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/SitemapServiceImpl.java @@ -0,0 +1,96 @@ +package com.eactive.eai.rms.common.acl.sitemap; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.eactive.eai.rms.common.acl.sitemap.ui.SitemapNode; +import com.eactive.eai.rms.common.base.BaseService; +import com.eactive.eai.rms.data.entity.man.menu.Menu; +import com.eactive.eai.rms.data.entity.man.menu.MenuService; +import com.eactive.eai.rms.data.entity.man.role.RoleMenuAuthService; + +@Service("sitemapService") +@Transactional(transactionManager = "transactionManagerForEMS") +public class SitemapServiceImpl extends BaseService implements SitemapService { + + @Autowired + private MenuService menuService; + + @Autowired + private RoleMenuAuthService roleMenuAuthService; + + public List getSitemapTree(String serviceType) { + Menu root = menuService.getById("ROOT_DEV"); + Menu langRoot = findLangRoot(root); + List tree = new ArrayList<>(); + if (langRoot == null) { + return tree; + } + + Set serviceTypeMenuIds = StringUtils.isBlank(serviceType) + ? null + : new HashSet<>(roleMenuAuthService.findMenuIdsByServiceType(serviceType)); + + for (Menu menu : sortedChildren(langRoot)) { + if (isVisible(menu) && matchesServiceType(menu, serviceTypeMenuIds)) { + tree.add(buildNode(menu, serviceTypeMenuIds)); + } + } + return tree; + } + + // 엔티티의 childMenus는 menuId 기준으로 정렬되어 있어, 실제 메뉴(운영화면 GNB)와 동일하게 sortOrder 기준으로 재정렬한다. + private List sortedChildren(Menu menu) { + List children = new ArrayList<>(menu.getChildMenus()); + children.sort(Comparator.comparing(Menu::getSortOrder, Comparator.nullsLast(Comparator.naturalOrder()))); + return children; + } + + // MenuService.getMenuList()의 GNB 렌더링과 동일하게 "ROOT"(한글)/"ROOT_EN"(영문) 이름의 언어별 루트를 찾는다. + private Menu findLangRoot(Menu root) { + String lang = LocaleContextHolder.getLocale().getLanguage(); + String langRootName = (StringUtils.isBlank(lang) || "ko".equalsIgnoreCase(lang)) + ? "ROOT" + : "ROOT_" + lang.toUpperCase(); + + return root.getChildMenus().stream() + .filter(m -> langRootName.equalsIgnoreCase(m.getMenuName())) + .findFirst() + .orElse(null); + } + + private SitemapNode buildNode(Menu menu, Set serviceTypeMenuIds) { + SitemapNode node = new SitemapNode(menu); + for (Menu child : sortedChildren(menu)) { + if (isVisible(child) && matchesServiceType(child, serviceTypeMenuIds)) { + node.getChildren().add(buildNode(child, serviceTypeMenuIds)); + } + } + return node; + } + + private boolean isVisible(Menu menu) { + return "Y".equalsIgnoreCase(menu.getDisplayYn()) && "Y".equalsIgnoreCase(menu.getUseYn()); + } + + // serviceType 필터가 없으면 통과. 있으면 자신이나 하위메뉴 중 하나라도 해당 serviceType 권한이 있어야 통과(상위메뉴 누락 방지). + private boolean matchesServiceType(Menu menu, Set serviceTypeMenuIds) { + if (serviceTypeMenuIds == null) { + return true; + } + if (serviceTypeMenuIds.contains(menu.getMenuId())) { + return true; + } + return menu.getChildMenus().stream().anyMatch(child -> matchesServiceType(child, serviceTypeMenuIds)); + } + +} diff --git a/src/main/java/com/eactive/eai/rms/common/acl/sitemap/ui/SitemapNode.java b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/ui/SitemapNode.java new file mode 100644 index 0000000..47f0da1 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/acl/sitemap/ui/SitemapNode.java @@ -0,0 +1,29 @@ +package com.eactive.eai.rms.common.acl.sitemap.ui; + +import java.util.ArrayList; +import java.util.List; + +import com.eactive.eai.rms.data.entity.man.menu.Menu; + +import lombok.Data; + +@Data +public class SitemapNode { + + private String menuId; + + private String menuName; + + private String menuUrl; + + private List children = new ArrayList<>(); + + public SitemapNode(Menu menu) { + this.menuId = menu.getMenuId(); + this.menuName = menu.getMenuName(); + this.menuUrl = menu.getMenuUrl(); + } + + public SitemapNode() { + } +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/man/role/RoleMenuAuthService.java b/src/main/java/com/eactive/eai/rms/data/entity/man/role/RoleMenuAuthService.java index e1e3d12..5fb47c2 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/man/role/RoleMenuAuthService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/man/role/RoleMenuAuthService.java @@ -51,4 +51,17 @@ public class RoleMenuAuthService extends AbstractEMSDataSerivce findMenuIdsByServiceType(String serviceType) { + + QRoleMenuAuth qRoleMenuAuth = QRoleMenuAuth.roleMenuAuth; + + return getJPAQueryFactory() + .select(qRoleMenuAuth.id.menuId) + .distinct() + .from(qRoleMenuAuth) + .where(qRoleMenuAuth.id.serviceType.eq(serviceType)) + .setHint(QueryHints.CACHEABLE, true) + .fetch(); + } + }