728x90
최근까지 코딩하는 것에 대해 흥미도 잃고, 의지도 떨어지고 그러는 바람에 수업일지도 띄엄띄엄 작성하다가 마지막 공개글이 한 달 전인 것 같다. 그래서 해야지, 해야지 하고 미뤄두던 개인 프로젝트를 STS4로 해보려고 잡았다가 무엇때문인지 자꾸 에러가 나서 다 포기하고 싶어져서 그만둘 뻔 했었다.
하지만 포기할 수는 없으니까 다시 마음잡고 모르겠으면 보고 따라하고 검색하고 그러는 것부터 차근차근 도전해보기로 했다.
나 자신, 화이팅!!!
0. 시작 전 설정(gradle, application 등)
- build.gradle
더보기
해당 설정은 내가 한 것이 아니라 선생님이 수업하실 때 설정한 파일 내용을 복사해왔다.
나중에 내가 익숙해진다면, 이것도 직접 설정해서 해보고싶다.
- application.preoperties
더보기
해당 설정은 나 혼자 검색해보면서 직접 해보려다가 에러가 계속 나는데 이유를 모르겠어서 멘붕이 왔었다.
결국 설명들이 붙어있는 선생님이 수업하실 때 설정한 파일 내용을 복사해왔다.
- log4jdbc~ / logback.xml
더보기
해당 설정은 이해하지 못했다 ㅠ
1. dto
- DB에 담을 회원의 정보를 담을 클래스
더보기
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Accessors(chain=true)
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MemberDto {
private String mId; // 아이디
private String mName; // 이름
private String mEmail; // 이메일
private String mPw; // 비밀번호
private String gName; // 게임 닉네임
private String joinDate; // 가입날짜
}
- @Accessors(chain=true): chaining된 형태로 객체를 생성하거나 수정할 수 있다. admin 페이지를 만들거나 할 때 사용한다. (아직 잘 모르겠다. 나중에 admin 페이지를 만들어 볼 예정이라 넣어놓았다.)
- @Builder: (아직 잘 모르겠다..)
- @Data: getter & setter를 따로 만들 필요없이 자동으로 생성해준다.
- @NoArgsConstructor: 기본 생성자를 만들어준다.
- @AllArgsConstructor: 입력받은 값에 따라 생성자를 만들어준다.
- 필드명은 파라미터명, 컬럼 명과 같아야 헷갈리지 않고 편하게 사용할 수 있다.
2. 회원가입
2-0) 참고한 링크 ㄱ
우선 뇌에 힘줘서 css는 안 넣었다.
회원가입에서 꼭 넣어서 연습하고 싶었던 것은 비동기 통신으로 아이디 중복 검사를 하는 것이었다.
그리고, 비밀번호 확인도 조금! 디테일하게 넣고 싶었다. (비밀번호 입력 전에 비밀번호 확인을 입력하려고 하거나 비밀번호 입력 후 비밀번호 확인을 눌렀다가 안 적는다던가 하는 그런 상황들)
게임 관련 사이트로 할 예정이었기 때문에 인게임 닉네임도 선택 사항으로 넣고, 회원가입 창에서 취소하고 뒤로 가고싶은 경우를 위해 뒤로가기도 넣었다. (사실 뒤로가기는 인터넷에 있으니 따로 필요없을 것 같지만..!)
2-1) body
- form 태그
- 다른 홈페이지들의 회원가입 페이지를 많이 뜯어봐야 할 것 같다. 대충 구조는 알겠는데, 이것보다 나은 구조를 짤 수 있을 것 같은데 잘 모르겠다 ㅠㅠ
- 그리고 class가 box_tip_title인 div는 p태그로 적은 부분을 제목(선 사이에 있는)으로 해서 안에 있는 요소들을 선으로 감싸는 구조로 하고 싶었는데 찾을 수 없었다..나중에 다시 찾아봐야겠다.
더보기
<form id="join_frm" method="post" action="/member/join" onsubmit="return joinCheck()">
<div class="big-box j-b-box">
<div class="box_tip_title">
<p class="tip_title">필수 입력 사항</p>
<div class="frm_item">아이디
<input type="text" id="mId" name="mId" class="input" placeholder="아이디 입력" value="" maxlength="20" autocapitalize="off">
<div id="chId" style="display: none;"></div>
</div>
<div class="frm_item">이름
<input type="text" id="mName" name="mName" class="input" placeholder="이름 입력" value="" maxlength="10" autocapitalize="off">
</div>
<div class="frm_item">이메일
<input type="text" id="mEmail" name="mEmail" class="input" placeholder="이메일 입력" value="" maxlength="40" autocapitalize="off">
</div>
<div class="frm_item" id="joinPwDiv">
비밀번호
<input type="password" id="mPw" name="mPw" class="input" placeholder="비밀번호 입력" value="" maxlength="20">
<br>비밀번호 확인
<input type="password" id="chMPw" name="chMPw" class="input" placeholder="비밀번호 재입력" value="" maxlength="20">
<div id="chPw" style="display: none;"></div>
</div>
</div>
<div class="box_tip_title">
<p class="tip_title">선택 입력 사항</p>
<div class="frm_item">인게임 닉네임
<input type="text" id="joinMGName" name="joinMGName" class="input" placeholder="인게임 닉네임 입력" value="" maxlength="40" autocapitalize="off">
</div>
</div>
</div>
<br>
<input type="button" value="뒤로가기" onclick="history.back()">
<button type="submit" class="btn btn-3 btn-3e" id="joinSubBtn" style="text-align: center;">join the membership!</button>
</form>
2-2) js
더보기
let useId = false; // id 체크용
let usePw = false; // pw 체크용
- jquery를 여럿으로 나누어 작성했기 때문에 나중에 회원가입 버튼을 눌렀을 때 간편하게 확인하기 위해 필드에 boolean으로 선언해두었다.
$('#mId').on('keyup blur',function(){ // 중복 아이디 체크
let id = $('#mId').val();
document.getElementById("chId").style.display = 'block';
if (id==''){
$('#chId').html('아이디를 입력해주세요.').css('color','red');
$('#mId').focus();
return;
}
let chIdSend = {mId:id};
console.log("chIdSend: ",chIdSend);
$.ajax({
method:'get',
url: '/member/idCheck',
data: chIdSend,
}).done(function(res){
console.log("res: ",res);
if(res=='ok'){
$('#chId').html('아이디 사용 가능!').css('color','blue');
useId = true;
}else{
$('#chId').html('아이디 사용 불가!').css('color','red');
useId = false;
}
}).fail((err,status)=>{
console.log("err:", err);
console.log("status:", status);
useId=false;
})
});
- 중복 아이디를 ajax 비동기로 통신하기 위한 코드
- jquery 이벤트로 keyup(키를 누르고 뗄 때 실행), blur(입력 양식에서 마우스 커서가 떼어지면 실행) 두 개를 동시에 사용했다.
- 비동기 통신을 하기 전에 blur를 통해 회원가입 할 아이디 값이 빈 칸이라면 아이디 칸에 커서를 옮기고 return하도록 했다.
- return되지 않았다면 비동기 통신을 위해 ajax 구조를 입력했다.
- 첫번째 괄호, 대괄호에는 method(보낼 방법: get/post), url(보낼 위치), data(보낼 데이터)를 입력한다.
- 뒤에 오는 두번째 코드는 갖다 오는 것에 성공하면 실행할 코드로, 받아온 데이터(매개변수)에 따라 아이디가 사용가능한지 아닌지 input mId 밑에 있는 div안 글씨를 바꾼다.
- 실패 시 세번째 코드가 받는다.
$('#chMPw').on('click',function(){ // 비밀번호 체크
let pw = $('#mPw').val();
let chPw = $('#chMPw').val();
let con = document.getElementById("chPw");
con.style.display = 'block';
if (pw==''){
$('#chPw').html("비밀번호를 먼저 입력해주세요.").css("color",'red');
$('#mPw').focus();
return;
}
})
$('#chMPw').blur(function(){
let pw = $('#mPw').val();
let chPw = $('#chMPw').val();
let con = document.getElementById("chPw");
con.style.display = 'block';
if (pw!='' && chPw==''){
$('#chPw').html("비밀번호 확인 칸은 비워둘 수 없습니다.").css("color",'red');
$('#chMPw').focus();
return;
}
})
$('#joinPwDiv').on('keyup', function(){
let pw = $('#mPw').val();
let chPw = $('#chMPw').val();
let con = document.getElementById("chPw");
con.style.display = 'block';
if (pw!=''){
if(pw.length<=20 && pw.length>=8){
$('#chPw').html("");
}else if(pw.length>20 || pw.length<8){
$('#chPw').html("비밀번호의 길이는 8~20로 정해주세요.").css("color",'red');
$('#mPw').focus();
return;
}
if(chPw!='' && pw!=chPw){
$('#chPw').html("비밀번호가 다릅니다.").css("color",'red');
$('#chMPw').focus();
}else if(pw==chPw){
usePw = true;
con.style.display = 'none';
}
return;
}
usePw = false;
});
- 첫번째 코드는 비밀번호 확인 칸을 클릭했을 때 비밀번호 칸이 비워져있다면 비밀번호 칸에 커서를 옮긴다.
- 두번째 코드는 비밀번호 확인 칸을 클릭했다가 빈 칸인 상태(채웠다가 지운 경우도)에서 다른 곳을 클릭 시 비밀번호 확인 칸을 비울 수 없다며 비밀번호 확인 칸에 커서를 옮긴다.
- 세번째 코드는 비밀번호/비밀번호 확인 칸에서 키보드가 눌렸다가 떼어질 때 비밀번호 칸의 길이, 비밀번호 칸과 비밀번호 확인 칸의 동일값인지 확인한다.
function joinCheck(){
let name = $('#mName').val();
let email = $('#mEmail').val();
let pw = $('#mPw').val();
let chPw = $('#chMPw').val();
let gName = $('#mGName').val();
if (!useId){
alert("아이디를 확인해주세요.");
$('#mId').focus();
return false;
}else if(name==''){
alert("이름을 입력해주세요.");
$('#mName').focus();
return false;
}else if(email==''){
alert("이메일을 입력해주세요.");
$('#mEmail').focus();
return false;
}else if(!usePw){
alert("비밀번호를 확인해주세요.");
$('#mPw').focus();
return false;
}
alert("회원가입 성공!")
return true;
}
- 모든 칸의 값을 저장해두고, 조건에 따라 커서를 움직이고 리턴한다.
- 모든 조건에 해당하지 않는다면 회원가입 성공 알림창을 띄우고 form 안의 정보들을 전송한다.
2-3) controller
더보기
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.myPro.persP.service.MemberService;
import lombok.extern.slf4j.Slf4j;
@RestController // asynchronous(비동기) 를 받아주는 컨트롤러
@Slf4j
public class MemberAsyController {
@Autowired
private MemberService mSer;
@GetMapping("/member/idCheck")
public String idCheck(@RequestParam(name = "mId") String mId) {
System.out.println(mId);
log.info("==> GetMapping - idCheck 요청: ", mId," <==");
return mSer.idCheck(mId);
}
}
- ajax 비동기 통신을 위해 만든 MemberAsyController
- @RestController는 asynchronous(비동기)를 받아주는 컨트롤러다.
- 가져올 매개변수에 @RequestParam에 mId(가져올 값의 키?)를 적어주지 않으면 에러가 나며 비동기 통신에 실패한다.
- MemberService에 매개변수를 넣어 idCheck 메소드를 실행해 리턴 값을 그대로 리턴해준다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.myPro.persP.dto.MemberDto;
import com.myPro.persP.service.MemberService;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
public class MemberController {
@Autowired
private MemberService mSer;
@GetMapping("/member/joinfrm")
public String join() {
log.info("==> GetMapping - joinfrm 요청 <==");
return "join";
}
@PostMapping("/member/join")
public String join(MemberDto mDto, RedirectAttributes ra) {
boolean result = mSer.join(mDto);
if(result) {
ra.addFlashAttribute("msg","회원가입 성공!");
return "redirect:/member/loginfrm";
}
ra.addFlashAttribute("msg","회원가입 실패");
return "redirect:/";
}
@GetMapping("/member/loginfrm")
public String login() {
log.info("==> GetMapping - loginfrm 요청 <==");
return "login";
}
@PostMapping("/member/login")
public String logrin() {
return "login";
}
}
- MemberController
- login은 아무 기능 없이 임시로 만들어두었다.
- GetMapping으로 joinfrm을 요청하는 것은 메인 화면에서 들어오는 링크로, join.jsp를 리턴해준다.
- PostMapping이 진정한 회원가입을 위한 기능인데, 여기서 메시지를 저장했는데 사용하는 것을 잊었다..
- form 태그에서 보내온 데이터를 알아서 MemberDto로 저장하고, 이 mDto를 MemberService를 통해 boolean으로 회원가입(DB전송) 성공여부를 받고, 성공여부에 따라 보낼 위치를 따로 지정해 리턴한다.
2-4) service
더보기
@Autowired
private MemberDao mDao;
public boolean join(MemberDto mDto) {
BCryptPasswordEncoder pwEn = new BCryptPasswordEncoder();
mDto.setMPw(pwEn.encode(mDto.getMPw()));
return mDao.join(mDto);
}
- 회원가입을 위한 메소드
- BcryptPasswordEncoder를 통해 비밀번호를 암호화해주고, MemberDao의 join을 실행하고 리턴 값을 그대로 리턴해준다.
public String idCheck(String mId) {
log.info("===> mSer checkId 요청: ",mId," <===");
boolean result = mDao.idCheck(mId);
System.out.println("==== mSer -> result: "+result);
if(!result) {
return "ok";
}
return "no";
}
- 중복 아이디 체크를 위한 메소드
- MemberDao에 id 검색을 실행하고 성공 값을 boolean으로 받아, 실패, 성공 시에 따라 "ok", "no"를 리턴해준다.
2-5) dao
더보기
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import com.myPro.persP.dto.MemberDto;
@Mapper
public interface MemberDao {
boolean join(MemberDto mDto);
boolean idCheck(String mId);
}
- MemberDao
<?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.myPro.persP.dao.MemberDao">
<insert id="join" parameterType="MemberDto">
insert into member values(#{mId},#{mName},#{mEmail},#{mPw},#{gName},default)
</insert>
<select id="idCheck" parameterType="String" resultType="boolean">
select count(*) from member where mId=#{mId}
</select>
</mapper>
- MemberDao의 xml 파일 (mappers)
- MemberDao.java의 이름이 id값이 되고, parameterType은 받아올 타입이다. 받아올 타입은 알아서 인식할 수 있기 때문에 생략해도 된다.
- resultType은 리턴해줄 타입이다. 안 적어도 java 파일의 타입을 통해 알아서 인식할 수도 있다. (생략하는 것을 추천하지 않는다고 하셨던 것 같다.)
3. 결과? 스크린샷 화면들
더보기
- 아이디에 아무것도 입력하지 않고, 다른 곳을 클릭했을 경우
- 아이디를 사용할 수 있을 경우
- 아이디를 사용할 수 없는 경우
- 이름, 이메일 입력 없이 회원가입 버튼을 눌렀을 경우
- 비밀번호 입력 없이 비밀번호 확인 칸을 클릭했을 경우
- 비밀번호 길이가 부족하거나 넘었을 경우
* 이때 길이를 충족하지 않은 상태로 비밀번호 확인 칸 입력 시 비밀번호 칸으로 이동한다.
- 비밀번호가 다를 경우
- 비밀번호가 같은 경우
- 회원가입 성공!
* DB 확인
1, 3번은 이전에 실험용으로 넣은 데이터다.
2번이 막 일지를 정리하면서 넣은 데이터!
틀리거나 헷갈렸던 점 메모
- ajax
- js에서 display (none, block) 제어
전체 피드백
- 타임리프 안 쓸건데 처음 시작 때 타임리프 넣어서 에러나고 제이쿼리 링크 안 긁어와서 제이쿼리 안 먹고 정말 다사다난했다 ㅠㅠ
- sql 구문에서도 resultType을 parameterType으로 적어놓고 뭐가 문젠지 모르고, 매개변수도 #${mId} 이런 식으로 적어놓고 에러나야 알고 그랬다.
- 역시 해봐야 익숙해지는 것 같다. 빨리 이거 끝내고 여러개 더 만들어봐야겠다. 비슷하더라도 여러번 해봐야 익숙해져서 나중에는 if문, for문 익숙해지는 것 마냥 편하게 사용할 테니까..!
- 그래도 뭔가 해결되니까 그나마 하고싶어지는 마음은 생기는 것 같다! 슬럼프(?) 극복하기..!
728x90
'프로그래밍 > +a' 카테고리의 다른 글
미니 팀 프로젝트 사전 준비 (파이썬) (2) | 2024.01.01 |
---|---|
slPro 2차 일지 (0) | 2023.12.28 |
Java_주말 복습: 문제 다시 풀어보기 (0) | 2023.10.01 |
Java_주말 복습: 문제 다시 풀어보기 (0) | 2023.10.01 |
자바로 콘솔창으로 하는 게임 만들어보기 (0) | 2023.09.24 |