개요

Controller

Front Controller

// DispatcherServlet.java

package front.ctrl;

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 com.sinc.intern.factory.BeanFactory;
import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

@WebServlet("*.inc")
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public DispatcherServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		requestProc(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		requestProc(request, response);
	}

	protected void requestProc(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 사용자의 url 요청을 그대로 출력
		// 어떤 요청인지 이곳에서 분기 가능
		String uri = request.getRequestURI();
		System.out.println("client url: " + uri);

		// DispatcherServlet 입장에서 Controller라는 하나의 타입으로 관리해서 편리
		BeanFactory factory = BeanFactory.getInstance();
		Controller ctrl = factory.getBean(uri);

		// View(JSP)를 Controller가 직접 전달하는게 아닌 Front Controller를 통해 전달
		// 포워딩 방식과 Send Redirect 방식 2가지
		ModelAndView mv = ctrl.execute(request, response);
		if (mv.isSend()) {
			// 포워딩 방식(현업) --> 권장
			// 브라우저의 url에 .jsp가 노출(.jsp)
			// insert.inc
			RequestDispatcher view = request.getRequestDispatcher(mv.getPath());
			view.forward(request, response);
		} else {
			// Send Redirect 방식
			// 브라우저의 url이 그대로 유지(inc)
			// select.inc
			response.sendRedirect(mv.getPath());
		}
	}
}

Front Controller 입장에서 Factory로부터 리턴받는 Controller라는 하나의 타입으로 관리해서 편리

Controller로부터 JSP 파일(View)을 인도받아서 이를 포워딩 방식이나 Send Redirect 방식으로 사용자에게 전달

1. Send Redirect 방식

-->

<--(jsp)

----------------------요청 끝

-->(jsp)

<--

요청에 대해 응답이 온 것처럼 보이지만 내부적으로 2번의 응답이 있는 구조

jsp 파일을 리턴하면서(2번째 화살표) 해당 요청이 끝남 -> connection이 끊기면 이전의 데이터 상태를 유지하지 못하므로 좋지 않다

클라이언트 브라우저에서 jsp에 대한 redirect 요청(3번째 화살표)

2. 포워딩 방식

-->

<--

Send Redirect 방식과 달리 하나의 요청과 응답으로 구성

분기 방식에 따라 데이터를 가져올 수도, 못가져올 수도 있다

포워딩 방식 O / SendRedirect 방식 X

// greeting.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div align="center">hello</div>
	<hr />
	Result :: ${msg}
</body>
</html>

Factory

Factory 클래스를 싱글톤으로 설계

Factory 클래스에 다양한 컨트롤러들을 Controller 타입의 Map으로 관리

Factory의 Map에 url과 컨트롤러를 key-value로 등록

Factory에서 Controller타입으로 Front Controller에게 전달

package com.sinc.intern.factory;

import java.util.HashMap;
import java.util.Map;

import com.sinc.intern.insa.ctrl.InsertCtrl;
import com.sinc.intern.insa.ctrl.MainCtrl;
import com.sinc.intern.insa.ctrl.SelectCtrl;
import com.sinc.intern.util.Controller;

// BeanFactory.java

public class BeanFactory {
	private static BeanFactory instance;
	private Map<String, Controller> map = new HashMap<String, Controller>();

	private BeanFactory() {
		map.put("/incWEB/insert.inc", new InsertCtrl());
		map.put("/incWEB/select.inc", new SelectCtrl());
		map.put("/incWEB/main.inc", new MainCtrl());
	}

	public static BeanFactory getInstance() {
		if (instance == null) {
			instance = new BeanFactory();
		}

		return instance;
	}

	// 객체의 다형성
	// 다양한 Controller들을 Controller라는 상위 인터페이스 타입으로
	public Controller getBean(String uri) {
		return map.get(uri);
	}

}

Controller

<>(Interface)

<> implements Controller

<> implements Controller

모든 컨트롤러들이 Controller interface를 구현

// Controller.java

package com.sinc.intern.util;

import java.io.IOException;

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

import com.sinc.intern.view.util.ModelAndView;

public interface Controller {
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException;
}
// SelectCtrl.java

package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class SelectCtrl implements Controller {

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("SelectCtrl execute");
		ModelAndView mv = new ModelAndView(true, "greeting.jsp");
		request.setAttribute("msg", "data"); // 데이터 가져옴
		return mv;
	}

}
// InsertCtrl.java

package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class InsertCtrl implements Controller {

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("InsertCtrl execute");
		ModelAndView mv = new ModelAndView(false, "greeting.jsp");
		request.setAttribute("msg", "data"); // 데이터 못가져옴
		return mv;
	}

}

Model And View

// ModelAndView.java

package com.sinc.intern.view.util;

public class ModelAndView {
	private boolean send;
	private String path;

	public ModelAndView() {

	}

	public ModelAndView(boolean send, String path) {
		super();
		this.send = send;
		this.path = path;
	}

