한 페이지로 할 수 있으면 하지만 일단 페이지 나눠서 작업
로그인해서 페이지가 바뀌면, 로그인에 대한 내용이 날라감 -> local storage(저장 비휘발성), session storage(휘발성)에 선택해 저장
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h1>index.html</h1>
<hr>
<!-- 로그인 여부에 따라 달라지는 UI -->
<a href="/login.html" id="linkLogin">Login |</a>
<span id="userNameWrapper"> <span id="userName"></span>님 안녕하세요 |</span>
<a href="#" id="linkLogout">Logout |</a>
<!-- 로그인 상관없는 UI -->
<a href="board.html">board </a>
<script src="/assets/js/common.js"></script>
<script>
window.onload = function(){
initUI();
// logout
document.querySelector("#linkLogout").onclick = logout;
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h1>login.html</h1>
<hr>
<div>
email : <input type="text" name="email" id="email" value="user3@mycom.com">
</div>
<div>
password : <input type="password" name="password" id="password" value="password3">
</div>
<button id="btnLogin">login</button>
<script>
window.onload=function(){
document.querySelector("#btnLogin").onclick = login;
}
async function login(){
// parameter, value
let email = document.querySelector("#email").value;
let password = document.querySelector("#password").value;
let urlParams = new URLSearchParams({
// email:email,
// password:password
email, password // shorthand property
});
// url
let url = "/auth/login";
//fetch options
let fetchOptions = {
method:"post",
body:urlParams
}
let response = await fetch(url, fetchOptions);
let data = await response.json();
console.log(data);
if(data.result == "success"){
// user roles
let roles = data.userDto.roles;
console.log(roles);
// save login data at sessionStorage
// spa가 아니라 multiple html 사용하므로 html 문서끼리 사전에 약속된 공간, 이름으로 관련 데이터 관리
sessionStorage.setItem("name", data.userDto.name);
sessionStorage.setItem("email", data.userDto.email);
sessionStorage.setItem("roles", JSON.stringify(roles));
// move page
window.location.href="/index.html";
} else{
alert("failed login")
}
}
</script>
</body>
</html>
@GetMapping("/logout")
public UserResultDto logout(HttpSession session) {
UserResultDto userResultDto = new UserResultDto();
try {
session.invalidate();
userResultDto.setResult("success");
} catch(IllegalStateException e) {
e.printStackTrace();
userResultDto.setResult("fail");
}
return userResultDto;
}
index.html에 있던 함수 옮기기
/**
*
*/
function initUI(){
let name = sessionStorage.getItem("name");
if(name!=null){
document.querySelector("#linkLogin").style.display = "none";
document.querySelector("#userName").innerHTML = name;
document.querySelector("#userNameWrapper").style.display = "inline";
document.querySelector("#linkLogout").style.display = "inline";
}else{
document.querySelector("#linkLogin").style.display = "inline";
document.querySelector("#userNameWrapper").style.display = "none";
document.querySelector("#linkLogout").style.display = "none";
}
}
async function logout(){
let url = "/auth/logout";
let response = await fetch(url);
let data = await response.json();
console.log(data);
if(data.result=="success"){
// 개별 항목 삭제
// sessionStorage.removeItem("name");
// sessionStorage.removeItem("email");
// sessionStorage.removeItem("roles");
// 전체 삭제
sessionStorage.clear();
initUI();
} else{
alert("fail logout");
}
}
package com.mycom.myapp.user.service;
import com.mycom.myapp.user.dto.UserResultDto;
import com.mycom.myapp.user.entity.User;
public interface UserService {
UserResultDto insertUser(User user);
}
package com.mycom.myapp.user.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.mycom.myapp.user.dto.UserResultDto;
import com.mycom.myapp.user.entity.User;
import com.mycom.myapp.user.entity.UserRole;
import com.mycom.myapp.user.repository.UserRepository;
import com.mycom.myapp.user.repository.UserRoleRepository;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
// user 등록, role 등록
// insertUser의 파라미터는 userDto -> user로 변경하는 작업 필요
// 코드를 간단하게 하기 위해 user 사용
@Override
public UserResultDto insertUser(User user) {
UserResultDto userResultDto = new UserResultDto();
// 기존 userRole 이름으로 find
// default : 사용자에게 "IT" 역할 부여
List<UserRole> userRole = List.of(userRoleRepository.findByName("IT")); // IT UserRole은 findByName을 통해 영속화
user.setUserRoles(userRole);
User savedUser = userRepository.save(user); // 전달받은 user 객체는 save를 통해 영속화
System.out.println(savedUser);
userResultDto.setResult("success");
// Hibernate: select ur1_0.id,ur1_0.name from user_role ur1_0 where ur1_0.name=?
// Hibernate: insert into user (email,name,password) values (?,?,?)
// Hibernate: insert into user_user_roles (user_id,user_roles_id) values (?,?)
// User(id=6, name=aa, email=a, password=a)
return userResultDto;
}
}
package com.mycom.myapp.user.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.mycom.myapp.user.entity.UserRole;
public interface UserRoleRepository extends JpaRepository<UserRole, Integer>{
// 기본적인 crud
// role 이름으로 select
UserRole findByName(String name);
}
package com.mycom.myapp.auth.controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mycom.myapp.user.dto.UserResultDto;
import com.mycom.myapp.user.entity.User;
import com.mycom.myapp.user.service.UserService;
import lombok.RequiredArgsConstructor;
@RestController
@RequestMapping("/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/register")
public UserResultDto insertUser(User user) { // 원래 userDto를 받아서 userService에 전달하는게 올바른 방법
return userService.insertUser(user);
}
}

