본문 바로가기
Servlet-Jsp

workout(운동기록프로그램 myBatis) #4

by 지민재 2022. 8. 14.
반응형
SMALL
mybatis-workout.xml 에 log4j 세팅 
<settings>
  <setting name="logImpl" value="LOG4J"/>
  </settings>
WEB-LNF / classes / log4j.properties 
log4j.rootLogger=DEBUG, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
https://miharayasuhiro.jp/products/detail.php?product_id=78&c=16 <-- 사이트 들어가서
log4j-1.2.17.jar 다운로드 후 lib 폴더에 넣어줍니다. 
controllers - controllers.member - JoinController 추가
package controllers.member;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/memver/join")
public class JoinController extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
	}

}
doGet - 양식을 보여줄 부분
doPost - 처리하는 부분
join.jsp
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="layout" tagdir="/WEB-INF/tags/layouts" %>
<layout:main title ="회원가입">
<form id="frmRegist" name="frmRegist" method="post" action="<c:url value= "/member/join" /> target="ifrmProcess" >
<jsp:include page="_form.jsp" />
<div class='term_agree'>
<input type="checkbox" name="isAgree" id="isAgree">
<label for="isAgree">약관에 동의</label>
</div>
<div class='btn-grp'>
<button type="reset">다시입력</button>
<button type="submit">가입하기</button>
</div>
</form>
</layout:main>

<jsp:include page="_form.jsp" /> :  include되는 jsp파일의 출력결과(Html 코드)만 포함

 

페이지 이동없이 내부에서 처리하기 위해 target 을 ifrm 으로 지정해주었다. 

 

_form.jsp
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<dl>
<dt>아이디 </dt>
<dd>
<input type ="text" name="memId" placeholder="아이디"/>
</dd>
</dl>

<dl>
<dt>비밀번호</dt>
<dd>
<input type ="password" name="memPw" placeholder="비밀번호"/>
</dd>
</dl>

<dl>
<dt>비밀번호 확인</dt>
<dd>
<input type ="password" name="memPw" placeholder="비밀번호 확인"/>
</dd>
</dl>

<dl>
<dt>회원명</dt>
<dd>
<input type ="text" name="memNm" placeholder="회원명"/>
</dd>
</dl>

<dl>
<dt>이메일</dt>
<dd>
<input type ="email" name="email" placeholder="이메일"/>
</dd>
</dl>

<dl>
<dt>휴대전화번호</dt>
<dd>
<input type ="text" name="mobile" placeholder="휴대전화번호"/>
</dd>
</dl>

 

join.jsp : @WebServlet("/memver/join")  의 view 부분이고 
_form.jsp : 어딘가에 추가할 부분은 관리의 편의성을 위해 _ 로 지정해서 파일을 만들어준다.

 

 

models.member/MemberDao
package models.member;

import org.apache.ibatis.session.SqlSession;

import mybatis.Connection;
public class MemberDao {
	
	private static MemberDao instance = new MemberDao();
	private MemberDao() {}
	
	public MemberDto register(MemberDto member) {
		SqlSession sqlSession = Connection.getSqlSession();
		
		int affectedRows = sqlSession.insert("MemberMapper.register", member);
		
		sqlSession.commit();
		sqlSession.close();
		
		if(affectedRows < 1 ) 
			return null;
		
		return member;
	}
	
	//회원 조회
	public MemberDto get(String memId) {
		SqlSession sqlSession = Connection.getSqlSession();
		MemberDto param = new MemberDto();
		param.setMemId(memId);
		
		MemberDto member = sqlSession.selectOne("MemberMapper.member", param);
		sqlSession.close();
		
		return member;
	}
	
	public static MemberDao getInstance() {
		if(instance == null ) {
			instance = new MemberDao();
		}
		
		return instance;
	}
}
객체를 여러개 만들지 않고 내부에 있는 객체로 공유하는 방식으로 쓰기 위해 싱글톤 패턴을 선택하였다.

사용자에게 Id 중복을 알려주기 위해 회원 조회 

 

 

싱글톤 패턴

최초 한번의 new 연산자를 통해서 고정된 메모리 영역을 사용하기 때문에 추후 해당 객체에 접근할 때 메모리 낭비를 방지할 수 있다. 그리고 생선된 인스턴스를 사용하기 때문에 속도 면으로도 이점이 있다고 한다.
또 다른 이점은 다른 클래스 끼리 데이터 공유가 쉽다 싱글톤 인스턴스가 전역으로 사용되는 인스턴스이기 때문에 다른 클래스의 인스턴스들이 접근하여 사용할 수 있다.

 

models.member/JoinService
package models.member;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import org.mindrot.bcrypt.BCrypt;
/**
 * 
 * 회원 가입 처리
 * @author alswo
 *
 */
