1. Exception Handler 처리 
2. @ControllerAdvice 와 @RestControllerAdvice 에 차이점을 이해 하자 
3. 사용자 정의 예외 클래스를 만들어 보자. 
4. 직접 예외 발생 시켜 보기 (사용자 정의 예외 클래스 활용)
5. 예외 페이지 생성 및 활용 (errorPage.jsp 생성)

Exception Handler 

스프링 MVC 의 중요한 구성 요소 중에 하나로 AOP 기반에 개념 입니다. 
구현하는 방법 중 하나는 @ExcetptionHandler 어노테이션을 사용하고 이 어노테이션은 
예외가 발생한 메서드를 구현하고, 처리할 예외 타입을 지정합니다.

@ControllerAdvice 와 @RestControllerAdvice 에 차이점

@ControllerAdvice와 @RestControllerAdvice는 모두 예외 처리를 담당하는 클래스에 
붙는 어노테이션으로 스프링에서 예외 처리를 담당하는 핵심적인 요소 중 하나입니다. 
그러나 두 어노테이션에 차이점은 반환 타입과 기본 응답 형태 입니다. 

@ControllerAdvice 어노테이션은 View 렌더링을 위해 ModelAndView 형태로 객체를 반환하도록 
기본 설정이 되어 있습니다. 즉 요청에 대한 응답이 view 형태로 전달되며, 
JSP 와 같은 템플릿 엔진을 사용할 수 있습니다. 


반면에 @RestControllerAdvice RESTfull 웹 서비스에서 사용하기 적합한 형태로 
응답 처리가 되며 응답에 형태는 JSON, XML 형태로 반환이 됩니다.

패키지 구조 

사용자 정의 클래스 만들어 보기

package com.tenco.bank.handler.exception;

import org.springframework.http.HttpStatus;

import lombok.Getter;

// Ioc 대상이 아님 (필요할 때 직접 new 처리) 
@Getter
public class CustomRestfullException extends RuntimeException {
	
	private HttpStatus status;
	// throw new CustomRestfullException('페이지 못 찾음', 404);
	public CustomRestfullException(String message, HttpStatus status) {
		super(message);
		this.status = status;
	}
	
}

 

package com.tenco.bank.handler.exception;

import org.springframework.http.HttpStatus;

public class CustomPageException extends RuntimeException {
	
	private HttpStatus status;
	
	public CustomPageException(String message, HttpStatus status) {
		super(message);
		this.status = status;
	}
	
}

ExceptionHandler 처리 하기 - @RestControllerAdvice 사용

package com.tenco.bank.handler;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.tenco.bank.handler.exception.CustomRestfullException;

/**
 * 예외 발생 시 (Json, XML)  
 * 데이터를 내려 줄 수 있다
 */
@RestControllerAdvice // IoC 대상 + AOP 기반 
public class MyRestfullExceptionHandler {
	
	@ExceptionHandler(Exception.class)
	public void exception(Exception e) {
		System.out.println(e.getClass().getName());
		System.out.println(e.getMessage());
	}
	
	// 사용자 정의 예외 클래스 활용
	@ExceptionHandler(CustomRestfullException.class)
	public String basicException(CustomRestfullException e) {
		StringBuffer sb = new StringBuffer();
		sb.append("<script>");
		// 반드시 마지막에 ; 콜론을 붙어서 사용하자.
		sb.append("alert('"+ e.getMessage() +"');"); 
		sb.append("history.back();");
		sb.append("</script>");
		return sb.toString();
	}
}

ExceptionHandler 처리 하기 - @ControllerAdvice 사용

package com.tenco.bank.handler;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import com.tenco.bank.handler.exception.CustomPageException;

/**
 * 
 * View 렌더링을 위해 ModelAndView 
 * 객체를 반환하도록 기본 설정 되어 있다. 
 * 예외 page를 리턴하도록 활용 예정 
 */
@ControllerAdvice
public class MyPageExceptionHandler {
	
	// 사용자 정의 클래스 활용
	@ExceptionHandler(CustomPageException.class)
	public ModelAndView handleRuntimePageException(CustomPageException e) {
		// ModelAndView 활용 방법 
		ModelAndView modelAndView = new ModelAndView("errorPage");
		modelAndView.addObject("statusCode", HttpStatus.NOT_FOUND.value());
		modelAndView.addObject("message", e.getMessage());
		return modelAndView;
	}
}

예외 발생 시켜 보기 1,2

public class AccountController {

	/**
	 * 계좌 목록 페이지 
	 * @return 목록 페이지 이동
	 */
	@GetMapping({"/list", "/"})
	public void list() {		
		// todo 예외 테스트 - 삭제 예정  
		//throw new CustomRestfullException("인증되지 않은 사용자 입니다.", HttpStatus.UNAUTHORIZED);
		throw new CustomPageException("페이지를 찾을 수 없습니다", HttpStatus.NOT_FOUND);
		
		// return "/account/list";
	}
... 생략 
}

예외 페이지 생성 및 활용 (errorPage.jsp 생성) /WEB-INF/view/errorPage.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page isErrorPage="true" %>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>에러 페이지</h1>
	<p>에러 코드 : ${statusCode}</p>
	<p>에러 메서지 : ${message}</p>
	
</body>
</html>
1. UserController 생성 
2. 회원 가입, 로그인 화면 구현하기 
3. AccountController 생성 
4. 계좌목록,출금,입금,계좌생성,계좌상세보기 페지이 만들기

UserController 파일 생성

package com.tenco.bank.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.tenco.bank.dto.SignInFormDto;
import com.tenco.bank.dto.SignUpFormDto;

@Controller
@RequestMapping("/user")
public class UserController {
	
	// http://localhost:8080/user/sign-up
	@GetMapping("/sign-up")
	public String signUp() {
		// prefix 
		// subfix 
		return "/user/signUp";
	}
	

	/**
	 * 회원 가입 처리 
	 * @param signUpFormDto
	 * @return 리다이렉트 로그인 페이지
	 */
	@PostMapping("/sign-up")
	public String signUpProc(SignUpFormDto signUpFormDto) {
		
		return "redirect:/user/sign-in";
	}
	
