본문 바로가기

프로젝트

[SpringBoot] 경매사이트 만들기 - 회원가입 및 로그인(시큐리티 적용1)

이번 포스팅은!!

스프링 시큐리티를 이용한 회원가입 및 로그인을 포스팅 하려고한다.

 

1. 수정사항

2. 회원가입 페이지 구현

3. 로그인 페이지 구현

4. 시큐리티 적용해서 회원가입 로그인해보기!

 

순서는 이렇게 진행할 생각이다 ㅎㅎ

 

그전에 먼저 수정사항부터 짚고 넘어가자.

 

● ERD 수정!

3차 수정인가?

회원, 권한, 찜 테이블을 수정했다.

회원 테이블 : 닉네임을 기본키로 하는것보다 시퀀스로 하는게 관리하기에 더 효율적이라고 생각했음.( 닉네임과 이메일은 유니크키로 중복없게 만듦.)

권한, 찜 테이블 : 이전에 MyBatis를 사용할땐 기본키를 복합키로 줬었는데,, 알아보니 JPA에선

첫번째로 별 관계는 부모 테이블의 기본 키를 자식 테이블로 전파하면서 자식 테이블의 기본 키 컬럼이 점점 늘어난다.

두번째로 식별 관계는 2개 이상의 컬럼을 합해서 복합 기본 키를 만들어야 하는 경우가 많다.

세번째로 식별 관계를 사용할 때 기본 키로 비즈니스 의미가 있는 자연 키 컬럼을 조합하는 경우가 많다.

이런 관계로 불리하다고 한다.. 개인적으론 클래스를 두개 만드는거 부터가 불편하긴함;

 

 

● 엔티티 클래스 수정!

본인은 오라클을 사용하는데 이전 포스팅에서 넘버링 전략으로 시퀀스를 사용한다고 말한적있다. 그리고 시퀀스를 사용하기 위한 어노테이션으로 @GeneratedValue(strategy = GenerationType.SEQUENCE) 를 말했는데 추가해야할 부분이있다. 그림으로 보자!

Member

그림을 보면 알겠지만 시퀀스를 사용하기 위해서 우리가 DDL로 'Create sequence 시퀀스이름' 을 해주는 것처럼 엔티티 클래스에서도 시퀀스 생성을 테이블을 만들때 시퀀스를 생성해줘야 한다.

결론적으로 추가해야할껀!

@SequenceGenerator : 시퀀스 만들게~ 라는 뜻.

name : 기본키에서 전략을 정할때 사용될 이름! 무조건 있어야됨!!

sequenceName : 시퀀스 이름

initiaValue : 시퀀스 시작번호!

allocationSize : 시퀀스 생성될때 마다 증가될 수! (기본값:50, 마이바티스로 따지면 그냥 '시퀀스이름.nextval' 과 같음ㅎㅎ)

 

@GeneratedValue -> genarator : 위에서 만든 SequenceGenerator 의 이름을 넣어줌!

 

 

● 패키지 계층구조!

이건 혹시나해서 올려봄!

 

 

● 에러 핸들링!

서버 쪽에서 로직 처리중 에러가 날 경우 일단 모든 에러를 handle 패키지의 GlobalExceptionHandler 클래스에서 핸들링할 수 있도록했다! 사실 그냥 무슨 에러인지만 반환하는건데,,ㅎㅎ 이부분은 나중에 로직을 짜볼예정임!!!

package org.my.toyproject.handler;

import org.my.toyproject.vo.ResponseVo;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

@ControllerAdvice
@RestController
public class GlobalExceptionHandler {
	
	@ExceptionHandler(Exception.class)
	public ResponseVo<String> handleArgumentException(Exception e) {
		return new ResponseVo<String>(HttpStatus.INTERNAL_SERVER_ERROR.value(), "서버에러요~뿌뿌뿌뿌이~~잉~~~");
	}
}
package org.my.toyproject.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseVo<T> {
	int status;
	T data;
}

@ExceptionHandler: Bean내에서 예외가 발생할때 안에 정의한 예외에 속한다면 해당 메서드에서 처리해줌!

@ControllerAdvice: Cotroller 전역에서 발생하는 모든 예외를 잡아온다!

근데 보다시피 나는 예외 최상위 클래스 (Exception)으로 정의해놨기 때문에 모든 에러는 저기루간다...ㅎㅎ

그리고 처리결과는 ReponseVo를 통해 상태값과, 데이터를 넣고 반환해준다!

 

주의해야할점

음,, 이게 예를들어 " ajax로 회원가입 요청을 했는데 유니크 칼럼중 중복되는게 DB에 존재한다? -> 회원가입 실패! -> ajax응답으로는 개발자가 정한 error쪽으로! " 이렇게 생각할 수도 있는데, 사실 ajax 즉, 클라이언트쪽에선 정상응답으로 가게된다는 사실.(정확한거는 아님!)

이유는 에러핸들링으로 서버쪽 에러를 잡아서 어찌됐든 reponseVo라는 객체로 보내줬기 클라이언트 쪽으로 보내줬기 때문에 정상이라고 생각하는것임! 그래서 이에대한 로직도 필요함!

그림으로 보면 무조건 success로 와진다는 말임!

 


수정했던 사항이랑 이전에 조금 추가한거는 위에 다썼고

이제 로그인과 회원가입에 대해 포스팅하겠다.

 

