2022.10.20 [THU]
- Day 54-
수업 주요 목차
- Review FrontController
- ID 중복체크
- GIT
🤖Review
- Front Controller Design Pattern : 클라이언트의 요청을 하나의 진입점으로 모아서 처리 (공통정책:인코딩, 예외처리, 인증 등..)을 효과적으로 처리할 수 있다. (예 : 은행 콜센터, 키오스크)
- Servlet URL을 (*.do)로 설정하여 모든 request(form tag의 action)를 FrontController로 모은다. (form tag의 액션을 컨트롤러이름 .do로 설정한다.)
- FrontControllerServlet에서 request의 servletPath를 가져와 문자열에 저장해준다.
- 그 후 subString을 이용하여 위의 문자열에서 /와 .do를 제거해준다. (=컨트롤러 이름)
- 컨트롤러 객체를 생성해줘야하는데 doDispatch의 일이 너무 많아지기 때문에 객체생성을 담당해주는 HandlerMapping 클래스를 만들어준다.
- Controller를 interface로 캡슐화하여 FrontControllerServlet에서 각각의 컨트롤러객체를 사용하는 것이 아니라, 계층구조 형성하였으므로 다양한 하위 컨트롤러 객체들을 단일한 소통방식으로 제어할 수 있게한다.
- FrontControllerServlet에서 HandlerMapping에게 컨트롤러 이름을 넘겨주면 HandlerMapping의 create 메소드를 이용해 컨트롤러 객체를 return해준다.
- HandlerMapping의 create 메소드에서는 reflection API를 사용하여 런타임시에 동적으로 객체를 생성해준다.(=사용자의 요청사항에 따라 그에 맞는 컨트롤러 객체를 생성해준다.)
- 우선 Class.forName()으로 클래스 객체를 가지고 온 뒤 newInstance()로 생성해주는데 Class.forName()의 매개변수로 (패키지명.컨트롤러이름)으로 넣어주어 해당 컨트롤러 객체를 가져온 뒤 생성해준다. (여기서 문자열을 다룰 때 StringBuilder를 사용해야 문자열이 매번 생성되는 것이 아니라 하나의 문자열이 변경되어 자원을 절약할 수 있다.)
- 그리고 각 컨트롤러가 return하는 path를 문자열에 담아준다. (예 : String viewPath=controller.handlerRequest(request,response))
- 마지막으로 viewPath(jsp파일)로 이동시켜줄 때 get 방식과 post 방식에 따라 viewPath가 startWith(redirect:)이면 response.sendRedirect(viewPath.trim().subString(9));로 아니면 request.getRequestDispatcher(viewPath).forward(request,response)로 보내준다.
Reflection API : 런타임시 동적으로 객체 생성 및 제어하기 위한 기술 (클래스 타입을 구체적으로 알지 못해도 정보에 접근할 수 있게 해주는 자바기술)
🔎 Eclipse 실습 내용
- 아이디 중복확인 개발단계
0. Ajax 스터디 및 자료조사
1. db sql
2. model unit test
3. controller 구성 - Ajax Response View
4. view : Ajax 구현
1. 아이디 중복체크 (Ajax 사용)
-DAO에 추가된 method
public boolean checkId(String id) throws SQLException {
boolean result=false;
Connection con=null;
PreparedStatement pstmt=null;
ResultSet rs=null;
try {
con=getConnection();
String sql="SELECT COUNT(*) FROM member WHERE id=?";
pstmt=con.prepareStatement(sql);
pstmt.setString(1, id);
rs=pstmt.executeQuery();
if(rs.next()) {
if(rs.getInt(1)>0) {
result=true;
}
}
} finally {
closeAll(rs,pstmt,con);
}
return result;
}
원래 위처럼 짰었는게 강사님이 rs.next()만 써주는 게 아니라 &&rs.getInt(1)>0도 함께 써주어도 된다고 하셔서 그렇게 수정했다.
- Ajax로 데이터를 통신할 때 jsp에 중복되어 선언되는 코드들을 담당할 서블릿
package org.kosta.myproject.controller;
import java.io.IOException;
import java.io.PrintWriter;
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("/AjaxView")
public class AjaxViewServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
//Ajax 응답이므로 필요한 데이터만 클라이언트로 전송하면 된다.
out.print(request.getAttribute("responsebody"));
out.close();
}
}
request.getAttribute("responsebody")는 controller에서 response.setAttribute("responsebody",로직처리결과)를 해주면 된다.
- CheckIdController
package org.kosta.myproject.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.MemberDAO;
public class CheckIdController implements Controller {
@Override
public String handlerRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String id=request.getParameter("id");
boolean checkId=MemberDAO.getInstance().checkId(id);
String message=null;
if(checkId) {
message="ok";
} else {
message="fail";
}
request.setAttribute("responsebody", message); // AjaxViewServlet이 클라이언트에게 응답하도록 저장
return "AjaxView";
}
}
-회원가입 폼 jsp
-개발 순서-
1. javascript onkeyup event test
2. 입력한 id를 span 영역에 보여주기
3. 입력한 아이디가 4자 미만이면 pink, 아이디는 4자 이상 메세지를 보여준다.
4. 4자 이상이 되면 ajax로 아이디 중복확인 메세지만 남긴다.
<font color=pink>아이디는 4자 이상</font>
5. 아이디가 4자 이상일 때 CheckIdController.do url로 ajax 요청하여 ok를 응답받으면 사용가능(white)
fail을 응답받으면 사용불가(red)
메세지를 제공한다.
6. 사용가능 상태일 때만 회원가입이 되게 한다. 아이디 중복확인하세요! alert
7. 아이디가 중복되면 회원가입 불가능하게 하기(js onsubmit과 preventdefault사용)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script
src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
<style type="text/css">
body {
background: linear-gradient(to right, rgba(115, 209, 250),
rgba(115, 169, 255));
color: white;
text-align: center;
}
input {
background-color: transparent;
border: 2px solid white;
border-radius: 9999em;
}
button {
color: gray;
background-color: white;
border: 2px solid white;
border-radius: 50px;
}
a {
color: white;
}
</style>
</head>
<body>
<div class="container pt-3">
<form action="RegisterController.do" method="post" onsubmit="checkRegister(event)">
<h3>회원가입</h3>
<br> <input type="text" id="id" name="memberId"
placeholder="아이디" required="required" onkeyup="checkId()"><br>
<span id="checkcheck"></span> <br>
<br> <input type="password" name="memberPassword"
placeholder="패스워드" required="required"><br>
<br> <input type="text" name="memberName" placeholder="이름"
required="required"><br>
<br> <input type="text" name="memberAddress" placeholder="주소"
required="required"><br>
<br>
<button type="submit" >회원가입</button>
<br>
<br> <a href="index.jsp">홈으로 돌아가기</a>
</form>
<script type="text/javascript">
let checkFlag=false;
function checkRegister(event){
if(checkFlag==false){
event.preventDefault();
alert("아이디 중복되어 회원가입 불가능합니다.");
}
}
function checkId() {
checkFlag=false;
//id가 checkcheck인 span에 사용자가 입력한 memberId text의 value를 할당한다.
//document.getElementById("checkcheck").innerHTML=document.getElementById("id").value;
let memberId = document.getElementById("id").value;
let checkResultSpan = document.getElementById("checkcheck");
if (memberId.length < 4) {
checkResultSpan.innerHTML = "<font color=red>아이디는 4자 이상</font>";
} else {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
let message=xhr.responseText;
if(message=="fail"){
document.getElementById("checkcheck").innerHTML ="<font color=white>사용가능한 아이디입니다</font>";
checkFlag=true;
} else{
document.getElementById("checkcheck").innerHTML ="<font color=red>중복되는 아이디입니다</font>";
} //else
} //if
} //function
xhr.open("get", "CheckIdController.do?id=" + memberId);
xhr.send();
} //else
} //if
</script>
</div>
</body>
</html>
중괄호 위치 때문에 제대로 작동 안됐던 거 빼고 나머지는 나름 그래도 천천히 풀어나갔는데 마지막 아이디 중복시 회원가입을 막는 거는 진짜 아예 갈피를 못잡겠어서(function을 새로 만들어야 하는 건지, 만든다면 else구문에 만들어 줘야 하는 건지, 아님 따로 빼서 만들어야 하는 건지, checkId() function의 결과를 어떻게 가져와야 하는 건지...아무튼 그래서 강사님한테 hint를 부탁드렸고 전역변수를 사용하라고 힌트를 주셔서 그 후에 풀 수 있었다....(오열)
↓
-Git
1. 개인 Branch에서 작업 + commit
2. Synchronized 확인 → pull 받을게 있으면 pull 받기
3. main으로 이동 + merge(내가 작업한 Branch 선택한 후 merge)
4. Push
5. 다음날 작업을 할 때에는 최신버전의 main에서 새로 branch를 만들어서 작업
//오늘의 숙제
복습