회원가입
1. 회원가입 이동처리
1) 링크 수정
- home.jsp 파일의 링크 수정
<a href="/user/register"><h3 class="box-title">회원가입</h3></a>
- header.jsp 파일의 링크를 수정
<li role="presentation"><a href="/user/register">회원가입</a></li>
- 회원 관련 요청을 처리해 줄 Controller를 기본 패키지에 생성하고 member/register 요청을 처리해 줄 메소드를 생성
package com.gmail.hi;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class UserController {
@RequestMapping(value = "user/register", method = RequestMethod.GET)
public void register(Model model) {
}
}
- views 디렉토리에 user 디렉토리를 생성하고 register.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@include file="../include/header.jsp"%>
<section class="content">
<!-- 회원가입 -->
<form id="registerform" enctype="multipart/form-data" method="post">
<p align="center">
<table border="1" width="50%" height="80%" align='center'>
<tr>
<td colspan="3" align="center"><h2>회원 가입</h2></td>
</tr>
<tr>
<td rowspan="5" align="center">
<p></p> <img id="img" width="100" height="100" border="1" /> <br />
<br /> <input type='file' id="image" name="image"
accept=".jpg,.jpeg,.gif,.png" /><br />
</td>
</tr>
<tr>
<td bgcolor="#f5f5f5"><font size="2"> 이메일</font></td>
<td> <input type="email" name="email"
id="email" size="30" maxlength=50 required="required" />
</td>
</tr>
<tr>
<td bgcolor="#f5f5f5"><font size="2"> 비밀번호</font></td>
<td> <input type="password" name="pw" id="pw"
size="20" required="required" />
</td>
</tr>
<tr>
<td bgcolor="#f5f5f5"><font size="2"> 비밀번호
확인</font></td>
<td> <input type="password" id="pwconfirm"
size="20" required="required" />
</td>
</tr>
<tr>
<td width="17%" bgcolor="#f5f5f5"><font size="2"> 닉네임</font></td>
<td> <input type="text" name="nickname"
id="nickname" size="20" pattern="([a-z, A-Z, 가힣]){2,}"
required="required" title="닉네임은 문자 2자 이상입니다." />
</td>
</tr>
<tr>
<td align="center" colspan="3">
<p></p> <input type="submit" value="회원가입" class="btn btn-warning" />
<input type="button" value="메인으로" class="btn btn-success"
onclick="javascript:window.location='/'">
<p></p>
</td>
</tr>
</table>
</form>
<br /> <br />
</section>
<%@include file="../include/footer.jsp"%>
2.이미지 미리보기
- register.jsp에 이미지 미리보기를 위한 스크립트 추가
<script>
var filename = ''
// change 이벤트가 발생하면 readURL 호출
// change - 내용이 변경되면 호출되는 이벤트
document.getElementById("image").addEventListener('change', function(e) {
if (this.files && this.files[0]) {
filename = this.files[0].name;
var reader = new FileReader();
reader.onload = function(e) {
document.getElementById('img').src = e.target.result;
}
reader.readAsDataURL(this.files[0]);
}
});
</script>
3. 이메일 중복 검사
- 기본키의 값을 입력받는 경우 중복체크를 수행해야 함
- 아이디나 이메일을 기본키로 설정하는 경우 포커스가 없어질 때 이벤트와 ajax를 이용해서 중복체크를 수행
- 중복체크를 ajax를 이용하지 않게 되면 중복된 데이터를 입력했을 때 결과를 전송 한 후 돌아와야 하므로 이전 데이터를 다시 입력해야 하는 경우도 발생하고 페이지 이동에 따른 과부하가 발생할 가능성이 생김
Ajax 나 WebSocket을 이용해서 서버로부터 데이터를 받아와서 출력하는 형식의 웹 애플리케이션을 많이 개발함
user.xml 파일에 아이디 중복 체크를 위한 sql을 작성
<!-- email 중복 검사를 위한 sql -->
<select id="emailcheck" resultType="java.lang.String" parameterType="java.lang.String">
select email
from springuser
where email = #{email}
</select>
- SpringUser 테이블 작업을 위한 UserDao 클래스를 기본 패키지에 dao패키지를 생성하고 아이디 중복 검사를 위한 메소드를 구현
package com.gmail.hi.dao;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
@Autowired
private SqlSession sqlSession;
public String emailcheck(String email) {
return sqlSession.selectOne("user.emailcheck", email);
}
}
- 회원 관련 작업을 처리해주는 메소드의 원형을 소유한 UserService 인터페이스를 기본 패키지 안에 생성하고 아이디 중복 검사를 위한 메소드를 선언
package com.gmail.hi;
public interface UserService {
public String emailcheck(String email);
}
- 회원 관련 작업을 처리해주는 메소드를 구현한 UserServiceImpl 클래스를 service 패키지에 만들고 아이디 중복 검사를 위한 메소드를 구현
package com.gmail.hi.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.gmail.hi.UserService;
import com.gmail.hi.dao.UserDao;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Override
public String emailcheck(String email) {
return userDao.emailcheck(email);
}
}
- Controller에서 처리한 결과를 json으로 출력하기 위한 의존성 라이브러리를 pom.xml 파일에 추가
<!-- Controller에서 json으로 처리 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
jackson 버전이 안맞아서 아래와 같은 Error 발생한다.
해결방법은 jackson 라이브러리를 최신버전으로 변경하였다 (2.5.4 -> 2.9.7)
org.springframework.beans.BeanInstantiationException: Failed to instantiate
[org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter]: Constructor threw exception;
nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
- 클라이언트의 요청을 받아서 결과를 JSON으로 리턴해 줄 수 있는 JSONController 클래스를 생성하고 아이디 중복체크를 처리하기 위한 메소드를 구현
package com.gmail.hi;
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JSONController {
@Autowired
private UserService userService;
@RequestMapping(value = "user/emailcheck", method = RequestMethod.GET)
public Map<String, Object> emailcheck(String email) {
Map<String, Object> map = new HashMap<String, Object>();
String result = userService.emailcheck(email);
map.put("result", result == null);
return map;
}
}
- register.jsp 파일의 이메일 입력란 뒤에 메시지를 출력할 div를 생성
<div id="emailDiv"></div>
- register.jsp 파일에 아이디 중복 검사를 위한 스크립트 코드를 추가
var emailcheck = false;
document.getElementById("email").addEventListener("blur",function() {
var addr = "emailcheck";
var email = document.getElementById("email").value;
$.ajax({url : addr, data : {'email' : email}, dataType : "json", success : function(data) {
if (data.result == true) {
document.getElementById("emailDiv").innerHTML = "사용 가능한 아이디입니다.";
document.getElementById("emailDiv").style.color = 'blue';
emailcheck = true;
} else {
document.getElementById("emailDiv").innerHTML = "사용 불가능한 아이디입니다.";
document.getElementById("emailDiv").style.color = 'red';
emailcheck = false
}
}
});
})
4. nickname 중복 검사
- user.xml 파일에 nickname 중복 체크를 위한 sql 을 작성
<!-- nickname 중복 검사를 위한 sql -->
<select id="nicknamecheck" resultType="java.lang.String" parameterType="java.lang.String">
select nickname
from springuser
where nickname = #{nickname}
</select>
- UserDao 클래스에 nickname 중복검사 메소드를 구현
public String nicknamecheck(String nickname) {
return sqlSession.selectOne("user.nicknamecheck", nickname);
}
- UserService 인터페이스에 nickname 중복 검사를 위한 메소드를 선언
public String nicknamecheck(String nickname);
- UserServiceImpl 클래스에 nickname 중복검사 메소드를 구현
@Override
public String nicknamecheck(String nickname) {
return userDao.nicknamecheck(nickname);
}
- JSONController 클래스에 nickname 중복체크를 처리하기 위한 메소드를 구현
@RequestMapping(value = "user/nicknamecheck", method = RequestMethod.GET)
public Map<String, Object> nicknamecheck(@RequestParam("nickname") String nickname) {
Map<String, Object> map = new HashMap<String, Object>();
String result = userService.nicknamecheck(nickname);
map.put("result", result == null);
return map;
}
- register.jsp 파일의 nickname 입력란 뒤에 메시지를 출력할 div를 생성
<div id="nicknameDiv"></div>
- register.jsp 파일에 아이디 중복 검사를 위한 스크립트 코드를 추가
var nicknamecheck = false;
document.getElementById("nickname").addEventListener("focusout",function(){
var nickname = document.getElementById("nickname").value;
$.ajax({url : "nicknamecheck", data : {'nickname':nickname}, dataType : "json", success : function(data) {
if (data.result == true) {
document.getElementById("nicknameDiv").innerHTML = "사용 가능한 nickname 입니다.";
document.getElementById("nicknameDiv").style.color = 'blue';
nicknamecheck = true;
} else {
document.getElementById("nicknameDiv").innerHTML = "사용 불가능한 nickname입니다.";
document.getElementById("nicknameDiv").style.color = 'red';
nicknamecheck = false
}
}
});
})
5. 유효성 검사
- register.jsp 비밀번호 유효성 검사 내역을 출력할 div를 추가
<div id="pwDiv"></div>
- register.jsp 파일에 유효성 검사를 위한 스크립트 코드를 추가
document.getElementById("registerform").addEventListener("submit",function(e){
if(emailcheck == false){
document.getElementById("emailDiv").innerHTML = "이메일 중복검사를 수행하세요!!";
document.getElementById("emailDiv").style.color='red';
document.getElementById("email").focus();
e.preventDefault();
}
if(nicknamecheck == false){
document.getElementById("nicknameDiv").innerHTML = "닉네임 중복검사를 수행하세요!!";
document.getElementById("nicknameDiv").style.color='red';
document.getElementById("nickname").focus();
e.preventDefault();
}
var pw = document.getElementById("pw").value;
var pwconfirm = document.getElementById("pwconfirm").value;
if(pw != pwconfirm){
document.getElementById("pwDiv").innerHTML = "2개의 비밀번호가 다릅니다!!";
document.getElementById("pwDiv").style.color='red';
document.getElementById("pw").focus();
e.preventDefault();
}
var pattern1 = /[0-9]/; // 숫자 var
pattern2 = /[a-zA-Z]/; // 문자 var
pattern3 = /[~!@#$%^&*()_+|<>?:{}]/;// 특수문자
if(!pattern1.test(pw) || !pattern2.test(pw) || !pattern3.test(pw) || pw.length < 8) {
document.getElementById("pwDiv").innerHTML = "비밀번호는 8자리 이상 문자, 숫자, 특수문자로 구성하여야 합니다.";
document.getElementById("pw").focus();
e.preventDefault();
}
})
6. 파일 업로드
서버에서의 처리
- 업로드 폴더 생성
- 업로드 되는 파일의 고유한 이름 생성
- 파일을 저장
파일 업로드 처리를 위한 기본 설정
- commons-fileupload 의존성 추가
- CommonsMultipartResolver 빈을 추가
- MultipartFile을 이용해서 파일을 받아서 업로드
pom.xml에 commons-fileupload 의존성 추가
<!-- file upload 의존성 추가 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
- servlet-context.xml 파일에 CommonsMultipartResolver 빈 생성 코드 추가
<beans:bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<beans:property value="10485760" name="maxUploadSize" />
</beans:bean>
7. 암호화
비밀번호는 암호화 해서 저장하고 비교해야 합니다.
암호화는 많은 자바라이브러리들이 기능을 제공합니다.
mavenrespository.com에서 jbcrypt를 검색해서 의존성 추가
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.4</version>
</dependency>
- 암호화
String 변경되서 저장되는 문자열= Bcrypt.hashpw(변경할 문자열, BCrypt.gensalt());
- 암호화된 데이터 체크
boolean isValemailPassword = BCrypt.checkpw(비교할 문자열1, 비교할 문자열2);
8. 회원가입
pom.xml 파일에 파일 업로드와 암호화를 위한 의존성 라이브러리를 추가
servlet-context.xml 파일에 파일 업로드 처리를 위한 MultipartResolver 설정을 추가
- user.xml 파일에 회원가입을 처리해 줄 sql을 생성
<!-- 회원가입을 처리 해 줄 sql -->
<insert id="register" parameterType="User">
insert into springuser(email, pw, nickname, image)
values(#{email}, #{pw}, #{nickname}, #{image})
</insert>
- UserDao 클래스에 회원가입을 처리해 줄 메소드를 생성
public int register(User user) {
return sqlSession.insert("user.register", user);
}
- 회원가입을 처리하는 UserService 인터페이스에 메소드 선언
public int register(MultipartHttpServletRequest request);
- 회원가입을 처리하는 메소드를 UserServiceImpl 클래스에 구현
@Override
public int register(MultipartHttpServletRequest request) {
int result = 0;
String email = request.getParameter("email");
String pw = request.getParameter("pw");
String nickname = request.getParameter("nickname");
MultipartFile image = request.getFile("image");
String uploadPath = request.getServletContext().getRealPath("/userimage");
// 파일 이름 만들기
UUID uemail = UUID.randomUUID();
String filename = image.getOriginalFilename();
User user = new User();
try {
if (filename.length() > 0) {
filename = uemail + "_" + filename;
// 저장된 파일 경로 만들기
String filepath = uploadPath + "\\" + filename;
// 파일 업로드
File file = new File(filepath);
image.transferTo(file);
} else {
filename = "default.png";
}
user.setImage(filename);
user.setEmail(email);
user.setPw(BCrypt.hashpw(pw, BCrypt.gensalt(10)));
user.setNickname(nickname);
System.out.println(user);
result = userDao.register(user);
} catch (Exception e) {
System.out.println(e.getMessage());
}
return result;
}
- 회원가입을 처리하는 메소드를 UserController에 작성
@Autowired
private UserService userService;
@RequestMapping(value = "user/register", method = RequestMethod.POST)
public String registerPost(MultipartHttpServletRequest request, RedirectAttributes rttr) {
int result = userService.register(request);
System.out.print("result:" + result);
if (result > 0) {
rttr.addFlashAttribute("insert", "success");
return "redirect:/";
} else {
return "redirect:register";
}
}
- home.jsp에 회원가입 성공을 알리는 대화상자 출력을 위한 코드 추가
<c:if test="${insert != null }">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function() {
$("#dialog-confirm").dialog({
resizable : false,
height : "auto",
width : 400,
modal : true,
buttons : {"닫기" : function() {
$(this).dialog("close");
},
}
});
});
</script>
</c:if>
<div id="dialog-confirm" title="회원가입" style="display: none">
<p>
<span class="ui-icon ui-icon-alert" style="float: left; margin: 12px 12px 20px 0;"></span>
회원가입에 성공하셨습니다.이제 로그인하고 사용하시면 됩니다.
</p>
</div>
- webapp 디렉토리에 회원 이미지를 저장할 userimage 디렉토리를 생성 하고 default.png 파일을 만들고 실행