JiYoung Dev 🖥

[JSP&Servlet] FrontController (2023.05.23~24) 본문

full stack/Back-End

[JSP&Servlet] FrontController (2023.05.23~24)

Shinjio 2023. 5. 24. 12:15

🎈 FrontController를 사용하는 이유

📖 FrontController 사용하기 전

JoinController, LoginControll를 모두 servlet으로 작성

 

 

servlet은 Httpservlet 객체를 받기 때문에 일반 class보다 무거움

→ servlet이 많아지면 프로젝트 자체가 무거워짐

 

 

따라서 FrontController라는 하나의 컨트롤러(servlet)를 만들고, 그 안에서 각각의 기능에 대한 클래스를 만들어 처리하도록 만듦!

 

🎈 FrontController 사용하기

📖 사용자 요청 구분 방법

FrontController를 사용하면 mapping값이 하나

 

FrontController 사용시 mapping 값

 

FrontController 사용 전 mapping 값

 

> mapping값만 보면 로그인 기능을 하는지, 회원가입 기능을 하는 지등의 어떤 처리를 하는지 구분할 수 없음

 

사용자의 요청을 구분할 수 있도록 추가해줘야 함 

 

⚙ FrontController 구현 - Spring 프레임워크에서 사용하는 방식

 

FrontController만 서블릿

상세 컨트롤러는 class 로 구현

 

 

- 회원 관련 요청을 하나의 컨트롤러(FrontController)로 보냄

- FrontController로 모든 요청을 보내기 위해 URL 요청을 특정 확장자(*.do) 형식으로 끝나도록 설계가 필요함

- .do : 확장자 >> .do만 붙이면 하나의 서블릿을 호출 > .do 앞쪽의 값을 가지고 원하는 기능 판단 후 원하는 기능 호출

 

FrontController 사용시 mapping url : *.do

 

 

FrontController에서 요청을 받으면 실제로 어떠한 Controller를 쓸 것인지 매칭

1. key는 요청경로, value는 특정 기능 Controller의 값을 가진 Map 생성 ▶ init 메서드

  - Map은 순서가 없는 구조로 key-value를 쌍으로 저장할 수 있음

2. 요청이 들어오면 Map이 가지고 있는 key값과 일치하는 controller 사용  

 - Controller(class파일)는 인터페이스를 이용하여 process라고 하는 동일한 메서드를 가지고 있음

 - 따라서 회원가입, 로그인 등 어떤 기능이든지 상관없이 무조건 process 메서드만 호출하면 해당 Controller로 이동하여 기능을 수행할 수 있도록 해줌

 

⚙ URL 파라미터 이용  : 쿼리 스트링 사용하여 구분

 - URL 경로, 값이 수정되면 모두 바꿔주어야 함

 - 외부 노출

 

 

🎈 FrontController 사용하기

1. FrontController Servlet 파일 생성 

- 파일 생성시 service 메서드와 함께 init 메서드 추가할 것 

- init 메서드는 최초로 요청이 들어왔을 때 딱 한 번만 실행되는 메서드로 최초로 요청이 들어왔을 때 요청 경로를 리스트로 미리 만들어 두고 다음 요청이 들어올때마다 꺼내서 사용하도록 하기 위함

 

 

2. pom.xml에 데이터베이스 관련 라이브러리 추가

 

	<!-- MyBatis 추가 (데이터베이스 연동용) -->
	<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
	<dependency>
	    <groupId>org.mybatis</groupId>
	    <artifactId>mybatis</artifactId>
	    <version>3.5.6</version>
	</dependency>
	
	<!-- ojdbc8 -->
	<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
	<dependency>
	    <groupId>com.oracle.database.jdbc</groupId>
	    <artifactId>ojdbc8</artifactId>
	    <version>21.1.0.0</version>
	</dependency>

 

3. web.xml에서 url map 변경 + html form의 action 값 변경

 

