💡 학습목표
1. signIn.jsp 파일 확인
2. UserController 로그인 처리 기능 추가
3. UserService 기능 추가
4. UserRepository 메서드 추가
5. user.xml 쿼리 추가
6. header.jsp 메뉴 처리 (jstl 사용)
7. 로그아웃 기능 구현
8. 사용자 정의 예외 클래스 만들기
URL 맵핑 주소 및 POST 선언
&<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!-- header.jsp -->
<%@ include file="/WEB-INF/view/layout/header.jsp"%>
<!-- start main.jsp -->
<div class="col-sm-8">
<h2>로그인 페이지</h2>
<h5>어서오세요 환영합니다.</h5>
<div class="bg-light p-md-5 h-75">
<!-- 로그인은 보안 때문에 예외적으로 POST 방식을 활용한다 -->
<div class="form-group">
<form action="/user/sign-in" method="post">
<div class="form-group">
<label for="username">username</label>
<input class="form-control" type="text" id="username" name="username" placeholder="Enter username">
</div>
<div class="form-group">
<label for="pwd">password</label>
<input class="form-control" type="password" id="pwd" name="password" placeholder="Enter password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- end main.jsp -->
<!-- footer.jsp -->
<%@ include file="/WEB-INF/view/layout/footer.jsp"%>
package com.tencoding.bank.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.tencoding.bank.dto.SignInFormDto;
import com.tencoding.bank.dto.SignUpFormDto;
import com.tencoding.bank.handler.exception.CustomRestfulException;
import com.tencoding.bank.repository.model.User;
import com.tencoding.bank.service.UserService;
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired // DI 처리
private UserService userService;
// 회원 가입 페이지 요청
// http://localhost:80/user/sign-up
@Autowired // DI 처리
private HttpSession session;
@GetMapping("/sign-up")
public String signUp() {
return "user/signUp";
}
// 로그인 페이지 요청
// http://localhost:80/user/sign-in
@GetMapping("/sign-in")
public String signIn() {
return "user/signIn";
}
// 회원 가입 처리
// @param signUpFormDto
// @return 리다이렉트 처리 - 로그인 페이지
@PostMapping("/sign-up")
public String signUpProc(SignUpFormDto signUpFormDto) {
// 1. 유효성 검사
if(signUpFormDto.getUsername() == null
|| signUpFormDto.getUsername().isEmpty()) {
throw new CustomRestfulException("username을 입력하세요", HttpStatus.BAD_REQUEST);
}
// 2. 유효성 검사 2
if(signUpFormDto.getPassword() == null
|| signUpFormDto.getPassword().isEmpty()) {
throw new CustomRestfulException("password을 입력하세요", HttpStatus.BAD_REQUEST);
}
// 3. 유효성 검사 3
if(signUpFormDto.getFullname() == null
|| signUpFormDto.getFullname().isEmpty()) {
throw new CustomRestfulException("fullname을 입력하세요", HttpStatus.BAD_REQUEST);
}
// 로직 추가 -- 서비스 호출
userService.signUp(signUpFormDto);
return "redirect:/user/sign-in";
}
/**
* 로그인 로직 처리
* @param signInFormDto
* @return 계좌 리스트 페이지로 리턴
*/
@PostMapping("/sign-in")
public String signInProc(SignInFormDto signInFormDto) {
// 1. 유효성 검사
if(signInFormDto.getUsername() == null
|| signInFormDto.getUsername().isEmpty()) {
throw new CustomRestfulException("username을 입력하세요", HttpStatus.BAD_REQUEST);
}
if(signInFormDto.getPassword() == null
|| signInFormDto.getPassword().isEmpty()) {
throw new CustomRestfulException("password을 입력하세요", HttpStatus.BAD_REQUEST);
}
// 2. 서비스 -> 인증된 사용자 여부 확인
User principal = userService.signIn(signInFormDto);
principal.setPassword(null);
// 3. 쿠키 + 세션
session.setAttribute("principal", principal);
return "redirect:/account/list";
}
}
package com.tencoding.bank.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.tencoding.bank.dto.SignInFormDto;
import com.tencoding.bank.dto.SignUpFormDto;
import com.tencoding.bank.handler.exception.CustomRestfulException;
import com.tencoding.bank.repository.interfaces.UserRepository;
import com.tencoding.bank.repository.model.User;
@Service // IoC 대상 - 싱글톤 패턴
public class UserService{
// DAO - 데이터 베이스 연동
@Autowired
private UserRepository userRepository;
// DI(Dependency Injection) - 가지고 오다
// public UserService(UserRepository userRepository) {
// this.userRepository = userRepository;
// }
// 트랜잭션 사용하는 이유는 정상 처리 commit(반영)
// 정상 처리 되지 않으면 Rollback 처리 됨
@Transactional
public void signUp(SignUpFormDto signUpFormDto) {
int result = userRepository.insert(signUpFormDto);
System.out.println("result : " + result);
if(result != 1) {
throw new CustomRestfulException("회원가입 실패", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
// 로그인 서비스 처리
public User signIn(SignInFormDto signInFormDto) {
User userEntity = userRepository.findByUsernameAndPassword(signInFormDto);
if(userEntity == null) {
throw new CustomRestfulException("아이디 혹은 비밀번호가 틀렸습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
}
return userEntity;
}
}
package com.tencoding.bank.repository.interfaces;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.tencoding.bank.dto.SignInFormDto;
import com.tencoding.bank.dto.SignUpFormDto;
import com.tencoding.bank.repository.model.User;
// ibatis -> 2.4 버전 이후로 MyBatis로 이름 변경 됨
@Mapper // Mapper 반드시 기술을 해주어야 동작한다.
public interface UserRepository {
// 뱅크 앱
// 매개 변수 수정
public int insert(SignUpFormDto signUpFormDto);
public int updateById(User user);
public int deleteById(Integer id);
public User findById(Integer id);
// 관리자 - 회원정보 리스를 보고 싶다면?
public List<User> findAll();
public User findByUsernameAndPassword(SignInFormDto signInFormDto);
}
<?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.tencoding.bank.repository.interfaces.UserRepository">
<select id="findByUsernameAndPassword" resultType="com.tencoding.bank.repository.model.User">
select * from user_tb where username=#{username} and password = #{password}
</select>
<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.tencoding.bank.repository.model.User">
select * from user_tb where id = ${id}
</select>
<select id="findAll" resultType="com.tencoding.bank.repository.model.User">
select * from user_tb
</select>
</mapper>
<c:choose>
<c:when test="조건식"></c:when>
<c:when test="조건식"></c:when>
...
<c:otherwise></c:when>
</c:choose>
header.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap 4 Website Example</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">
</head>
<body>
<div class="jumbotron text-center banner--imge" style="margin-bottom:0">
<h1>Tencoding Bank</h1>
<img alt="banner" src="https://picsum.photos/seed/picsum/200/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="/main-page">Home</a>
</li>
<c:choose>
<c:when test="${principal != null}">
<li class="nav-item">
<a class="nav-link" href="/user/logout">로그아웃</a>
</li>
</c:when>
<c:otherwise>
<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>
</c:otherwise>
</c:choose>
</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>tencoding bank app</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/deposit">입금</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/transfer">이체</a>
</li>
</ul>
<hr class="d-sm-none">
</div>
<!-- end of header.jsp -->
로그아웃 처리
UserController.java
/**
* 로그아웃 처리
* @return redirect - 로그인 페이지로 이동
*/
@GetMapping("/logout")
public String logout() {
session.invalidate();
return "redirect:/user/sign-in";
}
package com.tencoding.bank.handler.exception;
import org.springframework.http.HttpStatus;
import lombok.Getter;
@Getter
public class UnAuthorizedException extends RuntimeException{
private HttpStatus status;
public UnAuthorizedException(String message, HttpStatus status) {
super(message);
this.status = status;
}
}