유저의 정보를 담을 수 있는 Table 생성
CREATE TABLE users(
/*
CREATE TABLE users(
userId VARCHAR2(50) PRIMARY KEY,
userPw VARCHAR2(50) NOT NULL,
userName VARCHAR2(50) not null,
userPhone1 VARCHAR2(50),
userPhone2 VARCHAR2(50),
userEmail VARCHAR2(50),
userEmail2 VARCHAR2(50),
addrBasic VARCHAR2(300),
addrDetail VARCHAR2(300),
addrZipNum VARCHAR2(50),
regDate DATE DEFAULT sysdate);
*/
userId VARCHAR2(50) PRIMARY KEY,
userPw VARCHAR2(50) NOT NULL,
userName VARCHAR2(50) not null,
userPhone1 VARCHAR2(50),
userPhone2 VARCHAR2(50),
userEmail VARCHAR2(50),
userEmail2 VARCHAR2(50),
addrBasic VARCHAR2(300),
addrDetail VARCHAR2(300),
addrZipNum VARCHAR2(50),
regDate DATE DEFAULT sysdate
);
Interface Mapper
Mapper를 실행시키기 위한 Interface
package com.spring.myweb.user.mapper;
import org.apache.ibatis.annotations.Param;
import com.spring.myweb.command.UserVO;
public interface IUserMapper {
// 아이디 중복 확인
int idCheck(String userId);
// 회원 가입
void join(UserVO user);
}
DB와 연동이 잘되었는지 확인하기 위해 insert 테스트만 진행
package com.spring.myweb.user;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.spring.myweb.command.UserVO;
import com.spring.myweb.user.mapper.IUserMapper;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"file:src/main/webapp/WEB-INF/spring/root-context.xml"})
public class UserMapperTest {
@Autowired
private IUserMapper mapper;
@Test
public void insertTest() {
UserVO user = new UserVO();
user.setUserId("moon");
user.setUserPw("abc");
user.setUserName("문");
user.setUserPhone1("02-24389");
user.setUserPhone2("010-1234-1234");
user.setUserEmail("fpdfkej");
user.setUserEmail2("naver.com");
user.setAddrBasic("부산");
user.setAddrDetail("부산진구");
user.setAddrZipNum("23423");
mapper.join(user);
// 삽입 테스트 완료
}
}
회원 가입을 하기 위해 필요한 조건을 jQuery를 통해 진행 후 데이터를 Controller에 보냄
입력한 데이터의 유효성 검증을 Event를 활용하여 진행
비동기 통신을 통해 아이디 중복 검사 진행 로직 수행
주소 api를 활용하는 로직 수행
submit()함수를 활용하여 form태그에 입력된 데이터들을 서버에 보냄
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script>
/*아이디 형식 검사 스크립트*/
var id = document.getElementById("userId");
// 이거 요소 다시 지정
id.onkeyup = function() {
/*자바스크립트의 정규표현식 입니다*/
/*test메서드를 통해 비교하며, 매칭되면 true, 아니면 false반*/
var regex = /^[A-Za-z0-9+]{4,12}$/;
if (regex.test(document.getElementById("userId").value)) {
document.getElementById("userId").style.borderColor = "green";
document.getElementById("msgId").innerHTML = "아이디중복체크는 필수 입니다";
} else {
document.getElementById("userId").style.borderColor = "red";
document.getElementById("msgId").innerHTML = "";
}
} // 아이디 형식 검사 끄읏
/*비밀번호 형식 검사 스크립트*/
var pw = document.getElementById("userPw");
pw.onkeyup = function() {
var regex = /^[A-Za-z0-9+]{8,16}$/;
if (regex.test(document.getElementById("userPw").value)) {
document.getElementById("userPw").style.borderColor = "green";
document.getElementById("msgPw").innerHTML = "사용가능합니다";
} else {
document.getElementById("userPw").style.borderColor = "red";
document.getElementById("msgPw").innerHTML = "";
}
}
/*비밀번호 확인검사*/
var pwConfirm = document.getElementById("pwConfirm");
pwConfirm.onkeyup = function() {
var regex = /^[A-Za-z0-9+]{8,16}$/;
if (document.getElementById("pwConfirm").value == document
.getElementById("userPw").value) {
document.getElementById("pwConfirm").style.borderColor = "green";
document.getElementById("msgPw-c").innerHTML = "비밀번호가 일치합니다";
} else {
document.getElementById("pwConfirm").style.borderColor = "red";
document.getElementById("msgPw-c").innerHTML = "비밀번호 확인란을 확인하세요";
}
}
// 중복 검사
$(function() {
let code = '';
// 이메일 전송 인증번호 저장을 위한 변수
$('#idCheckBtn').click(function() {
console.log("중복 검사 이벤트 발생!");
const id = $('#userId').val();
// 비동기 방식으로 controller와 연동해서 중복 체크
// id값이 비어있을 때 사용
if (id === '') {
alert('아이디는 필수값입니다.');
return;
}
$.ajax({
type : 'POST',
url : '<c:url value ="/user/checkId" />',
data : id,
// 데이터가 하나일 때는 JSON.stringify() 안써도 됨
dataType : 'text',
contentType : 'application/json',
success : function(result) {
if (result === 'checkFail') {
alert("중복된 아이디입니다. 다시 입력해주십시요.");
$('#userId').val('');
$('#userId').focus();
// 다시 입력하도록 집중
} else {
alert('사용가능한 아이디입니다. 회원가입을 진행할 수 있습니다.');
$('#userId').attr('readonly', true);
// 사용가능한 아이디면 더이상 입력할 수 없도록 readonly 추가
$('#msgId').html('사용 가능한 아이디입니다.');
}
},
error : function() {
alert("오류입니다. 관리자에게 문의하세요");
}
}); // end ajax
}); // 아이디 중복 체크 끄읏
$('#mail-check-btn')
.click(
function() {
const email = $('#userEmail1').val()
+ $('#userEmail2').val();
// 완성된 이메일 주소
console.log('완성된 이메일 : ' + email);
$
.ajax({
type : 'get',
url : '<c:url value="/user/mailCheck?email="/>'
+ email,
// 특정 경로로 서버에 요청을 보냄
success : function(result) {
console.log('컨트롤러에서 전달받은 인증번호 : '
+ result);
$('.mail-check-input').attr(
"disabled", false); // 비활성화된 인증번호 창 활성화
// 속성 변경
// controller로 전달받은 값을 code에 넣어줌
// 나중에 인증번호 인증 여부 확인 값
code = result;
alert('인증번호가 전송되었습니다. 확인 후 입력한에 정확하게 입력하세요.');
},
error : function() {
}
}); // end ajax(이메일 전송)
// 인증 번호 비교
// blur -> focus가 벗어나는 경우 발생
$('.mail-check-input')
.blur(
function() {
// 해당 입력창을 벗어나면 이벤트가 발생하게 만듬
const inputCode = $(this).val();
const $resultMsg = $('#mail-check-warn');
if (inputCode === code) {
// 사용자가 입력한 값과 위에서 저장한 인증번호가 같다면
$resultMsg
.html('인증번호가 일치합니다.');
$resultMsg.css('color',
'green');
$('#mail-check-btn').attr(
'disabled', true);
// 이메일 인증 버튼 비활성화(화면에 보이지 않도록)
$('#userEmail1').attr(
'readonly', true);
// $('#userEmail2').attr('readonly', true);
// select 태그라서 readonly 안먹음
$('#userEmail2')
.attr('onFocus',
'this.initialSelect = this.selectedIndex');
$('#userEmail2')
.attr('onChange',
'this.selectedIndex = this.initialSelect');
// 초기값을 사용자가 선택한 값으로 무조건 설정하는 방법(select에서 readonly 대용)
// 2개 같이 작성해야 select 태그 변경 안됨
// 인증번호 인증이 확인되면 해당 input 태그(인증버튼) 없앰
$(this).css('display',
'none');
// 사용자가 더이상 변경하지 못하도록
} else {
$resultMsg
.html('인증번호를 다시 확인해 주세요.');
$resultMsg.css('color',
'red');
}
});
});
$('#registBtn').click(function() {
/* if($('#userId').attr('readonly') && document.getElementById("pwConfirm").value == document
// readonly 속성의 값이 true, false이므로
.getElementById("userPw").value && $('#userName') !== ''){
$('#formObj').submit();
// 해당 form 데이터를 지정한 요소로 보냄
} */
if (!$('#userId').attr('readonly')){
alert('아이디 중복 체크는 필수 입니다.');
return;
}
else if ($('#userPw').val === '' || $('#userPw').val() !== $('#pwConfirm').val()){
alert('비밀번호 규칙을 확인하세요.');
$('#userPw').focus();
return;
}
else if ($('#userName').val === ''){
alert('이름을 작성해주세요.');
return;
}
else{
// 해당 조건이 모두 아니라면 즉, 문제가 없다면
console.log($('#userId').attr('readonly'));
console.log(document.getElementById("pwConfirm").value == document
.getElementById("userPw").value);
console.log($('#userName') !== '');
$('#formObj').submit();
// 해당 form 데이터를 지정한 요소로 보냄
}
});
}); // end jQuery
// 다음 주소 api 사용
function searchAddress() {
new daum.Postcode({
oncomplete: function(data) {
// 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
// 각 주소의 노출 규칙에 따라 주소를 조합한다.
// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
var addr = '';
// 주소 변수
var extraAddr = '';
// 참고항목 변수
//사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
addr = data.roadAddress;
} else { // 사용자가 지번 주소를 선택했을 경우(J)
addr = data.jibunAddress;
}
// 우편번호와 주소 정보를 해당 필드에 넣는다.
document.getElementById('addrZipNum').value = data.zonecode;
document.getElementById('addrBasic').value = addr;
// 커서를 상세주소 필드로 이동한다.
// 내가 지정한 곳에 값을 넣어줌
document.getElementById('addrDetail').focus();
}
}).open();
}
</script>
사용자가 입력한 데이터를 비동기 방식으로 받아와서 처리 진행
// 아이디 중복 확인
@PostMapping("/checkId")
@ResponseBody
// RestController가 아닌 경우에는 @ResponseBody를 붙여야 비동기 통신이 가능
public String check(@RequestBody String id) {
System.out.println("/user/checkId : POST");
System.out.println("아이디 중복 확인 요청 아이디 값 : " + id);
int num = service.idCheck(id);
System.out.println(num);
if (num >= 1) {
return "checkFail";
}
else {
return "checkSuccess";
}
}
// 회원 가입 처리
@PostMapping("/userJoin")
public String Join(UserVO user, RedirectAttributes ra) {
// 커맨드 객체 사용
System.out.println("/user/userJoin : POST");
System.out.println("join요청 유저 값 가져오는지 확인 : " + user.toString());
service.join(user);
ra.addFlashAttribute("msg", "joinSuccess");
// 보낼 경로에 msg라는 이름으로 값을 보냄
return "redirect:/user/userLogin";
// 해당 경로로 재요청
}
Controller가 준 데이터를 실제 DB에 입력
<?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.spring.myweb.user.mapper.IUserMapper">
<!-- 중복 아이디 체크 -->
<select id="idCheck" resultType="int">
SELECT count(*) FROM users
WHERE userId = #{userId}
</select>
<insert id = "join">
INSERT INTO users(userId, userPw, userName, userPhone1,
userPhone2, userEmail, userEmail2, addrBasic,
addrDetail, addrZipNum)
VALUES (#{userId}, #{userPw}, #{userName}, #{userPhone1},
#{userPhone2}, #{userEmail}, #{userEmail2},
#{addrBasic}, #{addrDetail}, #{addrZipNum})
</insert>
</mapper>
Mybatis를 사용하기 위한 설정
null 처리 가능
result type 별칭 지정 가능
최대 응답 시간 지정 가능
mapper 위치 지정 가능
마지막으로 root-context.xml에 등록해줘야 mybatis에서 인식 가능
<?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">
<!-- mybatis 설정 -->
<configuration>
<settings>
<!-- mybatis에서 쿼리에 맵핑되는 파라미터에 NULL이 들어가면 에러가 발생함으로
value에 전달할 값이 null일 경우 처리할 값을 지정하면 에러가 발생하지 않도록 해줌-->
<!-- <setting name="jdbcTypeForNull" value="VARCHAR"/> -->
<setting name="jdbcTypeForNull" value="NULL"/>
<!-- mybatis로 전송된 값의 type null이면 value값으로 바꿔줌 -->
<settings name="defaultStatementTimeout" value="3000" />
<!-- DB로 부터의 응답을 얼만큼 오래 기다릴지를 판단하는 타임아웃 설정 -->
</settings>
<typeAliases>
<!-- select할 때 resultType이 길어지는 것을 별칭으로 만들어줌 -->
<typeAlias type="com.spring.myweb.command.UserVO" alias="UserVO" />
<typeAlias type="com.spring.myweb.command.ReplyVO" alias="ReplyVO" />
<typeAlias type="com.spring.myweb.command.FreeBoardVO" alias="FreeBoardVO" />
</typeAliases>
<!-- 여기서도 mapper 위치 지정 가능
하지만 root-context에 작성했기 때문에 굳이 지금 작성 하지 않아도 됨 -->
<!-- <mappers>
<mapper resource="classpath:/mappers/*.xml" />
</mappers> -->
</configuration>