[Spring] 프로젝트 커뮤니티,블로그 만들기(#5)-회원가입,로그인,로그아웃 구현하기
안녕하세요 무작정 일단 따라 해 보는 Spring 커뮤니티 만들기 5탄 시작합니다.
환경
Eclipse 2019-9 Jee
JDK 1.8_231
Apache Tomcat 8.5.47
MariaDB 10.4.10
MyBatis 3.2.2
JSTL 1.2
jackson 2.9.4
오늘의 할 일
1.유저(user) 테이블 만들기
2.유저(user) 회원가입,로그인 view 만들기
3.유저(user) 회원가입,로그인 백 로직 만들기(값 req,res DB insert)
1.유저(members) 테이블 만들기
제일 먼저 회원가입 기능을 만드려면 DB 테이블을 먼저 만들어야겠죠
저희는 MariaDB 10.4 버전을 사용하고 있기때문에
또 HeidiSQL 들어가줍니다들어가 줍니다.이제 사용법 아시죠?!
CREATE TABLE `members` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`userId` VARCHAR(64) NULL DEFAULT NULL,
`password` VARCHAR(256) NULL DEFAULT NULL,
`nickname` VARCHAR(64) NULL DEFAULT NULL,
`email` VARCHAR(64) NULL DEFAULT NULL,
`authority` INT(11) NULL DEFAULT NULL,
`declaration` INT(11) NULL DEFAULT NULL,
`last_login` TIMESTAMP NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
`create_time` TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
`update_time` TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
UNIQUE INDEX `userId` (`userId`)
)
id : 절대 겹치지 않는 구분자 PK
userId : 유저 아이디
password : 유저 비밀번호
nickname : 유저 닉네임
email : 유저 이메일
authority : 권한(관리자, 사용자 등..)
declaration : 신고 횟수
last_login : 마지막 로그인 시간
create_time : 유저 생성한 시간(회원 가입한 시간)
update_time : 비밀번호 업데이트한 시간(n일마다 비밀번호 교체 요구 기능 만들 예정)
UNIQUE INDEX `userId` (`userId`) : 웹 로직을 피해 DB에 데이터를 넣을 경우라도 중복은 피할 수 있게 유니크 키를 넣어줍니다.
최종 members 테이블
10.4 UI는 참 이쁘네요 10.2에 비해..
2.유저(members) 회원가입,로그인 view 만들기
views -> user 폴더 생성
views -> user 폴더 -> login.jsp 생성
src/main/java -> controller -> UserController.java 생성
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("user/*")
public class UserController {
@RequestMapping(value="user/login",method = RequestMethod.GET)
public ModelAndView login() {
ModelAndView mav = new ModelAndView();
return mav;
}
}
webapp -> index.jsp 수정
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:forward page="/user/login"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SpringEx01 커뮤니티</title>
</head>
<body>
</body>
</html>
나중에 sitemash를 사용할 때 index.jsp는 적용하기 어렵습니다. 그러므로 jsp:forward를 통해 진입하자마자
/user/login 페이지로 forward 해줍니다.
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<style>
body {
font: 13px/20px 'Helvetica Neue', Helvetica, Arial, sans-serif;
color: #333333;
background: #596778;
}
.signUp {
position: relative;
margin: 50px auto;
width: 280px;
padding: 33px 25px 29px;
background: #FFFFFF;
border-bottom: 1px solid #C4C4C4;
border-radius: 5px;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
}
.signUp:before,
.signUp:after {
content: '';
position: absolute;
bottom: 1px;
left: 0;
right: 0;
height: 10px;
background: inherit;
border-bottom: 1px solid #D2D2D2;
border-radius: 4px;
}
.signUp:after {
bottom: 3px;
border-color: #DCDCDC;
}
.signUpTitle {
margin: -25px -25px 25px;
padding: 15px 25px;
line-height: 35px;
font-size: 26px;
font-weight: 300;
color: #777;
text-align: center;
text-shadow: 0 1px rgba(255, 255, 255, 0.75);
background: #F7F7F7;
}
.signUpTitle:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8px;
background: #C4E17F;
border-radius: 5px 5px 0 0;
background-image: -webkit-linear-gradient(left, #C4E17F, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #db9CBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
background-image: -moz-linear-gradient(left, #c4e17f, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9CBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
background-image: -o-linear-gradient(left, #C4E17F, #C4E17F 12.5%, #F7FDCC 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9DBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
background-image: linear-gradient(to right, #C4E17F, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9CBE 62.5%, #c49cde 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62c2e4 87.5%, #62C2E4);
}
input {
font-family: inherit;
color: inherit;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.signUpInput {
width: 100%;
height: 50px;
margin-bottom: 25px;
padding: 0 15px 2px;
font-size: 17px;
background: white;
border: 2px solid #EBEBEB;
border-radius: 4px;
-webkit-box-shadow: inset 0 -2px #EBEBEB;
box-shadow: inset 0 -2px #EBEBEB;
}
.signUpInput:focus {
border-color: #62C2E4;
outline: none;
-webkit-box-shadow: inset 0 -2px #62C2E4;
box-shadow: inset 0 -2px #62C2E4;
}
.lt-ie9 .signUpInput {
line-height: 48px;
}
.loginButton {
position: relative;
vertical-align: top;
width: 100%;
height: 54px;
padding: 0;
font-size: 22px;
color: white;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
background: #CCCCFF;
border: 0;
border-bottom: 2px solid #D76B60;
border-radius: 5px;
cursor: pointer;
-webkit-box-shadow: inset 0 -2px #D76B60;
box-shadow: inset 0 -2px #D76B60;
}
.loginButton:active {
top: 1px;
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.signUpButton {
position: relative;
vertical-align: top;
width: 100%;
height: 54px;
padding: 0;
font-size: 18px;
color: white;
text-align: center;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
background: #F0776C;
border: 0;
border-bottom: 2px solid #D76B60;
border-radius: 5px;
cursor: pointer;
-webkit-box-shadow: inset 0 -2px #D76B60;
box-shadow: inset 0 -2px #D76B60;
}
.signUpButton:active {
top: 1px;
outline: none;
-webkit-box-shadow: none;
box-shadow: none;
}
:-moz-placeholder {
color: #AAAAAA;
font-weight: 300;
}
::-moz-placeholder {
color: #AAAAAA;
opacity: 1;
font-weight: 300;
}
::-webkit-input-placeholder {
color: #AAAAAA;
font-weight: 300;
}
:-ms-input-placeholder {
color: #AAAAAA;
font-weight: 300;
}
::-moz-focus-inner {
border: 0;
padding: 0;
}
</style>
<script type="text/javascript">
function loginValidation(){
var userId = $("#userId").val();
var password = $("#password").val();
if(!userId){
alert("아이디를 입력하세요.");
$("#userId").focus();
return false;
}else if(!password){
alert("비밀번호를 입력하세요.");
$("#password").focus();
return false;
}else {
login(userId,password);
}
}
function login(userId,password){
$.ajax({
url : "/jquery/login",
type : 'POST',
data : { userId : userId,
password : password
},
success:function(data){
if(data == 2){
alert("아이디 혹은 비밀번호가 맞지 않습니다.");
return false;
}else if(data == 3){
location.href="/view/dashboard";
}
}
})
}
function enterKeyCheck(){
if(event.keyCode == 13)
{
loginValidation();
}
}
</script>
</head>
<body>
<form class="signUp" id="signupForm">
<h1 class="signUpTitle">로그인</h1>
<input type="text" id="userId" class="signUpInput" placeholder="ID" autofocus onkeyup="enterKeyCheck()">
<input type="password" id="password" class="signUpInput" placeholder="Password" onkeyup="enterKeyCheck()">
<input type="button" value="로그인" onclick="loginValidation()" class="loginButton">
<input type="button" value="회원가입" onclick="location.href='/user/signUp'" class="signUpButton">
</form>
</body>
</html>
UI 코드 출처 : 블루비 웹스토어
views -> user 폴더 -> signUp.jsp 생성
signUp.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<meta charset="UTF-8">
<title>회원 가입</title>
<script type="text/javascript">
function signUpValidation(){
var userId = $("#userId").val();
var userPw = $("#password").val();
var userPwCheck = $("#passwordCheck").val();
var nickName = $("#nickname").val();
var email = $("#email").val();
if(!userId){
alert("아이디 입력은 필수입니다.");
$("#userId").focus();
}else if(!userPw){
alert("비밀번호 입력은 필수입니다.");
$("#password").focus();
}else if(!userPwCheck){
alert("비밀번호 확인 입력은 필수입니다.");
$("#passwordCheck").focus();
}else if(userPw != userPwCheck){
alert("비밀번호가 맞지 않습니다.");
$("#userPwCheck").focus();
}else if(!nickName){
alert("닉네임 입력은 필수입니다.");
$("#nickname").focus();
}else if(!email){
alert("이메일 입력은 필수입니다.");
$("#email").focus();
}else {
signUp()
}
}
function signUp(){
$.ajax({
url : "/jquery/signUp",
type:'POST',
data : $("#registerform").serialize(),
success:function(data){
if(data == 1){
alert("회원가입이 완료됐습니다.^^");
location.href = "/user/login"
}else if(data == 2){
alert("이미 존재하는 아이디입니다.");
return false;
}else if(data == 3){
alert("이미 존재하는 닉네임입니다.");
return false;
}
}
})
}
</script>
</head>
<body style="background-color:#f0f5f3">
<form id="registerform">
<div class="fieldlabel"><label for="userId">*아이디</label></div>
<div class="formfield"><input type="text" id="userId" name="userId" maxlength="20" value=""></div>
<div class="fieldlabel"><label for="password">*패스워드</label></div>
<div class="formfield">
<input type="password" id="password" name="password" maxlength="20" autocomplete="off">
</div>
<div class="fieldlabel"><label for="passwordCheck">패스워드확인</label></div>
<div class="formfield">
<input type="password" id="passwordCheck" name="passwordCheck" maxlength="20" autocomplete="off">
</div>
<div class="fieldlabel"><label for="nickname">*닉네임</label></div>
<div class="formfield"><input type="text" id="nickname" name="nickname" maxlength="20" value=""></div>
<div class="fieldlabel"><label for="email">*이메일</label></div>
<div class="formfield"><input type="text" id="email" name="email" size="20" maxlength="20"
value="" autocomplete="off"><span>@</span>
<input id="domain" list="domains" name="domain" placeholder="도메인입력/선택">
<datalist id="domains">
<option value="naver.com">
<option value="daum.net">
<option value="gmail.com">
<option value="yahoo.co.kr">
</datalist>
</div>
<div class="btnfield">
<input type="button" onclick="signUpValidation()" value="회원가입">
</div>
</form>
</body>
</html>
3.유저(members) 회원가입,로그인 백 로직 만들기
src/main/java -> controller -> UserController.java 수정
UserController.java
package com.company01.springEx01.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
@RequestMapping("user/*")
public class UserController {
@RequestMapping(value="user/login",method = RequestMethod.GET)
public ModelAndView login() {
ModelAndView mav = new ModelAndView();
return mav;
}
@RequestMapping(value="user/signUp",method = RequestMethod.GET)
public ModelAndView signUp() {
ModelAndView mav = new ModelAndView();
return mav;
}
}
src/main/java -> controller -> JqueryController.java 수정
JqueryController.java
package com.company01.springEx01.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.company01.springEx01.logic.Board;
import com.company01.springEx01.logic.Members;
import com.company01.springEx01.service.BoardService;
import com.company01.springEx01.service.UserService;
@Controller
@RequestMapping("jquery/*")
public class JqueryController {
@Autowired
BoardService boardService;
@Autowired
UserService userService;
@RequestMapping(value="jquery/boardwrite",method = RequestMethod.POST)
@ResponseBody
public int boardwrite(Board board) {
int result = 0;
result = boardService.boardwrite(board);
return result;
}
@RequestMapping("jquery/logout")
public String logout(HttpSession session) {
session.removeAttribute("loginUser");
return "/user/login";
}
@RequestMapping(value="jquery/login",method = RequestMethod.POST)
@ResponseBody
public int login(Members members,HttpSession session) {
int result = 0;
String col = null;
col = "userId";
Members userIdCheck = userService.getUserOne(members.getUserId(),col);
if(userIdCheck == null) {
result = 2;
}else {
if(members.getUserId().equals(userIdCheck.getUserId())) {
//ID OK
if(members.getPassword().equals(userIdCheck.getPassword())) {
//PW OK
session.setAttribute("loginUser", userIdCheck);
result = 3;
}else {
result = 2;
}
}else {
//ID not OK
result = 2;
}
}
return result;
}
@RequestMapping(value="jquery/signUp",method = RequestMethod.POST)
@ResponseBody
public int signUp(Members members) {
int result = 0;
String col = null;
col = "userId";
Members userIdCheck = userService.getUserOne(members.getUserId(),col);
if(userIdCheck != null) {
result = 2;
}
col = "nickname";
Members userNicknameCheck = userService.getUserOne(members.getNickname(),col);
if(userNicknameCheck != null) { result = 3; }
if(result < 2) {
result = userService.userJoin(members);
}
return result;
}
}
login method
Members userIdCheck = userService.getUserOne(members.getUserId(),col);
아이디가 존재하는지 입력값을 보내 DB에서 검사합니다.
존재할 경우
if(members.getUserId().equals(userIdCheck.getUserId())) { 아이디와 DB에 데이터 아이디와 같은지 확인
//ID OK
if(members.getPassword().equals(userIdCheck.getPassword())) { 비밀번호와 DB에 데이터 비밀번호가 같은지 확인
session.setAttribute("loginUser", userIdCheck); "세션"이라는 것에 로그인한 사용자의 정보를 담음
src/main/java -> services -> UserService.java (interface) 생성
UserService.java (interface)
package com.company01.springEx01.service;
import com.company01.springEx01.logic.Members;
public interface UserService {
Members getUserOne(String common, String col);
int userJoin(Members members);
}
src/main/java -> services -> UserServiceImpl.java 생성
UserServiceImpl.java
package com.company01.springEx01.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.company01.springEx01.dao.UserDAO;
import com.company01.springEx01.logic.Members;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDAO userDAO;
@Override
public Members getUserOne(String common,String col) {
return userDAO.getUserOne(common,col);
}
@Override
public int userJoin(Members members) {
return userDAO.userJoin(members);
}
}
src/main/java -> dao-> UserDAO.java
UserDAO.java
package com.company01.springEx01.dao;
import java.util.HashMap;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.company01.springEx01.logic.Members;
@Repository
public class UserDAO {
@Autowired
public SqlSession sqlSession;
public Members getUserOne(String common, String col) {
HashMap<String, Object> map = new HashMap<String, Object>();
if(col.equals("userId")) {
map.put("userId",common);
}else if(col.equals("nickname")) {
map.put("nickname",common);
}
return sqlSession.selectOne("getUserOne",map);
}
public int userJoin(Members members) {
return sqlSession.insert("userJoin",members);
}
}
src/main/java -> logic -> Members.java
Members.java
package com.company01.springEx01.logic;
import java.util.Date;
public class Members {
private int id;
private String userId;
private String password;
private String nickname;
private String email;
private int authority;
private int declaration;
private Date last_login;
private Date create_time;
private Date update_time;
private String domain;
get../set..
}
혹시 get/set 설정 모르시는 분들을 위한 설명
get/set 만들 클래스를 열은 상태에서 -> 이클립스에서 상단 메뉴 Source -> Generate and Setters... 클릭
Select All 버튼 클릭 -> Generate
src/main/resources -> mapper 폴더 -> user-Mapper.xml 생성
user-Mapper.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="mapper.user-Mapper">
<select id="getUserOne" resultType="members">
SELECT * FROM members
<if test="userId != null">
where userId = #{userId};
</if>
<if test="nickname != null">
where nickname = #{nickname};
</if>
</select>
<insert id="userJoin">
insert into members (id,userId,password,nickname,email,authority,last_login,create_time,update_time)
values (#{id},#{userId},#{password},#{nickname},#{email},1,#{last_login},now(),#{update_time})
</insert>
</mapper>
spring -> mybatis 폴더 -> mybatis-config.xml 수정
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<typeAlias alias="board" type="com.company01.springEx01.logic.Board"/>
<typeAlias alias="members" type="com.company01.springEx01.logic.Members"/>
</typeAliases>
<mappers>
<mapper resource="mapper/board-Mapper.xml"/>
<mapper resource="mapper/user-Mapper.xml"/>
</mappers>
</configuration>
views -> view -> dashboard.jsp 수정
dashboard.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/jstlHeader.jsp" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>dashboard</title>
<style>
table {
width: 100%;
border: 1px solid #444444;
}
th, td {
border: 1px solid #444444;
}
</style>
</head>
<body>
<p>환영합니다 ${sessionScope.loginUser.nickname }님 <a href="/jquery/logout">로그아웃</a></p>
<p>dashboard</p>
<div>게시글 리스트</div>
<table>
<thead><tr>
<td>제목</td>
<td>조회수</td>
<td>좋아요</td>
<td>첨부파일</td>
<td>글 작성 날짜</td>
</tr></thead>
<c:forEach var="b" items="${result }">
<fmt:formatDate value="${b.create_time}" pattern="yyyy-MM-dd HH:MM:ss" var="dateFormat_cr"/>
<tr>
<td><a href="/view/boardDetail?id=${b.id }">${b.subject }</a></td>
<td>${b.views }</td>
<td>${b.likes }</td>
<td>${b.attachments }</td>
<td>${dateFormat_cr }</td>
</tr>
</c:forEach>
</table>
<div> <a href="/view/boardwrite">글 작성하기</a></div>
</body>
</html>
${sessionScope.loginUser.nickname} "세션"에 담긴 닉네임 정보가 잘 나왔나 확인하는 작업
정리
1.signUp.jsp - 회원가입 페이지 뷰
-signUp Method POST 회원가입 사용자 등록 메서드
2.login - 로그인 페이지 뷰
-login Method POST 로그인 성공/실패 여부
3.logout Method - 세션에 담긴 로그인 정보를 삭제함으로써 로그아웃 기능을 제공함.
이제 감 잡으신 분들도 있겠지만 이 방식만 외우세요!
1.jsp 데이터 넘기거나 조회 (request or response)
2.Controller에서 받음
3.Controller에서 Service에게 요청
4.ServiceImpl이 받음
5.DAO가 받음
6.DAO가 DB에게 데이터 요청
7. 다시 리턴~jsp까지 전달
8. 설정은 XML 파일이 한다. 인식해주는 것, 새로운 것을 등록하는 것, 뭔가 바꿔주는 것
어떠한 기능이든 이 방식을 따릅니다. 그 과정이 복잡해지는 거지 그 방식은 똑같습니다.
페이지 뷰
로그인
회원가입
대시보드(수정)
UI가 뒤죽박죽인 건 나중에 부트스트랩+sitemash을 이용해 다시 작업할 것입니다.
다음 글은 로그인을 만들었으니 게시판 글쓴이,신고 등 유저+게시판을 이용한 작업을 진행하겠습니다.
최종 Project Explorer
이제 길어져서 한 번에 못 찍네요...
'Spring > 커뮤니티(블로그) 프로젝트' 카테고리의 다른 글
[Spring] 프로젝트 커뮤니티,블로그 만들기(#4)-게시판 작성,수정,삭제(CRUD) 만들기 (1) | 2019.11.30 |
---|---|
[Spring] 프로젝트 커뮤니티,블로그 만들기(#3)-DB 연결+MyBatis 설정하기 (1) | 2019.11.24 |
[Spring] 프로젝트 커뮤니티,블로그 만들기(#2)-package 생성 및 설정 (Feat.Controller,Service,DAO) (4) | 2019.11.17 |
[Spring] 프로젝트 커뮤니티,블로그 만들기(#1)-프로젝트 생성 및 톰캣 설정,인코딩 설정 (0) | 2019.11.17 |