1-1. User.java
- UserRole 만들기
1- 2. 회원가입 시 관리자 역할 부여 하기
- signup.html : checkbox이용
- UserController.java : @PostMapping("/signup")
2. AdminController.java 만들기
- 사용자 정보 가져오기
- 사용자 역할 확인하여 isAdmin 변수 설정
3. Admin.html 만들기
- user수, 구독자수, 총 매출, 고객 문의 수
- QnA 리스트 (승인/삭제)
- Coupon 리스트
4. nav에 관리자 역할인 경우에만 Admin 버튼 보이게 설정하기
1-1. User.java
1) User.java에 UserRole 만들기
@Entity
@Data
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String email;
private String pwd;
private String name;
private Integer phone;
private Date creDate;
private String carname;
@Column(nullable = true)
private Integer count;
private UserRole role;
public enum UserRole {
CUSTOMER, // 일반 고객0
ADMIN // 관리자1
}
public String getRole() {
return role.name(); // 열거형 값의 이름을 문자열로 반환
}
}
※ public enum UserRole : 열거형(Enumeration)을 정의 , 관련된 상수 값(CUSTOMER, ADMIN)을 그룹화하는 자료형 -> 각 상수는 0부터 정수 값으로 자동으로 할당됨.
※ public String getRole() : UserRole 열거형 내부에서 현재 사용자 역할을 나타내는 role 변수의 이름을 문자열로 반환하는 함수
※ implements Serializable 쓰는 이유
<SpringBoot 서버 재구동 시 세션의 값이 제거되는 현상>
* 로그인 자꾸 풀리는 문제(session초기화)
1. 자바에서 제공되는 자료형은 자동으로 제거되지 않음
2. 별도로 작성한 클래스는 자동으로 제거됨
* 해결방법
: 별도로 작성한 클래스에 Serializable 인터페이스를 구현하면 자동으로 제거되지 않음
2) UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
public User findByEmailAndPwd(String email, String pwd);
public User findByEmail(String email);
public User findById(long id);
List<User> findByEmailAndNameAndPhone(String email,String name, Integer phone);
}
1- 2. 회원가입 시 관리자 역할 부여 하기
1) signup.html
- input의 checkbox 이용하기
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="isAdmin" name="isAdmin">
<label class="form-check-label" for="isAdmin">관리자</label>
</div>
2) UserController.java
@PostMapping("/signup")
public String signupPost(@ModelAttribute User user, @RequestParam(value = "isAdmin", required = false) boolean isAdmin)
{
String userPwd = user.getPwd();
String encodePwd = passwordEncoder.encode(userPwd);
user.setPwd(encodePwd);
user.setCreDate(new Date());
// 사용자 역할 설정(삼항연산자)
User.UserRole userRole = isAdmin ? User.UserRole.ADMIN : User.UserRole.CUSTOMER;
// 사용자 정보 저장
user.setRole(userRole);
userRepository.save(user);
// User 수 증가
List<User> users = userRepository.findAll();
int userCount = users.size();
userCount++;
for (User u : users) {
u.setCount(userCount);
}
userRepository.saveAll(users);
return "redirect:/";
}
※ @RequestParam 어노테이션의 required 속성을 false로 설정하는 이유
: 해당 요청 매개변수(parameter)가 반드시 필수가 아니게 함, required=false를 사용하여 요청 매개변수가 누락되더라도 예외가 발생하지 않도록 설정
2. AdminController.java 만들기
- 사용자 정보 가져오기
- 사용자 역할 확인하여 isAdmin 변수 설정
@Controller
public class AdminController {
@Autowired
UserRepository userRepository;
@Autowired
HttpSession session;
@GetMapping("/admin")
public String admin(Model model) {
// 사용자 정보 가져오기
User user = (User) session.getAttribute("user_info");
// 사용자의 역할을 확인하여 isAdmin 변수 설정
boolean isAdmin = user != null && "ADMIN".equals(user.getRole());
model.addAttribute("isAdmin", isAdmin);
return "/admin";
}
}
※ 로그인 하면 session에 user_info 값이 들어가도록 설정해 놓았다.
그 값으로 사용자 정보를 가져오는 코드를 넣었다.(관리자인지 고객인지 알기 위한 코드)
※ isAdmin 변수를 user가 null이 아니고, 사용자의 역할이 "ADMIN"인 경우에만 true로 설정합니다.
※ model.addAttribute("isAdmin", isAdmin); << Model model을 넣어야함
- 모델 객체(model)에 isAdmin 변수를 추가
- 이렇게 하면 해당 모델 속성을 뷰(예: HTML 템플릿)에서 사용할 수 있게 됨. 예를 들어, 뷰에서 isAdmin 속성을 이용하여 사용자에게 특정 기능이나 페이지 접근 권한을 부여할 수 있다.
3. Admin.html 만들기
- container 만들기
- content-section 만들기
- 추가 기능들 만들기(관련 정보들 가져오기)
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head th:replace="common/head">
</head>
<body>
<div th:replace="common/header"></div>
<nav th:replace="common/nav"></nav>
<div class="container">
<div class="card">
<div id="main-content">
<!-- panel -->
<div id='wrapper'>
<!-- Content -->
<!-- 통계 -->
<div id='content-section'>
<div class='panel panel-default'>
<div class='panel-heading'>
<div class="admintitle">
<h4>PIKA ADMIN</h4>
</div>
</div>
<div class='panel-body'>
<div class='panel-count'>
<div class="box1">
<div class="count-name">User 수</div>
<p th:text="${userCount}"></p>
</div>
<div class="box2">
<div class="count-name">구독자 수</div>
<p th:text="${membershipCount}"></p>
</div>
<div class="box3">
<div class="count-name">총 매출</div>
<p>$<span th:text="${membershipCount * 3900}"></span></p>
</div>
<div class="box4">
<div class="count-name">고객 문의</div>
<p th:text="${totalQnaCount}"></p>
</div>
</div>
</div>
</div>
</div>
<!-- 충전소 정보 등록 -->
<div id='content-section'>
<div class='panel panel-default'>
<div class='panel-heading'>
<div class="admintitle">
<h4>Charging QnA</h4>
</div>
</div>
<div class='panel-body'>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">City</th>
<th scope="col">Location</th>
<th scope="col">Address</th>
<th scope="col">급속충전기 (대)</th>
<th scope="col">완속충전기 (대)</th>
</tr>
</thead>
<tbody>
<tr th:each="b:${chargings}">
<td th:text="${b.id}"></td>
<td th:text="${b.city}"></td>
<td th:text="${b.location}"></td>
<td th:text="${b.address}"></td>
<td th:text="${b.fastch}"></td>
<td th:text="${b.slowch}"></td>
<td>
<a class="btn btn-secondary btn-sm" th:href="@{/chargingsDetail/{id}(id=${b.id})}">View
Details</a>
<button th:onclick="'chargingsRm(' + ${b.id} +')'">삭제</button>
</td>
</tr>
</tbody>
</table>
<div class="plus-charging">
<button type="button" class="btn btn-block" id="charging-btn"> 충전소 정보 등록하기</button>
</div>
</div>
</div>
</div>
<!-- 차정보 등록 -->
<div id='content-section'>
<div class='panel panel-default'>
<div class='panel-heading'>
<div class="admintitle">
<h4>Car QnA</h4>
</div>
</div>
<div class='panel-body'>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Id</th>
<th scope="col">회사</th>
<th scope="col">차 이름</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="car : ${carQnas}">
<td th:text="${car.id}"></td>
<td th:text="${car.qnacompany}"></td>
<td th:text="${car.qnacarname}"></td>
<td><button th:onclick="'approve(' + ${car.id} + ')'">승인</button>
<button th:onclick="'carqnaRm(' + ${car.id} +')'">삭제</button>
</td>
</tr>
</tbody>
</table>
<div class="plus-car">
<button type="button" class="btn btn-block" id="plus-btn"> 차 정보 등록하기</button>
</div>
</div>
</div>
</div>
<!-- 쿠폰 삭제 -->
<div id='content-section'>
<div class='panel panel-default'>
<div class='panel-heading'>
<div class="admintitle">
<h4>Coupon</h4>
</div>
</div>
<div class='panel-body'>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">유저</th>
<th scope="col">쿠폰 이름</th>
<th scope="col">쿠폰 유효기간</th>
<th scope="col">쿠폰 번호</th>
<th scope="col">쿠폰 사용</th>
</tr>
</thead>
<tbody>
<tr th:each="coupon : ${coupons}">
<td th:text="${coupon.user.email}"></td>
<td th:text="${coupon.name}"></td>
<td>
<span th:text="${coupon.startDate}"></span>
~
<span th:text="${coupon.endDate}"></span>
</td>
<td th:text="${coupon.code}"></td>
<td th:text="${coupon.used}"></td>
<td>
<button th:onclick="'couponRm(' + ${coupon.id} +')'">삭제</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
//충전소등록버튼
document.querySelector('#charging-btn').addEventListener('click', () => {
location = '/chlregister';
});
//충전소 삭제 버튼
function chargingsRm(id) {
const isOk = confirm('삭제하시겠습니까?');
if (isOk) {
location = `/chargingslist/remove?id=${id}`;
}
}
//차 등록 버튼
document.querySelector('#plus-btn').addEventListener('click', () => {
location = '/addCar';
});
//차 삭제 버튼
function carqnaRm(id) {
const isOk = confirm('삭제하시겠습니까?');
if (isOk) {
location = `/admin/carQna/remove?id=${id}`;
}
}
//승인 버튼
function approve(id) {
const isOk = confirm('승인하시겠습니까?');
if (isOk) {
location = `/admin/carQna/approve?id=${id}`;
}
}
//쿠폰 삭제 버튼
function couponRm(id) {
const isOk = confirm('삭제하시겠습니까?');
if (isOk) {
location = `/coupon/remove?id=${id}`;
}
}
</script>
</body>
</html>
4. nav.html에 관리자 역할인 경우에만 Admin 버튼 보이게 설정하기
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="sidebar" style="width: 300px; height: 100%;">
<button class="button">⚡
</button>
<div class="content">
<!-- <nav class="nav">
<div class="nav-1">
<div class="head_logo">
<a href="/">
<img class="logo_text" src="car.png" alt="로고" />
</a>
</div>
</div> -->
<div class="nav-2">
<div class="menubar">
<a class="word" th:href="@{/}">홈</a>
</div>
<div class="menubar">
<a class="word" th:href="@{/map}">충전소 찾기</a>
<!-- <div class="submenu">
<a class="word" th:href="@{/map}">지도</a>
<a class="word" th:href="@{/map}">목록 추가</a>
</div> -->
</div>
<div class="menubar">
<a class="word">게시판</a>
<div class="submenu">
<a class="word" th:href="@{/board/list}">공지사항</a>
<a class="word" th:href="@{/qna/list}">Q&A</a>
</div>
</div>
<div class="menubar">
<a class="word">정보마당</a>
<div class="submenu">
<a class="word" th:href="@{/statistic/chargerStatus}">통계정보</a>
<a class="word" th:href="@{/statistic/ChargerExpense}">서비스안내</a>
</div>
</div>
<div class="menubar">
<a class="word">미디어</a>
<div class="submenu">
<a class="word" th:href="@{/media/news?searchText=전기차}">전기차 뉴스</a>
<a class="word" th:href="@{/media/reels}">전기차 영상</a>
<a class="word" th:href="@{/media/gamepage}">전기차 게임</a>
</div>
</div>
<div class="menubar">
<a class="word">멤버십</a>
<div class="submenu">
<a class="word" th:href="@{/exchange}">코인교환</a>
<a class="word" th:href="@{/coupon}">쿠폰함</a>
<br>
<a class="word" th:href="@{/membership}">가입하기</a>
<a th:if="${session != null and session.user_info != null and session.has_membership}" class="word" th:href="@{/mymembership}">나의 멤버십</a>
</div>
</div>
</div>
<br>
<br>
<div th:if="${session.user_info == null}" class="menubar">
<a th:href="@{/signin}" class="word">로그인</a>
<a th:href="@{/signup}" class="word">회원가입</a>
</div>
<div th:unless="${session.user_info == null}" class="menubar">
<span class="word">[[ ${session.user_info.name} + '님 반갑습니다.' ]]</span>
<br>
<a class="word" th:href="@{/exchange}">나의 찌리릿: <span th:text="${userCoin}"></span>개</a>
<br>
<a th:href="@{/mypage(email=${session.user_info.email})}" class="word">Mypage</a>
<br>
<!-- 관리자 권한으로 로그인하면 관리자 페이지 링크 보이게 설정 -->
<a th:if="${session != null and session.user_info != null and session.user_info.role == 'ADMIN'}" th:href="@{/admin}" class="word">
Admin
</a>
<br>
<a th:href="@{/signout}" class="word">로그아웃</a>
</div>
</div>
</div>
</div>
</div>
</nav>
</div>
</div>
</div>
<script>
const button = document.querySelector(".button");
const sidebar = document.querySelector(".sidebar");
let isSidebarOpen = false;
let timeoutId;
sidebar.style.width = "0";
button.addEventListener("click", () => {
if (!isSidebarOpen) {
sidebar.style.width = "300px";
isSidebarOpen = true;
} else {
sidebar.style.width = "0";
button.style.right = "80px";
closeSubmenus();
isSidebarOpen = false;
}
});
function closeSubmenus() {
const submenus = document.querySelectorAll(".submenu");
submenus.forEach((submenu) => {
submenu.style.display = "none";
});
// If there's no submenu open, move the button back to right.
if (!document.querySelector('.submenu[style*="block"]')) {
button.style.right = "80px";
}
}
const menuItems = document.querySelectorAll(".menubar");
menuItems.forEach((menuItem) => {
menuItem.addEventListener("mouseover", () => {
if (isSidebarOpen) {
closeSubmenus();
const submenu = menuItem.querySelector(".submenu");
if (submenu) {
submenu.style.display = "block";
button.style.right = "310px"; // If a submenu opens, move the button right.
}
}
});
menuItem.addEventListener("mouseout", () => {
if (isSidebarOpen) {
const submenu = menuItem.querySelector(".submenu");
if (submenu && submenu.style.display === "block") {
timeoutId = setTimeout(() => {
submenu.style.display = "none";
if (!document.querySelector('.submenu[style*="block"]')) { // check if there's no other opened sub-menu
button.style.right = "80px"; // If a submenu closes, move the button back to right.
}
}, 1000); // wait for one second before closing the submenu
}
}
});
menuItem.addEventListener("mouseover", () => clearTimeout(timeoutId)); // if mouse comes back on item before timeout ends, clear the timeout
});
</script>
</body>
</html>
※ Thymeleaf (타임리프) 사용하여 html에서 버튼 보이는 조건 생성해주기 ( th:if )
조건 1. 세션이 null이 아닐경우
조건 2. 세션에 저장된 user_info가 null이 아닐경우 (로그인되어야 함)
조건 3. 세션에 저장된 user_info에 저장된 role이 ADMIN 문자열인 경우 (관리자로 회원가입되어야함)
이 세가지 조건이 모두 만족(and)일 경우에 Admin a링크가 보이고 admin.html으로 이동!
결과
감사합니다 :)
'Back-End > Spring boot' 카테고리의 다른 글
[날다프로젝트] Service, Controller 와 Repository / DAO와 DTO (1) | 2024.02.17 |
---|---|
[JAVA][Spring] 본인 인증, 비밀번호 변경하기(2) (2) | 2023.10.27 |
[JAVA][Spring] 로그인, 회원 가입 (1) (0) | 2023.10.27 |