메뉴 동적 노출 기능 추가
This commit is contained in:
parent
249cc080e5
commit
c4e33cf22f
|
|
@ -21,6 +21,7 @@ dependencies {
|
|||
|
||||
// thymeleaf
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
|
||||
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.3.0'
|
||||
|
||||
// jpa
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ services:
|
|||
environment:
|
||||
- TZ=Asia/Seoul
|
||||
- MARIADB_ROOT_PASSWORD=root
|
||||
- MARIADB_DATABASE=login
|
||||
- MARIADB_DATABASE=admin-system
|
||||
- MARIADB_USER=admin
|
||||
- MARIADB_PASSWORD=1234
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,59 @@
|
|||
package com.bpgroup.poc.admin.app.login;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class LoginResult {
|
||||
private Long id;
|
||||
private String loginId;
|
||||
private String name;
|
||||
private String email;
|
||||
|
||||
public static LoginResult of(Long id, String loginId, String name, String email) {
|
||||
private Set<MenuInfo> menus = new HashSet<>();
|
||||
|
||||
public static LoginResult of(Long id, String loginId, String name, String email, Set<MenuInfo> menus) {
|
||||
LoginResult loginResult = new LoginResult();
|
||||
loginResult.id = id;
|
||||
loginResult.loginId = loginId;
|
||||
loginResult.name = name;
|
||||
loginResult.email = email;
|
||||
loginResult.menus = menus;
|
||||
return loginResult;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
public static class MenuInfo {
|
||||
private String menuGroupUri;
|
||||
private String menuGroupName;
|
||||
private Integer menuGroupSortOrder;
|
||||
private String menuUri;
|
||||
private String menuName;
|
||||
private Integer menuSortOrder;
|
||||
|
||||
public static MenuInfo of(
|
||||
String menuGroupUri,
|
||||
String menuGroupName,
|
||||
Integer menuGroupSortOrder,
|
||||
String menuUri,
|
||||
String menuName,
|
||||
Integer menuSortOrder
|
||||
) {
|
||||
MenuInfo menuInfo = new MenuInfo();
|
||||
menuInfo.menuGroupUri = menuGroupUri;
|
||||
menuInfo.menuGroupName = menuGroupName;
|
||||
menuInfo.menuGroupSortOrder = menuGroupSortOrder;
|
||||
menuInfo.menuUri = menuUri;
|
||||
menuInfo.menuName = menuName;
|
||||
menuInfo.menuSortOrder = menuSortOrder;
|
||||
return menuInfo;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,16 @@ import com.bpgroup.poc.admin.domain.admin.AdministratorRepository;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional
|
||||
public class LoginService {
|
||||
|
||||
private final AdministratorRepository loginRepository;
|
||||
|
|
@ -32,8 +37,27 @@ public class LoginService {
|
|||
administrator.get().getId(),
|
||||
administrator.get().getLoginId(),
|
||||
administrator.get().getName(),
|
||||
administrator.get().getLoginId()
|
||||
administrator.get().getLoginId(),
|
||||
getMenus(administrator.get())
|
||||
);
|
||||
}
|
||||
|
||||
private static LinkedHashSet<LoginResult.MenuInfo> getMenus(Administrator administrator) {
|
||||
return administrator.getAdministratorRole().getRole().getRoleMenus().stream()
|
||||
.map(roleMenu -> LoginResult.MenuInfo.of(
|
||||
roleMenu.getMenu().getMenuGroup().getUri(),
|
||||
roleMenu.getMenu().getMenuGroup().getName(),
|
||||
roleMenu.getMenu().getMenuGroup().getSortOrder(),
|
||||
roleMenu.getMenu().getUri(),
|
||||
roleMenu.getMenu().getName(),
|
||||
roleMenu.getMenu().getSortOrder()
|
||||
))
|
||||
.sorted(
|
||||
Comparator
|
||||
.comparingInt(LoginResult.MenuInfo::getMenuGroupSortOrder)
|
||||
.thenComparingInt(LoginResult.MenuInfo::getMenuSortOrder)
|
||||
)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
package com.bpgroup.poc.admin.domain.admin;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.bpgroup.poc.admin.domain.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Menu {
|
||||
ADMINISTRATOR_MANAGEMENT("/admin/management", "관리자 관리"),
|
||||
ROLE_MANAGEMENT("/admin/role", "권한 관리"),
|
||||
MENU_MANAGEMENT("/admin/menu", "메뉴 관리")
|
||||
;
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "menu")
|
||||
public class Menu extends BaseEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uri", length = 100, nullable = false)
|
||||
private String uri;
|
||||
|
||||
@Column(name = "name", length = 100, nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
private Integer sortOrder;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "menu_group_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
private MenuGroup menuGroup;
|
||||
|
||||
private final String uri;
|
||||
private final String name;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.bpgroup.poc.admin.domain.admin;
|
||||
|
||||
import com.bpgroup.poc.admin.domain.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "menu_group")
|
||||
public class MenuGroup extends BaseEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "uri", length = 100, nullable = false)
|
||||
private String uri;
|
||||
|
||||
@Column(name = "name", length = 100, nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "sort_order", nullable = false)
|
||||
private Integer sortOrder;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.bpgroup.poc.admin.domain.admin;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface MenuRepository extends JpaRepository<Menu, Long> {
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@ package com.bpgroup.poc.admin.domain.admin;
|
|||
|
||||
import com.bpgroup.poc.admin.domain.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "role")
|
||||
public class Role extends BaseEntity {
|
||||
|
|
@ -21,6 +23,6 @@ public class Role extends BaseEntity {
|
|||
private String description;
|
||||
|
||||
@OneToMany(mappedBy = "role", fetch = FetchType.LAZY)
|
||||
private List<RoleMenu> roleMenus = new ArrayList<>();
|
||||
private Set<RoleMenu> roleMenus = new HashSet<>();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ package com.bpgroup.poc.admin.domain.admin;
|
|||
|
||||
import com.bpgroup.poc.admin.domain.BaseEntity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
|
||||
@Table
|
||||
@Entity(name = "role_menu")
|
||||
@Getter
|
||||
@Entity
|
||||
@Table(name = "role_menu")
|
||||
public class RoleMenu extends BaseEntity {
|
||||
|
||||
@Id
|
||||
|
|
@ -15,8 +17,8 @@ public class RoleMenu extends BaseEntity {
|
|||
@JoinColumn(name = "role_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
private Role role;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "menu", length = 100, nullable = false)
|
||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
||||
@JoinColumn(name = "menu_id", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||
private Menu menu;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
package com.bpgroup.poc.admin.security.authentication;
|
||||
|
||||
import com.bpgroup.poc.admin.app.login.LoginResult;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
@Getter
|
||||
public class AuthenticationDetail {
|
||||
|
|
@ -11,12 +15,74 @@ public class AuthenticationDetail {
|
|||
private String name;
|
||||
private String email;
|
||||
|
||||
private MultiValueMap<MenuOneDepth, MenuTwoDepth> menus = new LinkedMultiValueMap<>();
|
||||
|
||||
public static AuthenticationDetail from(LoginResult result) {
|
||||
AuthenticationDetail authenticationDetail = new AuthenticationDetail();
|
||||
authenticationDetail.id = result.getId();
|
||||
authenticationDetail.loginId = result.getLoginId();
|
||||
authenticationDetail.name = result.getName();
|
||||
authenticationDetail.email = result.getEmail();
|
||||
|
||||
result.getMenus().forEach(menu -> authenticationDetail.menus.add(
|
||||
MenuOneDepth.of(
|
||||
menu.getMenuGroupUri(),
|
||||
menu.getMenuGroupName(),
|
||||
menu.getMenuGroupSortOrder()
|
||||
),
|
||||
MenuTwoDepth.of(
|
||||
menu.getMenuUri(),
|
||||
menu.getMenuName(),
|
||||
menu.getMenuSortOrder()
|
||||
)
|
||||
));
|
||||
|
||||
return authenticationDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
* EqualsAndHashCode annotattion이 없을 경우 MultiValueMap을 사용할 때 중복된 key를 찾지 못함
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
private static class MenuOneDepth {
|
||||
private String uri;
|
||||
private String name;
|
||||
private Integer sortOrder;
|
||||
|
||||
public static MenuOneDepth of(
|
||||
String uri,
|
||||
String name,
|
||||
Integer sortOrder
|
||||
) {
|
||||
MenuOneDepth menu = new MenuOneDepth();
|
||||
menu.uri = uri;
|
||||
menu.name = name;
|
||||
menu.sortOrder = sortOrder;
|
||||
return menu;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
private static class MenuTwoDepth {
|
||||
private String uri;
|
||||
private String name;
|
||||
private Integer sortOrder;
|
||||
|
||||
public static MenuTwoDepth of(
|
||||
String uri,
|
||||
String name,
|
||||
Integer sortOrder
|
||||
) {
|
||||
MenuTwoDepth menu = new MenuTwoDepth();
|
||||
menu.uri = uri;
|
||||
menu.name = name;
|
||||
menu.sortOrder = sortOrder;
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
package com.bpgroup.poc.admin.values;
|
||||
|
||||
public class AdministratorMenu {
|
||||
}
|
||||
|
|
@ -4,12 +4,14 @@ import com.bpgroup.poc.admin.security.authentication.AuthenticationFailReason;
|
|||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/login")
|
||||
public class LoginController {
|
||||
|
||||
@GetMapping("/login")
|
||||
@GetMapping
|
||||
public String loginPage(
|
||||
@RequestParam(required = false) AuthenticationFailReason error,
|
||||
Model model
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ spring:
|
|||
mode: always
|
||||
|
||||
datasource:
|
||||
url: jdbc:mariadb://localhost:3307/login
|
||||
url: jdbc:mariadb://localhost:3307/admin-system
|
||||
username: admin
|
||||
password: 1234
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
spring:
|
||||
application:
|
||||
name: login
|
||||
name: admin
|
||||
|
||||
profiles:
|
||||
default: local
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
INSERT INTO `administrator` (`login_id`, `password`, `email`, `name`, `create_date`, `update_date`)
|
||||
VALUES ('admin', '$2a$10$g6UOrQ/OS8o5r5CJk7C5juVFaItQ62U3EIn8zLPzkFplM3wVLvKZ2', 'admin@admin.com', '홍길동', CURDATE(), CURDATE());
|
||||
VALUES ('admin', '$2a$10$g6UOrQ/OS8o5r5CJk7C5juVFaItQ62U3EIn8zLPzkFplM3wVLvKZ2', 'admin@admin.com', '홍길동', CURDATE(),
|
||||
CURDATE());
|
||||
|
||||
INSERT INTO `role` (`name`, `description`, `create_date`, `update_date`)
|
||||
VALUES ('SUPER_ADMIN', '최고 관리자', CURDATE(), CURDATE()),
|
||||
|
|
@ -9,9 +10,47 @@ VALUES ('SUPER_ADMIN', '최고 관리자', CURDATE(), CURDATE()),
|
|||
INSERT INTO `administrator_role` (`administrator_id`, `role_id`, `create_date`, `update_date`)
|
||||
VALUES ('1', '1', CURDATE(), CURDATE());
|
||||
|
||||
INSERT INTO `role_menu` (`role_id`, `menu`, `create_date`, `update_date`)
|
||||
VALUES ('1', 'ADMINISTRATOR_MANAGEMENT', CURDATE(), CURDATE()),
|
||||
('1', 'ROLE_MANAGEMENT', CURDATE(), CURDATE()),
|
||||
('1', 'MENU_MANAGEMENT', CURDATE(), CURDATE());
|
||||
INSERT INTO `menu_group` (`uri`, `name`, `sort_order`, `create_date`, `update_date`)
|
||||
VALUES ('/admin', '관리자 관리', 2, CURDATE(), CURDATE()),
|
||||
('/settings', '설정', 3, CURDATE(), CURDATE()),
|
||||
('/temp', '임시', 1, CURDATE(), CURDATE());
|
||||
|
||||
INSERT INTO `menu` (`uri`, `name`, `sort_order`, `menu_group_id`, `create_date`, `update_date`)
|
||||
VALUES ('/admin/management', '관리자 관리', 1, 1, CURDATE(), CURDATE()),
|
||||
('/admin/role', '권한 관리', 2, 1, CURDATE(), CURDATE()),
|
||||
('/admin/temp01', '관리자 임시 1', 4, 1, CURDATE(), CURDATE()),
|
||||
('/admin/temp02', '관리자 임시 2', 3, 1, CURDATE(), CURDATE())
|
||||
;
|
||||
|
||||
INSERT INTO `menu` (`uri`, `name`, `sort_order`, `menu_group_id`, `create_date`, `update_date`)
|
||||
VALUES ('/temp/temp01', '임시 01', 4, 3, CURDATE(), CURDATE()),
|
||||
('/temp/temp02', '임시 02', 2, 3, CURDATE(), CURDATE()),
|
||||
('/temp/temp03', '임시 03', 1, 3, CURDATE(), CURDATE()),
|
||||
('/temp/temp04', '임시 04', 3, 3, CURDATE(), CURDATE())
|
||||
;
|
||||
|
||||
|
||||
INSERT INTO `menu` (`uri`, `name`, `sort_order`, `menu_group_id`, `create_date`, `update_date`)
|
||||
VALUES ('/settings/code', '코드 관리', 1, 2, CURDATE(), CURDATE()),
|
||||
('/settings/component', '컴포넌트', 1, 2, CURDATE(), CURDATE()),
|
||||
('/settings/temp01', '세팅 임시 1', 4, 2, CURDATE(), CURDATE()),
|
||||
('/settings/temp02', '세팅 임시 2', 3, 2, CURDATE(), CURDATE())
|
||||
;
|
||||
|
||||
INSERT INTO `role_menu` (`role_id`, `menu_id`, `create_date`, `update_date`)
|
||||
VALUES ('1', '1', CURDATE(), CURDATE()),
|
||||
('1', '2', CURDATE(), CURDATE()),
|
||||
('1', '3', CURDATE(), CURDATE()),
|
||||
('1', '4', CURDATE(), CURDATE()),
|
||||
('1', '5', CURDATE(), CURDATE()),
|
||||
('1', '6', CURDATE(), CURDATE()),
|
||||
('1', '7', CURDATE(), CURDATE()),
|
||||
('1', '8', CURDATE(), CURDATE()),
|
||||
('1', '9', CURDATE(), CURDATE()),
|
||||
('1', '10', CURDATE(), CURDATE()),
|
||||
('1', '11', CURDATE(), CURDATE()),
|
||||
('1', '12', CURDATE(), CURDATE())
|
||||
;
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6,18 +6,20 @@
|
|||
<nav class="menu_wrap flexitem">
|
||||
<h2>메뉴</h2>
|
||||
<button class="closeButton"><img th:src="@{/images/ico_close.svg}"></button>
|
||||
<div th:if="${#authorization.expression('isAuthenticated()')}">
|
||||
<div th:each="entry : ${#authentication.details.getMenus().entrySet()}">
|
||||
<a class="nav_tit"
|
||||
th:classappend="${pathInfo.activeClass('/admin')}">
|
||||
관리자
|
||||
th:classappend="${pathInfo.activeClass(entry.key.getUri())}"
|
||||
th:text="${entry.key.getName()}">
|
||||
</a>
|
||||
<ul class="nav_section">
|
||||
<li>
|
||||
<a th:with="path='/admin/management'" th:href="${path}"
|
||||
th:classappend="${pathInfo.activeClass(path)}">관리자 관리</a>
|
||||
<a th:with="path='/admin/role'" th:href="${path}"
|
||||
th:classappend="${pathInfo.activeClass(path)}">권한 관리</a>
|
||||
<li th:each="menu : ${entry.value}">
|
||||
<a th:with="path= ${menu.getUri()}" th:href="${path}"
|
||||
th:classappend="${pathInfo.activeClass(path)}"><span th:text="${menu.getName()}"></span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</th:block>
|
||||
</body>
|
||||
Loading…
Reference in New Issue