개발공부 일지
학원수업_52day [JSP,Servlet(19day) - 회원가입 구현 / Interceptor / Ajax 기초 ] 본문
학원수업_52day [JSP,Servlet(19day) - 회원가입 구현 / Interceptor / Ajax 기초 ]
짜몽- 2022. 10. 17. 22:46카카오 화재 이슈로 이제서야 티스토리를 올리는데, 오늘 몸이 안좋아 조퇴를 해서.....
많이 작성을 못했다
* 회원가입 구현

( 기존에 실습 하던 클래스들이 있어서 복붙하면서 진행 하심)
0. Interceptor 의 permitAll List 에 RegisterMemberController 추가
1. sql test
2. TestCase : TestCaseRegisterMember → Model 구현
3. Controller 구현
4. View 구현
1. register-form.jsp
<%@ 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>register-form</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
</head>
<body>
<div class="container pt-3">
<form action="RegisterMemberController.do" method="post">
<input type="text" name="id" placeholder="아이디" required="required"><br>
<input type="password" name="password" placeholder="패스워드" required="required"><br>
<input type="text" name="name" placeholder="이름" required="required"><br>
<input type="text" name="address" placeholder="주소" required="required"><br>
<button type="submit">회원가입</button>
</form>
</div>
</body>
</html>

2. register-result
<%@ 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>register-result</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
</head>
<body>
<div class="container pt-3">
<a href="index.jsp">Home</a><br><br>
회원 가입을 축하합니다
</div>
</body>
</html>

* HandlerMapping
package org.kosta.myproject.controller;
/**
* 컨트롤러 구현체 생성을 전담하는 Factory 클래스
* HandlerMapping 은 시스템 상에서 하나만 존재하여 공유해 사용하도록 Singleton Design Pattern 을 적용한다
*
* Reflection API 를 이용해 런타임시에 동적으로 컨트롤러 객체를 생성하게 구현한다
* @author KOSTA
*
*/
public class HandlerMapping {
private static HandlerMapping instance=new HandlerMapping();
private HandlerMapping() {}
public static HandlerMapping getInstance() {
return instance;
}
public Controller create(String command) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
String packageInfo=this.getClass().getPackage().getName();//현재 실행중인 패키지 경로를 받아온다
String classInfo=new StringBuilder(packageInfo).append(".").append(command).toString();//패키지 경로에 .컨트롤러명을 더한다
return (Controller) Class.forName(classInfo).newInstance();
}
}
* RegisterMemberController
package org.kosta.myproject.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.MemberDAO;
import org.kosta.myproject.model.MemberVO;
public class RegisterMemberController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String id=request.getParameter("id");
String password=request.getParameter("password");
String name=request.getParameter("name");
String address=request.getParameter("address");
MemberDAO.getInstance().registerMember(new MemberVO(id,password, name, address));
return "redirect:register-result.jsp";
}
}
* 기존에 작성했던 MemberDAO . Register
public void registerMember(MemberVO vo) throws SQLException {
Connection con=null;
PreparedStatement pstmt=null;
try {
con=getConnection();
String sql="insert into member(id,password,name,address) values(?,?,?,?)";
pstmt=con.prepareStatement(sql);
pstmt.setString(1, vo.getId());
pstmt.setString(2, vo.getPassword());
pstmt.setString(3, vo.getName());
pstmt.setString(4, vo.getAddress());
pstmt.executeUpdate();
}finally {
closeAll(pstmt, con);
}
}
Interceptor 란?
Interceptor란 컨트롤러에 들어오는 요청 HttpRequest와 컨트롤러가 응답하는 HttpResponse를 가로채는 역할을 한다.
(Controller로 가는 호출을 가로채서 특정 처리를 하는 역할.)
인터셉터는 관리자만 접근할 수 있는 관리자 페이지에 접근하기 전에 관리자 인증을 하는 용도로 활용될 수 있다.
스프링 인터셉터는 스프링MVC가 제공하는 기술이다.
인터셉터의 흐름은
HTTP 요청 → WAS → 필터 → 디스패처 서블릿 → 스프링 인터셉터 → 컨트롤러
아래 빨간 부분에서 동작한다.


- preHandle
- 컨트롤러 호출 전에 호출 (더 정확히는 핸들러 어댑터 호출 전에 호출)
- preHandle 의 응답값이 true이면 다음으로 진행하고, false이면 더는 진행하지 않는다. false 인 경우 나머지 인터셉터는 물론이고, 핸들러 어댑터도 호출되지 않는다.
- postHandle
- 컨트롤러 호출 후에 호출 (더 정확히는 핸들러 어댑터 호출 후에 호출)
- afterCompletion
- 뷰가 렌더링 된 이후에 호출
* 인터셉터로 제한을 적용 했을 때 흐름 ?
HTTP 요청 → WAS → 필터 → Dispatcher Servlet → 스프링 인터셉터 → 컨트롤러 (로그인 사용자)
HTTP 요청 → WAS → 필터 → Dispatcher Servlet → 스프링 인터셉터 (이때 적절하지 않은 요청이라 판단하여 컨트롤러 호출을 하지 않는다) (미인증 사용자)