public class JoinService {
	public void join(HttpServletRequest request) {
		MemberValidator vaildator = new MemberValidator();
		
		String memId = request.getParameter("memId");
		String memPw = request.getParameter("memPw");
		String memPwRe = request.getParameter("memPwRe");
		String memNm = request.getParameter("memNm");
		String email = request.getParameter("email");
		String mobile = request.getParameter("mobile");
		
		
		//필수 데이터 검증 
		Map<String, String> requiredFields = new HashMap<>();
		requiredFields.put("memId", "아이디를 입력하세요");
		requiredFields.put("memPw", "비밀번호를 입력하세요");
		requiredFields.put("memPwRe", "비밀번호를 확인해주세요");
		requiredFields.put("memNm", "회원명을 입력하세요");
		
		vaildator.requiredCheck(request, requiredFields);
		
		//중복 회원 체크
		vaildator.duplicateMember(memId);
		
		//3. 아이디 비밀번호 복잡성 체크 
		vaildator.checkMemId(memId);
		vaildator.checkMemPw(memPw);
		
		//4. 비밀번호 해쉬화(bcrypt)
		String hash = BCrypt.hashpw(memPw, BCrypt.gensalt(12));
	}
}

 

 

commons/BadRequestException
package commons;

public class BadRequestException extends RuntimeException {

	public BadRequestException() {
		this("잘못된 요청입니다.");
	}

	public BadRequestException(String message) {
		super(message);
	}
}
메세지를 넣지 않으면 기본 메세지를 출력하고 메세지를 지정하면 그 지정한 메세지를 출력 

 

 

commons/Utils
package commons;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;
/**
 * 에외를 alert 출력
 * @author alswo
 *
 */
public class Utils {
	public static void alertError(HttpServletResponse response, RuntimeException e) {
		try {
			response.setContentType("text/html; charset=urf-8");
			PrintWriter out = response.getWriter();
			out.println("<script>alert('"+e.getMessage() + "')</script>");
		} catch (Exception e2) {
			
		}
		
		
	}
}
RuntimeException 객체가 넘어오면 알아서 인식하여 에러 alert 출력 

 

controllers.member/JoinController
package controllers.member;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import commons.BadRequestException;
import models.member.JoinService;
import static commons.Utils.*;

@WebServlet("/member/join")
public class JoinController extends HttpServlet{

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		RequestDispatcher rd = req.getRequestDispatcher("/member/join.jsp");
		rd.forward(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		
		try {
			JoinService service = new JoinService();
			
			service.join(req);
		} catch (BadRequestException e) {
			e.printStackTrace();
			alertError(resp, e);
		}
		
		
	}

}
req.setCharacterEncoding("UTF-8"); 이 부분은 필터로 공통 적용 되게끔 바꿀 예정 

 

commons/Vaildator
package commons;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

public interface Validator {
	default void requiredCheck(HttpServletRequest request, Map<String, String> fields) {
		 for(Map.Entry<String, String> entry : fields.entrySet()) {
			 String value = request.getParameter(entry.getKey());
			 String msg = entry.getValue();
			 if(value == null || value.isBlank()) {
				 throw new BadRequestException(msg);
			 }
		 }
	 }
}
키 값이 null 값이거나 비어있으면 JoinService 에 value 값으로 들어간 메세지가 출력된다. 

 

 

models.member/MemberVaildator
package models.member;

import java.util.regex.*;
import mybatis.Connection;

import org.apache.ibatis.session.SqlSession;

import commons.BadRequestException;
import commons.Validator;

public class MemberValidator implements Validator {
	public void duplicateMember(String memId) {
		SqlSession sqlSession = Connection.getSqlSession();
		MemberDto param = new MemberDto();
		param.setMemId(memId);
		
		int count = sqlSession.selectOne("MamberMapper.count", param);
		
		sqlSession.close();
		
		if(count > 0 ) {
			throw new BadRequestException("이미 등록된 회원입니다."); 
		}
	}
	//Id 복잡성 체크(자리수 6자리,알파벳,숫자)
	public void checkMemId(String memId) {
		if(memId.length() < 6) {
			throw new BadRequestException("아이디는 6자리 이상 입력하세요");
		}
		
		Pattern pattern = Pattern.compile("[^a-z0-9]", Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(memId);
		
		if(matcher.find()) {//숫자, 알파벳이 아닌 문자가 포함되어 있는 경우
			throw new BadRequestException("아이디는 알파벳과 숫자로만 입력하세요");
		}
	}
	
	public void checkMemPw(String memPw) {
		if(memPw.length() < 8) {
			throw new BadRequestException("비밀번호는 8자리 이상을 입력하세요");
		}
	}
 
}
MemberMapper.xml 을 보면 SELECT COUNT(*) FROM member WHERE memId=#{memId}; 이렇게 정의를 하였다.
memId 가 0이상이면 Id 는 sql문에서 unique 로 해놓았지만 사용자도 알아야하기 때문에 "이미 등록된 회원입니다." 라고 에러메세지를 지정해주었다. 


 

댓글