<li><h5>회원가입</h5></li>
<form action="join.do" method="post">
  <li><input type="text" name="email" placeholder="Email을 입력하세요" ></li>
  <li><input type="password" name="pw" placeholder="PW를 입력하세요" ></li>
  <li><input type="text" name="tel" placeholder="전화번호를 입력하세요" ></li>
  <li><input type="text" name="address" placeholder="집주소를 입력하세요" ></li>
  <li><input type="submit" value="JoinUs" class="button fit"></li>
</form>

 

4. FrontController Servlet 구현

 

 

package com.smhrd.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//회원관리된 요청 받아줄 프론트 컨트롤러(회원가입, 로그인)
//요청 구분 - 프론트 컨트롤러 : *.do (ex.login.do > 로그인 요청 / join.do > 회원가입 요청)
public class FrontController extends HttpServlet {
	private static final long serialVersionUID = 1L;
	Map<String, Command> list = null;
	//최초로 요청 들어왔을 때 딱 한 번만 실행
	//서버를 끄거나 중단하지 않는 이상 다시 호출되지 않음
	//최초로 요청 들어왔을 때 요청 경로를 리스트로 미리 만들어 두고 요청 들어올 때 꺼내서 씀
	public void init(ServletConfig config) throws ServletException {
		//여기로 들어올 수 있는 요청 경로를 미리 리스트로 만들어 놓기
		//순서 없는 구조인 map 사용! (key-value 쌍으로 저장할 수 있기 때문에)
		//배열은 특정 값만 저장할 수 있음, ArrayList는 순서 있는 구조
		//map 안에 저장할 구조 : key - 요청경로(String /join.do) / value - 그 기능을 수행해줄 컨트롤러 객체
		list = new HashMap<>();
		list.put("/join.do", new JoinController());
		list.put("/login.do", new LoginController());
	}

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String uri = request.getRequestURI();
		String path = request.getContextPath();
		String subUri = uri.substring(path.length());
		
		System.out.println(uri);
		System.out.println(path);
		System.out.println(subUri);
		
		Command controller = list.get(subUri);
		String des = controller.process(request, response);
		System.out.println(des);
		response.sendRedirect(des);
		
	}

}

 

5. Command 인터페이스 구현

- process 메서드 구현 (매개변수 request, response)

 

package com.smhrd.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//모든 컨트롤러가 구현할 인터페이스 
public interface Command {

	//모든 컨트롤러가 process 메서드를 오버라이딩 할 수 있게 강제성 부여!
	//반환 : 최종적으로 이동해야 하는 페이지의 이름
	//메서드 이름 : process
	//request, reponse 객체를 매개인자로 넣어줘야함!
	public String process(HttpServletRequest request, HttpServletResponse response);
}

 

6. Command를 구현 받는 상세 Controller 구현 (JoinController.java)

 

package com.smhrd.controller;


import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.smhrd.model.WebMember;
import com.smhrd.model.WebMemberDAO;

public class JoinController implements Command {
	
	@Override
	public String process(HttpServletRequest request, HttpServletResponse response) {
		
		String url = "";
		
		try {
			//요청 데이터 인코딩
			request.setCharacterEncoding("UTF-8");
			
			String email = request.getParameter("email");
			String pw = request.getParameter("pw");
			String tel = request.getParameter("tel");
			String address = request.getParameter("address");
			
			WebMember member = new WebMember(email, pw, tel, address);
			
			WebMemberDAO dao = new WebMemberDAO();
			int cnt = dao.join(member);
			
			if(cnt>0) {
				System.out.println("회원가입 성공!");
				url = "joinSuccess.jsp";
			}else {
				System.out.println("회원가입 실패!");
				url = "index.jsp";
			}	
		}catch(UnsupportedEncodingException e) {
			System.out.println("인코딩 방식 잘못 지정함!");
		}catch(Exception e) {
			e.printStackTrace();
		}
		return url;
	}

}

 

오류 발생 예. 

 




 

 

 

 

 

 

 

 

 

 

 

 

 

context path : 서버 안에서 프로젝트를 구별하는 경로

 

path 경로가 겹쳐서 오류 발생 > 수정