- preHandle
- 컨트롤러 호출 전에 호출
- postHandle
- 컨트롤러에서 예외가 발생하면 postHandle은 호출되지 않는다.
- afterCompletion
- afterCompletion 은 항상 호출
- 예외와 무관하게 공통 처리를 하려면 afterCompletion()을 사용
- 예외가 발생하면 afterCompletion()에 예외 정보( ex )를 포함해서 호출된다.
- 이 경우 예외( ex )를 파라미터로 받아서 어떤 예외가 발생했는지 로그로 출력할 수 있다.
예) 로그인
- CheckLoginInterceptor 클래스
현 시스템에서 인증이 필요없는 서비스컨트롤러 목록 정의
인증이 필요한 서비스컨트롤러에 대해 인증 체크해서
인증 상태이면 true 를 FrontControllerServlet 으로 반환
비인증 상태이면 false 를 FrontControllerServlet 으로 반환한다
package org.kosta.myproject.controller;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/*
CheckLoginInterceptor
현 시스템에서 인증이 필요없는 서비스컨트롤러 목록 정의
인증이 필요한 서비스컨트롤러에 대해
인증 체크해서
인증 상태이면 true 를 FrontControllerServlet 으로 반환
비인증 상태이면 false 를 FrontControllerServlet 으로 반환한다
*/
public class CheckLogininterceptor {
private static CheckLogininterceptor instance=new CheckLogininterceptor();
//인증이 필요없는 컨트롤러 리스트
private ArrayList<String> permitAllList=new ArrayList<>();
private CheckLogininterceptor() {} {
permitAllList.add("TestController");
permitAllList.add("LoginController");
permitAllList.add("RegisterMemberController");
}
public static CheckLogininterceptor getInstance() {
return instance;
}
public boolean checkLogin(HttpServletRequest request,String controllerName) {
boolean result=true; //지역변수 명시적초기화
if(permitAllList.contains(controllerName)==false) {//인증이 필요한 컨트롤러이면 인증을 체크한다 . //포함되있으면, 포함되있지않으면 false
HttpSession session=request.getSession(false); // 세션이 없으면 null, 있으면 기존 세션 반환
if(session==null||session.getAttribute("mvo")==null) //비인증 상태이면 false 를 리턴
System.out.println("**"+getClass().getName()+" "+controllerName+"=> 비인증 상태이므로 로그인해야 함**");
result=false;
}
return result;
}
/*public static void main(String[] args) { //프로그램을 더 견고하게한다, 시큐어코딩
//boolean result=CheckLogininterceptor.getInstance().checkLogin(null, "TestController");
boolean result=CheckLogininterceptor.getInstance().checkLogin(null, "UpdateMemberController"); //반드시 인증
System.out.println("서비스 진행여부:"+result);*/
}
* 인터셉터를 지원하는 Spring 메소드
①HandlerInterceptor 인터페이스
②HandlerInterceptorAdapter 추상클래스
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler)
→ Controller 요청 전 실행
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndVeiw modelAndVeiw)
→ Controller 처리가 끝나고 화면에 띄어주는 처리 직전에 수행
- afterCompletion() : 모든 처리가 끝난 후 호출
Ajax 란?
- JavaScript와 XML을 이용하여 Web Client와 Server간의 비동기적 처리를 지원하는 프로그래밍 기법
– Google의 Google Map이 AJAX를 이용하여 구축된 이후 각광 받음.
– Web 2.0의 Rich Client 기술로 인식되어 Web의 많은 분야에서 적용되는 추세
• AJAX는 그 자체가 하나의 기술이라기 보다는 패턴을 의미 한다. – 기존 Web Browser가 제공하는 기능을 활용하는 프로그래밍 패턴.
– 기존 기술인 JavaScript와 XML등을 이용한 프로그래밍 패턴