	public boolean isSend() {
		return send;
	}

	public void setSend(boolean send) {
		this.send = send;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	@Override
	public String toString() {
		return "ModelAndView [send=" + send + ", path=" + path + "]";
	}

}

Welcome page

MVC에선 모든 요청들이 무조건 컨트롤러를 통해서 처리되어야 함

Controller를 태워야지만 Back단의 데이터를 사용할 수 있다

모든 Request는 무조건 Controller에서 시작해야 한다

<<index.jsp>>(Welcome page)도 예외가 아니다

Welcome page에서 script 태그를 통해 <<main.inc>>로 태워 컨트롤러를 거치게 한다

<>에서 <<main.jsp>> 리턴

// index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<script>
	location.href = "main.inc";
</script>
// MainCtrl.java

package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class MainCtrl implements Controller {

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("MainCtrl execute");
		ModelAndView mv = new ModelAndView(true, "main.jsp");
		return mv;
	}
}
// main.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<div align="center">진짜루 재미없는 웹 프레임워크 by jslim</div>
	<hr />
	Post ::
	<br />
	<form action="parameter.inc" method="post">
		<input type="text" name="msg" id="msg"> <input type="submit"
			value="이벤트">
	</form>

	Get ::
	<br />
	<a href="parameter.inc?msg=jslim">링크</a>
</body>
</html>

Get방식

  • url 뒤에 ?와 함께 key-value 쌍을 전달하는 방식
  • url에 노출됨

Post방식

  • 캡슐화되서 parameter로 넘어옴
  • url에 노출 X
// ParamCtrl.java

package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class ParamCtrl implements Controller {

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		System.out.println("method: " + request.getMethod());
		System.out.println("url: " + request.getRequestURL());
		System.out.println("queryString: " + request.getQueryString());
		
		request.setCharacterEncoding("utf-8");
		String msg = request.getParameter("msg");
		System.out.println("Param Result :: " + msg);
		
		return new ModelAndView(true, "greeting.jsp");
	}
}

Model

의존성 주입(Dependency Injection)

Controller가 Service를 소유

Service가 Dao를 소유

VO와 DTO

  • VO(Value Object)
  • DTO(Data Transfer Object)

하나 이상의 parameter가 있으면 무조건 객체(VO나 DTO)에 담는다

parameter로 넘어오는 변수 이름과 VO의 변수 이름은 동일하게 맞추는 것이 좋다

// LoginCtrl.java
package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.insa.model.vo.UserDTO;
import com.sinc.intern.insa.service.UserService;
import com.sinc.intern.insa.service.UserServiceImpl;
import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class LoginCtrl implements Controller {

	private UserService service; // Dependency Injection

	public LoginCtrl() {
		service = new UserServiceImpl();
	}

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("LoginCtrl execute");
		String id = request.getParameter("id");
		String pwd = request.getParameter("pwd");
		UserDTO dto = new UserDTO(id, pwd);
		Object user = service.select(dto); // 하나 이상의 parameter가 있으면 무조건 객체(VO나 DTO)에 담는다
		System.out.println("Ctrl result user: " + user);
		return null;
	}
}
// UserDao.java
package com.sinc.intern.insa.model.sql;

import java.util.List;

public interface UserDao {

	public Object selectRow(Object obj);

	public List<Object> selectRow();

	public int insertRow(Object obj);

	public int updateRow(Object obj);

	public int deleteRow(Object obj);
}

// UserDaoImpl.java
package com.sinc.intern.insa.model.sql;

import java.util.List;

public class UserDaoImpl implements UserDao {

	@Override
	public Object selectRow(Object obj) {
		System.out.println("UserDao selectRow");
		System.out.println("Dao user: " + obj);
		return null;
	}

	@Override
	public List<Object> selectRow() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int insertRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int updateRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int deleteRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

}
// UserService.java
package com.sinc.intern.insa.service;

import java.util.List;

public interface UserService {

	public Object select(Object obj);

	public List<Object> select();

	public int insert(Object obj);

	public int update(Object obj);

	public int delete(Object obj);
}

// UserServiceImpl.java
package com.sinc.intern.insa.service;

import java.util.List;

import com.sinc.intern.insa.model.sql.UserDao;
import com.sinc.intern.insa.model.sql.UserDaoImpl;

public class UserServiceImpl implements UserService {

	private UserDao dao; // Dependency Injection

	public UserServiceImpl() {
		dao = new UserDaoImpl();
	}

	@Override
	public Object select(Object obj) {
		System.out.println("UserService select");
		return dao.selectRow(obj);
	}

	@Override
	public List<Object> select() {

		return null;
	}