	/**
	 * 로그인 폼
	 * @return 로그인 페이지 
	 */
	@GetMapping("/sign-in")
	public String signIn() {
		
		return "/user/signIn";
	}
	
	/**
	 * 로그인 처리 
	 * @param signInFormDto
	 * @return 메인 페이지 이동 (수정 예정)
	 */
	@PostMapping("/sign-in")
	public String signInProc(SignInFormDto signInFormDto) {
		
		// todo 변경 예정 
		return "/test/main";
	}
	

}

회원 가입 화면 구현 (signUp.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/view/layout/header.jsp"%>

<!-- todo main 영역으로 지정 예정  -->
<div class="col-sm-8">
	<h2>회원 가입</h2>
	<h5>어서오세요 환영합니다</h5>
	<div class="bg-light p-md-5 h-75">
		<form action="/user/sign-up" method="post">
			<div class="form-group">
				<label for="username">User name:</label>
				<input type="text" class="form-control" placeholder="Enter username" id="username" name="username">
			</div>
			<div class="form-group">
				<label for="password">Password:</label>
				<input type="password" class="form-control" placeholder="Enter password" id="password" name="password">
			</div>
			<div class="form-group">
				<label for="fullname">Fullname:</label>
				<input type="text" class="form-control" placeholder="Enter fullname" id="fullname" name="fullname">
			</div>
			<button type="submit" class="btn btn-primary">Submit</button>
		</form>
	</div>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

로그인 화면 구현 처리 (signIn.jsp )

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/view/layout/header.jsp"%>

<div class="col-sm-8">
	<h2>로그인 </h2>
	<h5>어서오세요 환영합니다</h5>
	<div class="bg-light p-md-5 h-75">
		<form action="/user/sign-in" method="post">
			<div class="form-group">
				<label for="username">User name:</label>
				<input type="text" class="form-control" placeholder="Enter username" id="username" name="username">
			</div>
			<div class="form-group">
				<label for="password">Password:</label>
				<input type="password" class="form-control" placeholder="Enter password" id="password" name="password">
			</div>
			<button type="submit" class="btn btn-primary">Submit</button>
		</form>
	</div>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

AccountController 파일 생성

package com.tenco.bank.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/account")
public class AccountController {

	/**
	 * 계좌 목록 페이지 
	 * @return 목록 페이지 이동
	 */
	@GetMapping({"/list", "/"})
	public String list() {
		return "/account/list";
	}
	
	// 출금 페이지 
	@GetMapping("/withdraw")
	public String withdraw() {
		return "/account/withdrawForm";
	}
	
	
	// 입금 페이지
	@GetMapping("/deposit")
	public String deposit() {
		return "/account/depositForm";
	}
	
	// 이체 페이지 
	@GetMapping("/transfer")
	public String transfer() {
		return "/account/transferForm";
	}
	
	// 계좌 생성 페이지 
	@GetMapping("/save")
	public String save() {
		return "/account/saveForm";
	}
	
	// 계좌 상세 보기 페이지 
	@GetMapping("/detail")
	public String detail() {
		return "";
	}
	
	
}

계좌 목록 페이지 구성 (list.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/view/layout/header.jsp"%>

<div class="col-sm-8">
	<h2>나의 계좌 목록 </h2>
	<h5>어서오세요 환영합니다</h5>
	<div class="bg-light p-md-5 h-75">
		<table class="table">
			<thead>
				<tr>
					<th>계좌 번호</th>
					<th>잔액</th>
				</tr>
			</thead>
			<tbody>
				<tr>
					<td>1111</td>
					<td>500원</td>
				</tr>
				<tr>
					<td>2222</td>
					<td>200원</td>
				</tr>
			</tbody>
		</table>
	</div>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

출금 계좌 화면 구현 (withdraw.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ include file="/WEB-INF/view/layout/header.jsp"%>
<!-- todo main 영역으로 지정 예정 -->
<div class="col-sm-8">
	<h2>출금 페이지(인증)</h2>
	<h5>어서오세요 환영합니다.</h5>
	<div class="bg-light p-md-5 h-75">
		<form action="#" method="post">
			<div class="form-group">
				<label for="amount">출금 금액:</label> 
				<input type="text" class="form-control" placeholder="출금 금액을 입력하시오" id="amount" name="amount">
			</div>
			<div class="form-group">
				<label for="wAccountNumber">출금 계좌 번호:</label> 
				<input type="text" class="form-control" placeholder="출금 계좌번호" id="wAccountNumber" name="wAccountNumber">
			</div>				
			<div class="form-group">
				<label for="wAccountPassword">출금 계좌 비밀번호:</label> 
				<input type="password" class="form-control" placeholder="출금 계좌비밀번호" id="wAccountPassword" name="wAccountPassword">
			</div>				
			<button type="submit" class="btn btn-primary">출금</button>
		</form>
	</div>
	<br>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

입금 계좌 화면 구성(depositForm.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/view/layout/header.jsp"%>

<div class="col-sm-8">
	<h2>계좌 생성 페이지(인증)</h2>
	<h5>어서오세요 환영합니다</h5>
		<div class="bg-light p-md-5 h-75">
		<form action="#" method="post">
			<div class="form-group">
				<label for="number">계좌 번호:</label>
				<input type="text" class="form-control" placeholder="생성 계좌 번호 입력" id="number" name="number">
			</div>
			<div class="form-group">
				<label for="password">계좌 비밀번호:</label>
				<input type="password" class="form-control" placeholder="계좌 비밀번호 입력" id="password" name="password">
			</div>
			<div class="form-group">
				<label for="balance">입금 금액:</label>
				<input type="text" class="form-control" placeholder="출금계좌비밀번호" id="balance" name="balance">
			</div>
			
			<button type="submit" class="btn btn-primary">계좌 생성</button>
		</form>
	</div>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

이체 계좌 화면 구성 (transferForm.jsp )

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ include file="/WEB-INF/view/layout/header.jsp"%>
<!-- todo main 영역으로 지정 예정 -->
<div class="col-sm-8">
	<h2>이체 페이지(인증)</h2>
	<h5>어서오세요 환영합니다.</h5>
	<div class="bg-light p-md-5 h-75">
		<form action="#" method="post">
			<div class="form-group">
				<label for="amount">이체 금액:</label> 
				<input type="text" class="form-control" placeholder="이체 금액을 입력하시오" id="amount" name="amount">
			</div>
			<div class="form-group">
				<label for="wAccountNumber">출금 계좌 번호:</label> 
				<input type="text" class="form-control" placeholder="출금 계좌번호" id="wAccountNumber" name="wAccountNumber">
			</div>				
			<div class="form-group">
				<label for="dAccountNumber">이체할 계좌 번호:</label> 
				<input type="text" class="form-control" placeholder="이체 계좌번호" id="dAccountNumber" name="dAccountNumber">
			</div>				
			<div class="form-group">
				<label for="wAccountPassword">출금 계좌 비밀번호:</label> 
				<input type="password" class="form-control" placeholder="출금 계좌비밀번호" id="wAccountPassword" name="wAccountPassword">
			</div>				
			<button type="submit" class="btn btn-primary">이체</button>
		</form>
	</div>
	<br>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

계좌 생성(saveForm.jsp)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<%@ include file="/WEB-INF/view/layout/header.jsp"%>
<!-- todo main 영역으로 지정 예정 -->
<div class="col-sm-8">
	<h2>계좌 생성 페이지(인증)</h2>
	<h5>어서오세요 환영합니다.</h5>
	<div class="bg-light p-md-5 h-75">
		<form action="#" method="post">
			<div class="form-group">
				<label for="number">계좌 번호:</label> 
				<input type="text" class="form-control" placeholder="생성할 계좌 번호 입력" id="number" name="number">
			</div>
			<div class="form-group">
				<label for="password">계좌 비밀번호:</label> 
				<input type="password" class="form-control" placeholder="계좌 비밀번호 입력" id="password" name="password">
			</div>				
			<div class="form-group">
				<label for="balance">입금 금액:</label> 
				<input type="text" class="form-control" placeholder="입금 금액" id="balance" name="balance">
			</div>				
			<button type="submit" class="btn btn-primary">계좌 생성</button>
		</form>
	</div>
	<br>
	<br>
</div>

<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

header.jsp 주소 연결

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<html lang="en">
<head>
<title>My Bank</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.slim.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="/css/styles.css">
<style>

</style>
</head>
<body>

	<div class="jumbotron text-center banner--img" style="margin-bottom: 0">
		<h1 class="m--title">My Bank</h1>
		<img alt="sample" src="https://picsum.photos/300/200">
	</div>

	<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
		<a class="navbar-brand" href="#">MENU</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse"
			data-target="#collapsibleNavbar">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="collapsibleNavbar">
			<ul class="navbar-nav">
				<li class="nav-item"><a class="nav-link" href="#">Home</a></li>
				<li class="nav-item"><a class="nav-link" href="/user/sign-in">로그인</a></li>
				<li class="nav-item"><a class="nav-link" href="/user/sign-up">회원가입</a></li>
			</ul>
		</div>
	</nav>

	<div class="container" style="margin-top: 30px">
		<div class="row">
			<div class="col-sm-4">
				<h2>About Me</h2>
				<h5>Photo of me:</h5>
				<div class="m--profile"></div>
				<p style="padding: 8px 0">자라나는 코린이에 은행 관리 시스템 입니다</p>
				<h3>Some Links</h3>
				<p>Lorem ipsum dolor sit ame.</p>
				<ul class="nav nav-pills flex-column">
					<li class="nav-item"><a class="nav-link" href="/account/save">계좌생성</a></li>
					<li class="nav-item"><a class="nav-link"  href="/account/list">계좌목록</a></li>
					<li class="nav-item"><a class="nav-link" href="/account/withdraw">출금</a></li>
					<li class="nav-item"><a class="nav-link" href="/account/deposit">입금</a></li>
					<li class="nav-item"><a class="nav-link" href="/account/transfer">이체</a></li>
					<li class="nav-item"><a class="nav-link disabled" href="#">My Info</a>
					</li>
				</ul>
				<hr class="d-sm-none">
			</div>

 

정적 파일은 static 폴더에 html 파일 및 css, js, images 등 추가할 수 있다 

1. 템플릿 엔진 JSP 사용하기로 결정 됨 (의존성) 확인 필요 
2. yml 설정 확인하기 (폴더 구조 확인)  
3. bootstrap 4 css 프레임워크 사용하기 
4. layout 구성 하기  (https://picsum.photos/ 사용 )

의존성 추가 확인

implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'

implementation 'javax.servlet:jstl'


환경 설정 확인

spring:
  mvc:
    view:
      prefix: /WEB_INF/view/
      suffix: .jsp
      
spring boot 에서 ViewResolver 는 컨트롤러가 반환한 뷰 이름과 매핑하여 
해당 뷰 파일을 찾고, 렌터링 하는 일을 수행 하는 인터페이스 입니다. 

/WEB-INF/view/xxx/xxx.jsp

main.jsp 기본 화면 적용해보기

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<html lang="en">
<head>
<title>My Bank</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.slim.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<style>
.fakeimg {
	height: 200px;
	background: #aaa;
}
/* 배너 백그라운드 처리하기  */
.banner--img {
	background-image: url('https://picsum.photos/600');
	background-size: cover;
	background-position: center;
	width: 100%;
}

.m--profile {
	background-image: url('https://picsum.photos/id/1/350');
	background-size: cover;
	background-position: center;
	width: 100%;
	height: 200px;
}

.m--title {
	color: aqua;
}
</style>
</head>
<body>

	<div class="jumbotron text-center banner--img" style="margin-bottom: 0">
		<h1 class="m--title">My Bank</h1>
		<img alt="sample" src="https://picsum.photos/300/200">
	</div>

	<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
		<a class="navbar-brand" href="#">MENU</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse"
			data-target="#collapsibleNavbar">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="collapsibleNavbar">
			<ul class="navbar-nav">
				<li class="nav-item"><a class="nav-link" href="#">Home</a></li>
				<li class="nav-item"><a class="nav-link" href="#">SignIn</a></li>
				<li class="nav-item"><a class="nav-link" href="#">SignUp</a></li>
			</ul>
		</div>
	</nav>

	<div class="container" style="margin-top: 30px">
		<div class="row">
			<div class="col-sm-4">
				<h2>About Me</h2>
				<h5>Photo of me:</h5>
				<div class="m--profile"></div>
				<p style="padding: 8px 0">자라나는 코린이에 은행 관리 시스템 입니다</p>
				<h3>Some Links</h3>
				<p>Lorem ipsum dolor sit ame.</p>
				<ul class="nav nav-pills flex-column">
					<li class="nav-item"><a class="nav-link" href="#">계좌생성</a>
					</li>
					<li class="nav-item"><a class="nav-link"  href="#">계좌목록</a></li>
					<li class="nav-item"><a class="nav-link" href="#">출금</a></li>
					<li class="nav-item"><a class="nav-link" href="#">입금</a></li>
					<li class="nav-item"><a class="nav-link" href="#">이체</a></li>
					<li class="nav-item"><a class="nav-link disabled" href="#">My Info</a>
					</li>
				</ul>
				<hr class="d-sm-none">
			</div>


			<!-- todo main 영역으로 지정 예정  -->
			<div class="col-sm-8">
				<h2>TITLE HEADING</h2>
				<h5>Title description, Dec 7, 2017</h5>
				<div class="fakeimg">Fake Image</div>
				<p>Some text..</p>
				<p>Sunt in culpa qui officia deserunt mollit anim id est laborum
					consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
					labore et dolore magna aliqua. Ut enim ad minim veniam, quis
					nostrud exercitation ullamco.</p>
				<br>
			</div>
		</div>
	</div>
	
	<div class="f-wrap">
		<div class="jumbotron text-center" style="margin-bottom: 0">
			<p>Footer</p>
		</div>
	</div>
</body>
</html>

layout 구성 하기

header.jsp 파일 생성 및 설정

footer.jsp 파일 생성 및 설정

css 폴더 생성 및 설정


header.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<html lang="en">
<head>
<title>My Bank</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script
	src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.slim.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
	src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<style>
.fakeimg {
	height: 200px;
	background: #aaa;
}
/* 배너 백그라운드 처리하기  */
.banner--img {
	background-image: url('https://picsum.photos/600');
	background-size: cover;
	background-position: center;
	width: 100%;
}

.m--profile {
	background-image: url('https://picsum.photos/id/1/350');
	background-size: cover;
	background-position: center;
	width: 100%;
	height: 200px;
}

.m--title {
	color: aqua;
}
</style>
</head>
<body>

	<div class="jumbotron text-center banner--img" style="margin-bottom: 0">
		<h1 class="m--title">My Bank</h1>
		<img alt="sample" src="https://picsum.photos/300/200">
	</div>

	<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
		<a class="navbar-brand" href="#">MENU</a>
		<button class="navbar-toggler" type="button" data-toggle="collapse"
			data-target="#collapsibleNavbar">
			<span class="navbar-toggler-icon"></span>
		</button>
		<div class="collapse navbar-collapse" id="collapsibleNavbar">
			<ul class="navbar-nav">
				<li class="nav-item"><a class="nav-link" href="#">Home</a></li>
				<li class="nav-item"><a class="nav-link" href="#">SignIn</a></li>
				<li class="nav-item"><a class="nav-link" href="#">SignUp</a></li>
			</ul>
		</div>
	</nav>

	<div class="container" style="margin-top: 30px">
		<div class="row">
			<div class="col-sm-4">
				<h2>About Me</h2>
				<h5>Photo of me:</h5>
				<div class="m--profile"></div>
				<p style="padding: 8px 0">자라나는 코린이에 은행 관리 시스템 입니다</p>
				<h3>Some Links</h3>
				<p>Lorem ipsum dolor sit ame.</p>
				<ul class="nav nav-pills flex-column">
					<li class="nav-item"><a class="nav-link" href="#">계좌생성</a>
					</li>
					<li class="nav-item"><a class="nav-link"  href="#">계좌목록</a></li>
					<li class="nav-item"><a class="nav-link" href="#">출금</a></li>
					<li class="nav-item"><a class="nav-link" href="#">입금</a></li>
					<li class="nav-item"><a class="nav-link" href="#">이체</a></li>
					<li class="nav-item"><a class="nav-link disabled" href="#">My Info</a>
					</li>
				</ul>
				<hr class="d-sm-none">
			</div>

footer.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
		
		</div>
	</div>
	
	<div class="f-wrap">
		<div class="jumbotron text-center" style="margin-bottom: 0">
			<p>Footer</p>
		</div>
	</div>
</body>
</html>

main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	
<%@ include file="/WEB-INF/view/layout/header.jsp" %>


			<!-- todo main 영역으로 지정 예정  -->
			<div class="col-sm-8">
				<h2>TITLE HEADING</h2>
				<h5>Title description, Dec 7, 2017</h5>
				
				<br>
			</div>
			
<%@ include file="/WEB-INF/view/layout/footer.jsp" %>

 

'Spring boot > spring boot 앱 만들어 보기 2 단원' 카테고리의 다른 글

bank app - Exception Handler  (0) 2023.04.18
bank app - 화면 구현(2)  (0) 2023.04.17
bank app MyBatis 설정  (0) 2023.04.17
bank app - h2 db 초기 값 설정  (0) 2023.04.17
bank app 모델링  (0) 2023.04.17
1. MyBatis 에 대한 개념 
2. yml 파일에 MyBaits 설정 하기 (의존성 추가 되어 있는 상태)
3. UserRepository 인터페이스 선언 하기 
4. user.xml 파일 정의 
5. AccountRepository 인터페이스 선언 
6. account.xml 파일 정의 
7. HistoryRepository 인터페이스 선언 
8. history.xml 파일 정의

MyBatis

자바 객체와 SQL문 사이의 자동 매핑을 지원하는 매퍼프레임 워크입니다. 

MyBatis에서는 SQL 쿼리를 작성할 때 XML 또는 어노테이션을 이용해서 작업할 수 있습니다. 
이를 통해 쿼리 구문을 작성하고 데이터 베이스와 통신을 수행할 수 있습니다. 

MyBatis는 매우 유연한 구조를 가자고 있어 SQL 쿼리와 자바 객체의 매핑 규칙을 
세부적으로 지정할 수 있으며 동적 SQL 쿼리 구문을 작성할 수 있게 지원합니다.

mybatis yml 파일에 설정하기

: ibatis ← 이전 이름 ( 2.4 이 후부터는 mybatis 변경 됨)

server:
  port: 8080
  servlet:
    encoding:
      charset: utf-8
      force: true
      

spring:
  mvc:
    view:
      prefix: /WEB-INF/view/
      suffix: .jsp
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password: 
  sql:
    init:
      schema-locations:
      - classpath:db/table.sql
      data-locations:
      - classpath:db/data.sql

  h2:
    console:
      enabled: true
  output:
    ansi: 
      enabled: always
      
      
mybatis:
  mapper-locations:
  - classpath:mapper/**.xml    
  configuration:
    map-underscore-to-camel-case: true

UserRepository 인터페이스 선언 하기

@Mapper  // MyBatis 의존 설정 함(build.gradle 파일) 
public interface UserRepository {
	public int insert(User user);
	public int updateById(User user); 
	public int deleteById(Integer id);
	public User findById(Integer id); 
	public List<User> findAll();
}

mapper/user.xml 파일 생성 DB 접근 기술 - UserDAO를 구현 했다면
Mybatis 는 xml 파일로 설정 합니다.
이점은 Connection, PreparedStatement, ResultSet
알아서 관리 및 매핑 해주고 close 처리를 자동으로 해준다.

user.xml 파일 정의

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tenco.bank.repository.interfaces.UserRepository"> 
	
	<insert id="insert">
		insert into user_tb (username, password, fullname, created_at)
		values( #{username}, #{password}, #{fullname}, now())
	</insert>
	
	<update id="updateById">
		update user_tb set username = #{username}, password = #{password}, 
		                fullname = #{fullname} where id = #{id}
	</update>
	
	<delete id="deleteById">
		delete from user_tb where id = #{id}
	</delete>
	
	
	<select id="findById" resultType="com.tenco.bank.repository.model.User">
		select * from user_tb where id = #{id}
	</select>
	
	<select id="findAll" resultType="com.tenco.bank.repository.model.User">
		select * from user_tb
	</select>
	
	
</mapper>

AccountRepository 인터페이스 선언

package com.tenco.bank.repository.interfaces;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.tenco.bank.repository.model.Account;

@Mapper // mybatis 연결 처리 
public interface AccountRepository {
	
	public int insert(Account account); 
	public int updateById(Account account); 
	public int deleteById(int id); 
	
	public List<Account> findAll();   
	public Account findById(int id); 
}

account.xml 파일 정의

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tenco.bank.repository.interfaces.AccountRepository"> 
	
	<insert id="insert">
		insert into account_tb(number, password, balance, user_id, created_at)
		values(#{number}, #{password}, #{balance}, #{userId}, now())
	</insert>	
	
	<update id="updateById">
		update account_tb set number = #{number}, password = #{password},
			balance = #{balance}, user_id = #{userId} where id = #{id}
	</update>
	
	<delete id="deleteById">
		delete from account_tb where id = #{id}
	</delete>
	
	<select id="findById" resultType="com.tenco.bank.repository.model.Account">
		select * from account_tb where id = #{id}
	</select>
	
	<select id="findAll" resultType="com.tenco.bank.repository.model.Account">
		select * from account_tb 
	</select>
</mapper>

HistoryRepository 인터페이스 선언

package com.tenco.bank.repository.interfaces;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.tenco.bank.repository.model.History;

@Mapper // 반드시 지정하기 ! 
public interface HistoryRepository {
	
	public int insert(History history); 
	public int updateById(History history); 
	public int deleteById(int id); 
	public History findById(int id);
	public List<History> findAll(); 
	
}

history.xml 파일 정의

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
	namespace="com.tenco.bank.repository.interfaces.HistoryRepository">

	<insert id="insert"
		parameterType="com.tenco.bank.repository.model.History">
		insert into
		history_tb(
		amount, w_balance, d_balance,
		w_account_id, d_account_id
		)
		values(
		#{amount}, #{wBalance}, #{dBalance},
		#{wAccountId}, #{dAccountId}
		)
	</insert>

	<update id="updateById"
		parameterType="com.tenco.bank.repository.model.History">
		update history_tb
		set amount = #{amount},
		w_balance =	#{wBalance},
		d_balace = #{dBalance},
		w_account_id = #{wAccountId},
		d_account_id = #{dAccountId}
		where id = #{id}
		
	</update>

	<delete id="deleteById" parameterType="int">
		delete from history_tb
		where id = #{id}
	</delete>
	
	<select id="findById" resultType="com.tenco.bank.repository.model.History">
		select * from history_tb where id = #{id}
	</select>

	<select id="findAll" resultType="com.tenco.bank.repository.model.History">
		select * from history_tb
	</select>


</mapper>

 

'Spring boot > spring boot 앱 만들어 보기 2 단원' 카테고리의 다른 글

bank app - 화면 구현(2)  (0) 2023.04.17
bank app 화면 구현(1)  (0) 2023.04.17
bank app - h2 db 초기 값 설정  (0) 2023.04.17
bank app 모델링  (0) 2023.04.17
패키지 설정  (0) 2023.04.17

H2 메모리 DB 초기 테이블 설정 및 초기 데이터 셋팅

1. yml 파일 확인 및 추가 설정

2. H2 인 메모리 접근 및 데이터 확인


yml 설정

server:
  port: 8080
  servlet:
    encoding:
      charset: utf-8
      force: true
      


spring:
  mvc:
    view:
      prefix: /WEB_INF/view/
      suffix: .jsp
  datasource:
    url: jdbc:h2:mem:testdb;MODE=MySQL
    driver-class-name: org.h2.Driver
    username: sa
    password:
  sql: 
    init:
      schema-locations:
      - classpath:db/table.sql  
      data-locations:
      - classpath:db/data.sql
      
  h2:
    console:
      enabled: true
  output:
    ansi: 
      enabled: always

초기 스키마 설정

-- 유저 테이블 설계해 보기 
CREATE TABLE user_tb(
	id int AUTO_INCREMENT PRIMARY KEY, 
    username VARCHAR(50) not null UNIQUE, 
    password VARCHAR(30) not null, 
    fullname VARCHAR(50) not null, 
    created_at TIMESTAMP not null DEFAULT now()
);

-- 사용자에 계좌 정보 테이블 설계 
CREATE TABLE account_tb(
	id int AUTO_INCREMENT PRIMARY KEY, 
    number VARCHAR(30) not null UNIQUE, 
    password VARCHAR(20) not null, 
    balance BIGINT not null COMMENT '계좌 잔액',
    user_id int, 
    created_at TIMESTAMP not null DEFAULT now()
);

-- 입금 내역 저장 
-- 출금 내역 저장 
-- 사용자간 이체 내역 저장 

-- 사용자들에 history 테이블 설계 
-- BIGINT 8바이트 크기에 정수형 
-- 조(10에 12) -- 경(10에 16승) -- 해(10에20승)
-- 자(10에 24) -- 양(10에 28)
 
 
CREATE TABLE history_tb(
	id int AUTO_INCREMENT PRIMARY key COMMENT '거래 내역 ID', 
	amount BIGINT not null COMMENT '거래 금액',
	w_account_id int COMMENT '출금 계좌 id',
	d_account_id int COMMENT '입금 계좌 id',
	w_balance BIGINT COMMENT '출금 요청된 계좌에 잔액',
	d_balance BIGINT COMMENT '입금 요청된 계좌에 잔액', 
	created_at TIMESTAMP not NULL DEFAULT now() 
);

초기 데이터 등록

INSERT INTO user_tb(username, password, fullname, created_at) values('길동', '1234',
'고', now());
INSERT INTO user_tb(username, password, fullname, created_at) values('둘리', '1234',
'애기공룡', now());
INSERT INTO user_tb(username, password, fullname, created_at) values('콜', '1234',
'마이', now());


INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('1111', '1234', 900, 1, now());
INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('2222', '1234', 1100, 2, now());
INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('333', '1234', 0, 3, now());



-- 이체 내역을 기록 ( 1번 계좌에서 2번 계좌로 100원을 이체 한다) 
INSERT INTO history_tb(amount, w_balance, d_balance, 
					   w_account_id, d_account_id, created_at)
VALUES (100, 900, 1100, 1, 2, now());

-- 출금 내역 ( 1번계좌에서 100원을 출금 처리 )
INSERT INTO history_tb(amount, w_balance, d_balance, 
					   w_account_id, d_account_id, created_at)
VALUES (100, 800, null, 1, null, now());

-- 입금 내역 (1번 계좌에 500원 입금 처리 )
INSERT INTO history_tb(amount, w_balance, d_balance, 
					   w_account_id, d_account_id, created_at)
VALUES (500, null, 700, null, 1, now());

결과 확인

'Spring boot > spring boot 앱 만들어 보기 2 단원' 카테고리의 다른 글

bank app 화면 구현(1)  (0) 2023.04.17
bank app MyBatis 설정  (0) 2023.04.17
bank app 모델링  (0) 2023.04.17
패키지 설정  (0) 2023.04.17
프로젝트 설정  (0) 2023.04.17
TRM 기반으로 모델링을 해보자 

Table Relational mapping은 데이터베이스의 테이블과 애플리케이션의 객체 간의 매핑을 의미합니다. 

MyBatis에서는 데이터베이스 쿼리를 XML 파일로 작성하고, 
Java 코드에서 이를 호출하는 방식으로 데이터베이스와의 상호작용을 수행합니다. 
XML 파일에서는 SQL 쿼리를 작성하고, Java 코드에서는 이를 호출하여 결과를 반환합니다.

1. 테이블 설계 
2. 비지니스 로직 기본 확인 
3. 모델링 구현

user.xml 파일

<select id="selectUserById" resultType="User">
  SELECT id, name, email
  FROM user
  WHERE id = #{id}
</select>

테이블 설계

CREATE DATABASE bank;
use bank;

-- 유저 테이블 설계해 보기 
CREATE TABLE user_tb(
	id int AUTO_INCREMENT PRIMARY KEY, 
  username VARCHAR(50) not null UNIQUE, 
  password VARCHAR(30) not null, 
  fullname VARCHAR(50) not null, 
  created_at TIMESTAMP not null DEFAULT now()
);

-- 사용자에 계좌 정보 테이블 설계 
CREATE TABLE account_tb(
	id int AUTO_INCREMENT PRIMARY KEY, 
    number VARCHAR(30) not null UNIQUE, 
    password VARCHAR(20) not null, 
    balance BIGINT not null COMMENT '계좌 잔액',
    user_id int, 
    created_at TIMESTAMP not null DEFAULT now()
);

-- 입금 내역 저장 
-- 출금 내역 저장 
-- 사용자간 이체 내역 저장 

-- 사용자들에 history 테이블 설계 
-- BIGINT 8바이트 크기에 정수형 
-- 조(10에 12) -- 경(10에 16승) -- 해(10에20승)
-- 자(10에 24) -- 양(10에 28)
 
 
CREATE TABLE history_tb(
	id int AUTO_INCREMENT PRIMARY key COMMENT '거래 내역 ID', 
	amount BIGINT not null COMMENT '거래 금액',
	w_account_id int COMMENT '출금 계좌 id',
	d_account_id int COMMENT '입금 계좌 id',
	w_balance BIGINT COMMENT '출금 요청된 계좌에 잔액',
	d_balance BIGINT COMMENT '입금 요청된 계좌에 잔액', 
	created_at TIMESTAMP not NULL DEFAULT now() 
);

테이블 설계 및 제약 설정

유저 샘플 데이터 
INSERT INTO user_tb(username, password, fullname, created_at) values('길동', '1234',
'고', now());
INSERT INTO user_tb(username, password, fullname, created_at) values('둘리', '1234',
'애기공룡', now());
INSERT INTO user_tb(username, password, fullname, created_at) values('콜', '1234',
'마이', now());

계좌 테이블 샘플 데이터 
INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('1111', '1234', 900, 1, now());
INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('2222', '1234', 1100, 2, now());
INSERT INTO account_tb(number, password, balance, user_id, created_at)
values('333', '1234', 0, 3, now());

자바 코드로 모델을 하기

User 모델링

package com.tenco.bank.repository.model;

import java.sql.Timestamp;

import lombok.Data;

@Data
public class User {
	private Integer id; 
	private String username; 
	private String password; 
	private String fullname; 
	private Timestamp createdAt;
}

Account 모델링

package com.tenco.bank.repository.model;

import java.sql.Timestamp;

import lombok.Data;

/**
 * 모델 클래스 
 */
@Data
public class Account {
	
	private Integer id;
	private String number; 
	private String password; 
	private Long balance; 
	private Integer userId; 
	private Timestamp createdAt; 
	
	public void withdraw(Long amount) {
		this.balance -= amount;
	}
	
	public void deposit(Long amount) {
		this.balance += amount;
	}
	
	// 패스워드 체크
	// 잔액 여부 확인 (출금시) 
	// 계좌 소유자 확인 
}
package com.tenco.bank.repository.model;

import java.sql.Timestamp;

import lombok.Data;

@Data
public class History {
	
	private Integer id;
	private Long amount;
	private Long wBalance;
	private Long dBalance;
	private Integer wAccountId;
	private Integer dAccountId;
	private Timestamp createdAt;
}

'Spring boot > spring boot 앱 만들어 보기 2 단원' 카테고리의 다른 글

bank app 화면 구현(1)  (0) 2023.04.17
bank app MyBatis 설정  (0) 2023.04.17
bank app - h2 db 초기 값 설정  (0) 2023.04.17
패키지 설정  (0) 2023.04.17
프로젝트 설정  (0) 2023.04.17
패키지 및 폴더 구조 잡기 

1. 정적 자원 관리 
src/main/resources/static ← 정적 자원 루트 폴더이다. 
css 폴더 생성 
images 폴더 생성(서버가 기본적으로 가지고 있어야 하는 앱 아이콘 등) 
js 폴더 생성 

2 개발 시 필요한 패키지 추가 
src/main/resources 
db 패키지 생성 ( .sql 파일 저장 - 초기 데이터 관리 )
mapper 패기지 생성 ( MyBatise 를 사용하기 위한 xml 파일)

3 템플릿 엔진 JSP 사용할 폴더 설정 
src/main/ → webapp 폴더 생성 
WEB-INF 폴더 생성 
view 폴더 생성 
view → layout 폴더, user폴더 , account 폴더 

4 자바 코드를 담을 패키지 설정 

controller 생성 
service 패키지 생성 
dto 패키지 생성 ← 추가 
repository 패키지 생성 
repository → model 패키지 생성 
repository → interfaces 패키지 생성 ( DAO 사용할 표준 - MyBatis mapper 연동 )

네이밍 컨벤션 정해보기

일관성 있는 네이밍 컨벤션을 유지하는 것이 중요 하다. 

정적 파일 : .css, image, xml - 스네이크 케이스 사용 ex)  xx_xx.css, xx_x.js 
jsp 파일 : xxx.jsp - 카멜 케이스 사용 :  ex) home.jsp,  accountPage.jsp 
java 파일 : 파스칼 케이스 사용 : ex) HomeController.java 
폴더 및 패키지 명 : 스네이크 케이스 사용 

HTML 태그 id, name 속성 : 카멜 케이스 사용 ex) userId, 
CSS 클래스명 : 소문자로 —> xxx - - xxx (외부 라이브러리랑 충돌 방지) 

데이터 베이스 
테이블 명 : 소문자 사용 - 스네이크 케이스 사용 tb 붙이기 : user_tb, account_tb 
컬럼명 : 스네이크 케이스 : user_id, 

DTO 클래스 
카멜케이션 사용

 

'Spring boot > spring boot 앱 만들어 보기 2 단원' 카테고리의 다른 글

bank app 화면 구현(1)  (0) 2023.04.17
bank app MyBatis 설정  (0) 2023.04.17
bank app - h2 db 초기 값 설정  (0) 2023.04.17
bank app 모델링  (0) 2023.04.17
프로젝트 설정  (0) 2023.04.17
학습 목표 

1. 세션 활용해 보기 
2. 인증된 사용자 여부를 인터셉터에서 확인하고 페이지 이동 처리 하기 

시나리오 코드 결과물 
클라이언트는 login.html 파일에는 누구나 접근할 수 있는 페이지로 만들기 
클라이언트는 mypage/myinfo.html 파일에는 인증 된 사용자만 접근 하게 만들기 
클라이언트는 mypage/cart.html 파일에는 인증 된 사용자만 접근 하게 만들기

사전 기반 지식

Spring Boot에서 기본적으로 제공하는 세션은 내장형 서버(Tomcat, Jetty 등)를 사용할 때, 
메모리 기반 세션을 사용합니다. 따라서 세션 데이터는 서버의 메모리에 저장됩니다.

내장형 서버의 경우 server.servlet.session.* 프로퍼티를 사용하여 세션 관련 설정을 할 수 있습니다.
예를 들어 다음과 같이 application.properties 파일에서 설정할 수 있습니다.

# 세션 타임아웃 설정 (기본값: 30분)
server.servlet.session.timeout=60

# 세션 쿠키 이름 설정 (기본값: JSESSIONID)
server.servlet.session.cookie.name=MYSESSIONID

# 세션 쿠키 경로 설정 (기본값: /)
server.servlet.session.cookie.path=/

Spring Boot에서 제공하는 세션은 서버의 메모리에 저장되므로, 서버를 재시작하면 세션 데이터가 모두
삭제됩니다. 이러한 한계를 극복하기 위해서는 세션 클러스터링, 분산 캐시 등의 기술을 이용하여 
세션 데이터를 외부 저장소(디스크, 데이터베이스, 분산 캐시 등)에 저장할 수 있습니다.

HttpSession은 서버 메모리에 생성되는 세션 객체이며, 사용자의 요청마다 새로운 HttpSession 객체가 생성됩니다.
이때 Spring Container는 Servlet Container와 함께 사용되어, 
HttpSession 객체에 접근하여 세션 데이터를 저장하거나 가져올 수 있습니다.

시나리오 코드 1

UserController 만들어 보기

package com.example.demo9.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo9.dto.User;

@Controller
public class UserController {

	// 1. 로그인 페이지 직접 URL 요청해서 응답 받을 수 있다. (사전 지식) 
	// 2. 로그인 페이지를 controller를 타서 응답 처리해 보자. 
	@GetMapping("/login-page")
	public String login() {
		return "login.html";
	}
	
	// MIME TYPE - form : x-www-form-urlencoded 
	// @RequestBody <-- application/json
	@PostMapping("/login-proc")
	public String loginProc(HttpServletRequest request,
							HttpServletResponse response, User user) {
		// 로직 : 세션 저장 후 myInfo 페이지 이동 처리 함 
		HttpSession session = request.getSession();
		System.out.println("user : " + user);
		session.setAttribute("user", user);
		//response.sendRedirect("/mypage/myinfo");
		return "redirect:/mypage/myinfo.html";
	}
	
	// myinfo 설계 
	// http://localhost:8080/mypage/myinfo <-- 설계 해야 인터 페이스 동작 됩
	@GetMapping("/mypage/myinfo")
	public String myInfo() {
		// 인증이 필요한 페이지로 만들기로 함
		return "mypage/myinfo.html";
	}
}

static/login.html 파일 생성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>로그인 페이지 입니다.</h1>
	<form action="/login-proc" method="post">
		<input type="text" name="username" value="tenco">
		<br>
		<input type="password" name="password" value="1234">
		<br>
		<input type="submit" value="로그인처리">
	</form>
</body>
</html>

static/mypage/myinfo.html 파일 생성

여기 페이지는 인증된 사용자만 들어 올 수 있도록 설계

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>MyInfo 페이지 입니다</h1>
	<h2>여기는 인증된 사용자만 페이지를 볼 수 있도록 처리 할 예정</h2>
</body>
</html>

static/mypage/cart.html 파일 생성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>cart.html 파일 입니다.</h1>
	<h2>여기에도 인증된 사용자만 들어 올수 있도록 코드 추가</h2>
</body>
</html>
package com.example.demo9.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import com.example.demo9.dto.Cart;
import com.example.demo9.dto.User;

@Controller
public class UserController {

	// 로그인 페이지 직접 URL 요청해서 응답 받을수 있다.
	// 로그인 페이지를 controller 를 타서 응답 처리해보자.
	@GetMapping("/login-page")
	public String login() {

		return "login.html";
	}

	@PostMapping("/login-proc")
	public String loginProc(HttpServletRequest request, HttpServletResponse response, User user) {
		// 로직 : 세션 저장후 myInfo 페이지 이동 처리함
		HttpSession session = request.getSession();
		System.out.println("user : " + user);
		session.setAttribute("user", user);
		return "redirect:/mypage/myinfo.html";
	}
	
	@PostMapping("/cart-proc")
	public String cartProc(HttpServletRequest request, HttpServletResponse response, Cart cart) {
		// 로직 : 세션 세션에 저장된 값을 한번 더 받아와서 인증 처리를 해준후 넘겨준다
		// 세션 값을 저장해두기때문에 한번더 넣을 필요없이 키값으로 저장되어있는 값을 불러와서 
		// 확인 후 넘겨준다
		HttpSession session = request.getSession();
		System.out.println("cart : " + cart);
		session.setAttribute("cart", cart);
		return "redirect:/mypage/cart.html";
	}
	
	// myinfo 설계
	// http://localhost:8080/mypage/myinfo <-- 설계 해야
	@GetMapping("/mypage/myinfo")
	public String myinfo() {
		// 인증이 필요한 페이지로 만들기로 함
		return "mypage/myinfo.html";
	}


}

spring boot 에서 제공하는 interceptor 를 활용하여 인증 처리 로직을 구현

HandlerInterceptor 구현한 AuthInterceptor 클래스 생성하기

package com.example.demo9.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Component // IoC 대상 
public class AuthInterceptor implements HandlerInterceptor {
	
	// myInfo 이동시 세션 여부를 확인 (controller 들어가 전에 가로채기) 
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		HttpSession session = request.getSession();
		// 사용자가 로그인을 하면 세션 메모리 영역에 user 키=값 구조로 저장 처리 할 예정
		Object user = session.getAttribute("user");
		System.out.println("preHandler 동작 확인 ");
		if(user == null) {
			response.sendRedirect("/login-page");
			return false; 
		} 
		return true;
	}
}

우리가 만든 AuthInterceptor 등록할 WebMvcConfig 클래스 생성하기

package com.example.demo9.handler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
	
	@Autowired // DI 처리 
	private AuthInterceptor authInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 야 authInterceptor 동작 시킬 때 모든 페이지를 
		// 너가 가로채면 무조건 리다이렉트 되잖아 !!!
		// 그게 아니라 내가 명시하는 요청 설계 주소에서만 동작 
		// 하도록 일 하겠니!!
		// http:localhost:8080/hello <-- 인터 셉터 동작 하지 않음 
		// http:localhost:8080/mypage/myinfo <-- 인터 셉터 동작 함 
		registry.addInterceptor(authInterceptor)
				.addPathPatterns("/mypage/**");
	}
}

 

'Spring boot' 카테고리의 다른 글

Spring boot - Interceptor - 1  (0) 2023.04.13
스프링 부트 JSP 연결  (0) 2023.04.13
spring boot execption(예외처리)  (0) 2023.04.13
Spring Boot Validation  (0) 2023.04.13
어노테이션 종류  (0) 2023.04.13

+ Recent posts