Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags more
Archives
Today
Total
관리 메뉴

개발공부 일지

학원수업_52day [JSP,Servlet(19day) - 회원가입 구현 / Interceptor / Ajax 기초 ] 본문

학원수업/Web(HMTL,CSS,JSP,Servlet)

학원수업_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>

index.jsp 브라우저 결과

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>

step1-syn.jsp 기존 동기 방식 클릭 후 화면

 

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();
	}

}

SynServlet 결과

여기서 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>

 

url로 넘어가지 않고 (화면이 바뀌지않고) 그대로 보여줌