	@Override
	public int insert(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int update(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int delete(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}
}
// UserDTO.java

package com.sinc.intern.insa.model.vo;

public class UserDTO {
	private String id, pwd;

	public UserDTO() {

	}

	public UserDTO(String id, String pwd) {
		super();
		this.id = id;
		this.pwd = pwd;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	@Override
	public String toString() {
		return "UserDTO [id=" + id + ", pwd=" + pwd + "]";
	}

}

DAO

Data Access Object

어떤 벤더사의 DB를 사용하더라도 동일한 인터페이스로 DB에 접근해야 한다

데이터에 접근하는 순서

  1. Driver loading
  2. Connection
  3. Statement(SQL)
  4. Execute
    1. DML: int
    2. Select: Result Set
  5. Result Set handling
  6. Connection close();

위 과정을 모두 포함하는 Framework = MyBatis

// LoginCtrl.java
package com.sinc.intern.insa.ctrl;

import java.io.IOException;

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

import com.sinc.intern.insa.model.vo.UserDTO;
import com.sinc.intern.insa.service.UserService;
import com.sinc.intern.insa.service.UserServiceImpl;
import com.sinc.intern.util.Controller;
import com.sinc.intern.view.util.ModelAndView;

public class LoginCtrl implements Controller {

	private UserService service; // Dependency Injection

	public LoginCtrl() {
		service = new UserServiceImpl();
	}

	@Override
	public ModelAndView execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		System.out.println("LoginCtrl execute");
		String id = request.getParameter("id");
		String pwd = request.getParameter("pwd");
		UserDTO dto = new UserDTO(id, pwd);
		Object user = service.select(dto); // 하나 이상의 parameter가 있으면 무조건 객체(VO나 DTO)에 담는다
		System.out.println("Ctrl result user: " + user); // User가 있을수도 있고 null일수도 있으므로 유효성 체크를 해서 분기
		return null;
	}
}
// UserDaoImpl.java
package com.sinc.intern.insa.model.sql;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;

import com.sinc.intern.insa.model.vo.UserDTO;
import com.sinc.intern.insa.model.vo.UserVO;

public class UserDaoImpl implements UserDao {

	// DB Connection을 위한 프로퍼티들
	public static final String DRIVER = "oracle.jdbc.driver.OracleDriver";
	public static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	public static final String USER = "hr";
	public static final String PASSWD = "hr";

	public UserDaoImpl() {
		try {
			Class.forName(DRIVER); // 1. Driver Loading
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	@Override
	public Object selectRow(Object obj) {
		System.out.println("UserDao selectRow");
		System.out.println("Dao user: " + obj);

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rset = null;
		String loginSQL = "SELECT * FROM INTERN_USER_TBL WHERE ID = ? AND PWD = ?";
		UserVO user = null;

		try {
			conn = DriverManager.getConnection(URL, USER, PASSWD); // 2. Connection
			pstmt = conn.prepareStatement(loginSQL); // 3. Statement(SQL)
			pstmt.setString(1, ((UserDTO) obj).getId());
			pstmt.setString(2, ((UserDTO) obj).getPwd());
			rset = pstmt.executeQuery(); // 4. Execute
			if (rset.next()) { // 5. Result Set handling
				user = new UserVO(rset.getString(1), rset.getString(2), rset.getString(3), rset.getDouble(4),
						rset.getString(5));
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (conn != null) {
					conn.close();
				}
			} catch (Exception e2) {
				// TODO: handle exception
			}
		}

		return user;
	}

	@Override
	public List<Object> selectRow() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int insertRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int updateRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public int deleteRow(Object obj) {
		// TODO Auto-generated method stub
		return 0;
	}

}
// UserVO.java

package com.sinc.intern.insa.model.vo;

public class UserVO {

	private String id, pwd, name;
	private double point;
	private String dept;

	public UserVO() {
		// TODO Auto-generated constructor stub
	}

	public UserVO(String id, String pwd, String name, double point, String dept) {
		super();
		this.id = id;
		this.pwd = pwd;
		this.name = name;
		this.point = point;
		this.dept = dept;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPoint() {
		return point;
	}

	public void setPoint(double point) {
		this.point = point;
	}

	public String getDept() {
		return dept;
	}

	public void setDept(String dept) {
		this.dept = dept;
	}

	@Override
	public String toString() {
		return "UserVO [id=" + id + ", pwd=" + pwd + ", name=" + name + ", point=" + point + ", dept=" + dept + "]";
	}

}

DTO와 VO의 변수명

DTO는 User로부터 오는 parameter들과 변수 이름 동일하게

VO는 DB로부터 꺼내는 테이블의 레코드를 담아야 하므로 테이블의 컬럼명과 변수 이름 동일하게

Controller의 역할

파라미터를 받고 파라미터를 DTO(객체)로 만들어서 Service에 넘기고 DAO까지 가게 해준다

DB로부터 받은 데이터의 유효성 검사를 한다

데이터에 따라 알맞은 View를 분기하고 해당 데이터를 쉐어한다


출처: SHINSEGAE I&C 인턴십

profile
Backend Developer

0개의 댓글

관련 채용 정보

Powered by GraphCDN, the GraphQL CDN