package com.mycom.myapp.user.service;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import com.mycom.myapp.user.dto.UserResultDto;
import com.mycom.myapp.user.entity.User;
import com.mycom.myapp.user.entity.UserRole;
import com.mycom.myapp.user.repository.UserRepository;
import com.mycom.myapp.user.repository.UserRoleRepository;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
// user 등록, role 등록
// insertUser의 파라미터는 userDto -> user로 변경하는 작업 필요
// 코드를 간단하게 하기 위해 user 사용
@Override
@Transactional // 트랜잭션 APO가 @가 붙은 모든 메소드에 대해 Proxy를 만들고 제어
// 잘 못 관리되면 필요없는 메소드까지 트랜잭션으로 관리 => 성능 저하
public UserResultDto insertUser(User user) {
UserResultDto userResultDto = new UserResultDto();
// #1 기존 UserRole 이름으로 find
// // 기존 userRole 이름으로 find
// // default : 사용자에게 "IT" 역할 부여
// List<UserRole> userRole = List.of(userRoleRepository.findByName("IT")); // IT UserRole은 findByName을 통해 영속화
// user.setUserRoles(userRole);
// User savedUser = userRepository.save(user); // 전달받은 user 객체는 save를 통해 영속화
// System.out.println(savedUser);
//
// userResultDto.setResult("success");
//
//// Hibernate: select ur1_0.id,ur1_0.name from user_role ur1_0 where ur1_0.name=?
//// Hibernate: insert into user (email,name,password) values (?,?,?)
//// Hibernate: insert into user_user_roles (user_id,user_roles_id) values (?,?)
//// User(id=6, name=aa, email=a, password=a)
// #2
// 새로운 역할 부여
// 객체가 새로 생성되어서 영속화 x 상태에서 user 객체와 연결되고 user객체만 save
// UserRole userRole = new UserRole(); // 영속화 x
// userRole.setName("test_role");
// List<UserRole> userRoles = List.of(userRole);
// user.setUserRoles(userRoles);
// User savedUser = userRepository.save(user); // 영속화
// System.out.println(savedUser);
// org.hibernate.TransientObjectException: persistent instance references an unsaved transient instance of 'com.mycom.myapp.user.entity.UserRole'
// #3 새로운 role 추가 + save
// UserRole userRole = new UserRole(); // 영속화 x
// userRole.setName("test_role");
// List<UserRole> userRoles = List.of(userRole);
// user.setUserRoles(userRoles);
// userRoleRepository.save(userRole); // userRole 영속화
// User savedUser = userRepository.save(user); // user 영속화
// System.out.println(savedUser);
// userRole -> user -> user_roles 순서대로 insert
// Hibernate: insert into user_role (name) values (?)
// Hibernate: insert into user (email,name,password) values (?,?,?)
// Hibernate: insert into user_user_roles (user_id,user_roles_id) values (?,?)
// #4 새로운 role 추가 + user entity에서 persist 설정
// UserRole userRole = new UserRole(); // 영속화 x
// userRole.setName("test_role");
// List<UserRole> userRoles = List.of(userRole);
// user.setUserRoles(userRoles);
// User savedUser = userRepository.save(user); // user 영속화
// System.out.println(savedUser);
// user -> role -> user_role insert
// Hibernate: insert into user (email,name,password) values (?,?,?)
// Hibernate: insert into user_role (name) values (?)
// Hibernate: insert into user_user_roles (user_id,user_roles_id) values (?,?)
//////////////// RuntimException
// #5 role 추가 + persist x + userRole save
// userRole save + NullPointerException + user save
// UserRole userRole = new UserRole();
// userRole.setName("test_role");
// List<UserRole> userRoles = List.of(userRole);
// user.setUserRoles(userRoles);
// userRoleRepository.save(userRole);
//
// // 예외 발생
// String s = null;
// s.length();
//
// User savedUser = userRepository.save(user);
// System.out.println(savedUser);
//
// // userRole은 추가됨 => 트랜잭션 처리 x
//
// // @Transactional 추가 => 트랜잭션 처리 o (userRole도 추가 안됨)
//
//
// userResultDto.setResult("success");
////////////// 중간 결과
// 여러 개의 repository 작업을 하나의 단위로 처리 가능
// 하지만, 응답 약속인 ~ReaultDto 생성 문제 발생 => try-catch 도입
///////// 에외 + try-catch + @Transactional사용
try {
UserRole userRole = new UserRole();
userRole.setName("test_role");
List<UserRole> userRoles = List.of(userRole);
user.setUserRoles(userRoles);
userRoleRepository.save(userRole);
// 예외 발생
// String s = null;
// s.length();
User savedUser = userRepository.save(user);
System.out.println(savedUser);
userResultDto.setResult("success");
} catch(Exception e) {
e.printStackTrace();
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
userResultDto.setResult("fail");
}
// userRole 추가됨 => 에러 처리(result는 fail)해서 큰 문제없다고 판단하기 때문에 트랜잭션 처리 x
// TransactionAspectSupport 추가 => 트랜잭션 처리 o
return userResultDto;
}
}
@OneToMany(cascade=CascadeType.PERSIST, fetch=FetchType.EAGER
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h1>register.html</h1>
<hr>
<div>
name : <input type="text" name="name" id="name">
</div>
<div>
email : <input type="text" name="email" id="email">
</div>
<div>
password : <input type="password" name="password" id="password">
</div>
<button id="btnRegister">register</button>
<script>
window.onload=function(){
document.querySelector("#btnRegister").onclick = register;
}
async function register(){
// parameter, value
let name = document.querySelector("#name").value;
let email = document.querySelector("#email").value;
let password = document.querySelector("#password").value;
let urlParams = new URLSearchParams({
name, email, password // shorthand property
});
// url
let url = "/users/register";
//fetch options
let fetchOptions = {
method:"post",
body:urlParams
}
let response = await fetch(url, fetchOptions);
let data = await response.json();
console.log(data);
if(data.result == "success"){
// move page
window.location.href="/login.html";
} else{
alert("failed register")
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
<style>
#navbar{
display:none;
}
</style>
</head>
<body>
<h1>board.html</h1>
<hr>
<div id=navbar>
<!-- 로그인 여부에 따라 달라지는 UI -->
<a href="/login.html" id="linkLogin">Login |</a>
<span id="userNameWrapper"> <span id="userName"></span>님 안녕하세요 |</span>
<a href="#" id="linkLogout">Logout |</a>
<!-- 로그인 상관없는 UI -->
<a href="board.html">Board |</a>
<a href="register.html" id="linkRegister">Register</a>
</div>
<script src="/assets/js/common.js"></script>
<script>
window.onload = function(){
initUI();
// logout
document.querySelector("#linkLogout").onclick = logout;
}
</script>
</body>
</html>
common.js도 수정
initUI(){
document.querySelector("#navbar").style.display="block";
}