AJAX 프로그래밍 패턴
1. XMLHttpRequest 객체 구하기
2. 서버에 Request 전달
3. 서버에서 응답한 Response 데이터 처리하기
<textarea> 태그 란?
- 사용자가 여러 줄의 텍스트를 입력할 수 있는 텍스트 입력 영역을 정의할 때 사용한다.
텍스트 입력 영역에는 개수의 제한 없이 문자를 입력할 수 있으며, 입력된 문자는 고정폭 글꼴로 렌더링된다.
텍스트 입력 영역의 크기는 <textarea> 요소의 cols 속성과 rows 속성으로 지정할 수 있으며,
CSS에서 height 속성과 width 속성을 사용하면 더욱 손쉽게 지정할 수 있다.
<textarea> 태그의 rows 속성은?
- 텍스트 입력 영역 중 보이는 영역의 라인수를 명시한다.
텍스트 입력 영역의 크기는 CSS의 height 속성과 width 속성을 사용해도 설정할 수 있다.
| <textarea rows="숫자"> |
Ajax post 방식일 때 content type을 지정해야 한다.
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
1. index.jsp
<%@ 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>Ajax</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
</head>
<body>
<div class="container pt-3">
<a href="step1-syn.jsp">기존 동기방식 테스트</a><br><br>
<a href="step2-asyn-ajax.jsp">Ajax 비동기방식 테스트</a><br><br>
</div>
</body>
</html>

2. step1-syn.jsp (기존 동기 방식 테스트 화면)
<%@ 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>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
</head>
<body>
<div class="container pt-3">
<form action="SynServlet">
<input type="text" name="id" required="required" placeholder="아이디">
<button type="submit">동기방식테스트</button>
</form>
<br><br>
<textarea rows="50" cols="50"></textarea>
</div>
</body>
</html>

2-1. SynServlet (기존방식)
package step1;
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;
/**
* Servlet implementation class SynServlet
*/
@WebServlet("/SynServlet")
public class SynServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace(); }
*/
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>동기적 방식</title>");
out.println("</head>");
out.println("<body bgcolor=yellow>");
out.println("SynServlet이 응답했습니다");
out.println("</body>");
out.println("</html>");
out.close();
}
}

여기서 HTML 내용을 JSP 로 작성하지 않은 이유는 ?
jsp 로 하면 화면의 전환이 필요하여 버튼 누르면 원래 서블릿으로 해당 url mapping 으로 이루어지는데,
그 url mapping 에 맞는 서블릿안에 화면만 보여주기 위해서! (url로 넘어가지 않고 보여주려는)
3. ASynServlet
package step2;
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;
/**
* Servlet implementation class ASynServlet
*/
@WebServlet("/ASynServlet")
public class ASynServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private int count;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
++count;
/*
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
// Ajax 통신의 응답은 페이지가 아니라 필요한 데이터만 응답한다
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
System.out.println("ASynServlet ajax 요청에 대한 응답");
out.print("hello ajax count:"+count);
out.close();
}
}
3-1. step2-asyn-ajax.jsp
<%@ 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>Insert title here</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>
</head>
<body>
<br>
<span id="result"></span>
<br>
<div class="container pt-3">
<form>
<input type="text" name="id" required="required" placeholder="아이디">
<button type="button" onclick="startAjax()">비동기Ajax방식테스트</button>
</form>
<br>
<span id="result"></span>
<br>
<textarea rows="50" cols="50"></textarea>
</div>
<script type="text/javascript">
let xhr;
function startAjax() {
xhr=new XMLHttpRequest(); //Ajax 통신을 위한 자바스크립트 객체
// ajax 요청에 대한 서버의 응답이 완료될 때 실행될 함수 : callback 함수
// ajax 콜백 함수를 등록
xhr.onreadystatechange=callback;
//alert("startAjax "+xhr);
xhr.open("get", "ASynServlet");
xhr.send(); //요청을 보겠다는 뜻
}
// 서버가 정상적으로 응답하면 동작될 함수
function callback() { //콜백은 서버가 응답하면서 실행
// readtState==4 서버로부터 응답 완료
// status==200 응답 상태 코드 200 정상 수행
if(xhr.readyState==4&&xhr.status==200){ //4가 응답이 완료된 상태
//alert(xhr.responseText); //responseText : 서버가 응답한 데이터
//result id span 영역에 서버에서 응답받은 데이터를 입력한다
document.getElementById("result").innerHTML=xhr.responseText;
}
}
</script>
</body>
</html>

'학원수업 > Web(HMTL,CSS,JSP,Servlet)' 카테고리의 다른 글
| 학원수업_54day [JSP,Servlet(21day) - JSON / Ajax (0) | 2022.10.19 |
|---|---|
| 학원수업_53day [JSP,Servlet(20day) - AJAX 비동기적처리 (GET, POST)/ HandlerInterceptor ] (0) | 2022.10.19 |
| 학원수업_51day [JSP,Servlet(18day) - 로그인,로그아웃, 회원 수정] (0) | 2022.10.14 |
| 학원수업_50day [JSP,Servlet(17day) - Front Controller 3 / Command Pattern] (0) | 2022.10.13 |
| 학원수업_49day [JSP,Servlet(16day) - Front Controller 2] (0) | 2022.10.12 |