로그인과 회원가입을 위해서 가장 먼저 필요한건 당연히 뷰다. 뷰를 먼저 만들어보자~

 

● 회원가입!!

헤더부분에 Login, Join 버튼을 만들었다!

상단에 시큐리티 태그립을 이용해서 로그인이 됐는지 안됐는지 판단하고~

아래에서 c:choose로 로그인 했을때 보이는 버튼과 안했을때 보이는 버튼을 다르게 해놨다!

여튼 Join을 들어가게 되면 위에서 설정해놓은 주소(회원가입 페이지)로 들어가게된다!
(${pageContext.request.contextPath} <-- 이거는 상대경로를 위해서 작성!)

 

 

(회원가입 페이지)

회원가입 화면!

joinForm.jsp

<form role="form" class="php-email-form">
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="nickName">닉네임</label> 
			<input type="text" id="nickName" class="kdg-join-css" placeholder="NickName" required>
		</p>
	</div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="name">이름</label> 
			<input type="text" id="name" class="kdg-join-css" placeholder="Name" required>
		</p>
    </div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="email">이메일</label> 
			<input type="email" id="email" class="kdg-join-css" placeholder="Email" required>
		</p>
	</div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="passWord">비밀번호</label> 
			<input type="text" id="passWord" class="kdg-join-css" placeholder="PassWord" required>
		</p>
	</div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="phone">핸드폰</label> 
			<input type="number" id="phone" class="kdg-join-css" placeholder="PhoneNumber" required>
		</p>
	</div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="bankName">은행명</label> 
			<input type="text" id="bankName" class="kdg-join-css" placeholder="BankName" required>
		</p>
	</div>
	<div class="form-group mt-3">
		<p style="color: white;" align="left">
			<label for="bankAccount">은행계좌</label> 
			<input type="number" id="bankAccount" class="kdg-join-css" placeholder="BankAccount" required>
		</p>
	</div>
	<div class="my-3">
	</div>
</form>
				
<div class="text-center">
	<button id="joinButton" class="kdg-join-button-css">Join</button>
</div>

조금 조잡하지만 어쩔수 없다 ㅋㅋㅋ 지금은 저게 최선,,,이고 나중에 틀이 다잡히면 회원가입도 여러가지로 구성해볼 예정이다. 여튼 위의 jsp 파일에서 보면 나머지는 다 회원가입 할때 입력하는 부분이고 밑에 버튼을 통해 회원가입이 시작되는걸 볼수 있다! 그럼 id="joinButton"을 누르게 되면 어떻게 되냐? -> ajax를 통해 회원가입을 하게된다.

 

member.js

//member 회원가입
let index={
	init:function(){
		//function(){} 이 아닌 ()=>{} 를 사용하는 이유는 this를 바인딩하기 위함!
		$("#joinButton").on("click",()=>{ 
			this.save();
		});
	},
	
	save:function(){
		let data={
			nick:$("#nickName").val(),
			name:$("#name").val(),
			email:$("#email").val(),
			passWord:$("#passWord").val(),
			phone:$("#phone").val(),
			bankName:$("#bankName").val(),
			bankAccount:$("#bankAccount").val()
		};
		//ajax는 기본이 json으로 통신한다.
		//ajax 호출시 default가 비동기 호출임.
		//ajax통신을 이용해서 데이터를 변경하고 insert 요청 ㄱㄱ.
		//통신 성공하고 서버가 json을 리턴해주면 자동으로 자바객체로 변환해준다는걸 참고하자. 그래서 dataType이 필요없을수도..? 
		$.ajax({
			//요청수행
			type:"post",
			url:"joinProc",//join을 안적는 이유는 어차피 메서드 post라 join거 앎.
			data:JSON.stringify(data),//위의 data는 js객체라 이렇게 json으로 변경해줘야함.(글고 http body데이터임)
			contentType: "application/json; charset=utf-8",//body데이터가 어떤 타입인지(MIME)
			dataType:"json",//응답이 왔을때의 데이터가 json모양이면 js객체로 변환.
			beforeSend : function(xhr, settings) {
				console.log("Before Send");
				console.log(xhr);
				console.log(settings);
			},
			success: function(resp,status){
				//응답 성공일떄
				console.log(status);
				console.log(resp);
				alert("회원가입이 완료되었습니다.");
				location.href="home";
			},
			error: function(resp){
				alert("error");
				console.log(resp);
			}
		});			
	}
}


index.init();

버튼을 누르면 위의 js가 실행된다. 간단하게 보면

버튼 클릭 -> init 함수 실행 -> save함수 실행 -> 입력받은 데이터를 data변수에 넣기 -> ajax 실행으로 이뤄진다!

보내줄 데이터를 JSON.stringify(data) 로해주는 이유는 data는 현재 js객체이고 ajax 송수신은 중간언어인 xml 혹은 json으로만 이뤄지기 때문에 json 타입으로 바꿔서 보내주기 위해서이다.

 

주의할점은

이게 정의된 js파일은 html부분의 body 끝에 넣어주는게 좋다! 왜냐면 브라우저가 html을 읽을때 위에서 부터 차례대로 읽으면서 내려오기 때문에 js를 먼저 읽어버리면 버튼을 클릭해도 js가 실행되지 않는다 ㅠ

 


글이 길어지는거 같아서.. 다음 포스팅에 이어하려고 한다;