11/27

AI·2025년 11월 27일

한 페이지로 할 수 있으면 하지만 일단 페이지 나눠서 작업
로그인해서 페이지가 바뀌면, 로그인에 대한 내용이 날라감 -> local storage(저장 비휘발성), session storage(휘발성)에 선택해 저장

index

<!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>

login

<!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>

controller - logout 추가

	@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;
	}

common.js

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");
	}
}

register

Service

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);
}

ServiceImpl

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;
	}

}

UserRoleRepository

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);
	
}

controller

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);
	}
}

ServiceImpl 추가

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;
	}
	

}

user.java 변경

@OneToMany(cascade=CascadeType.PERSIST, fetch=FetchType.EAGER

register.html

<!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>

board.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";
}

0개의 댓글