JSP

#1 JSP Project 03(Blog) - 프로젝트 전체 구조

H-V 2021. 6. 26. 13:04

210624~26 유투버 '데어프로그래밍'님 강의 참조

 

전체구조

  • 프론트 컨트롤러는 총 3개 (생성한 테이블 개수와 맞추는게 좋다. 하나로 모든 도메인을 처리하는것은 좋지않다)

- 프론트 컨트롤러란?

MVC디자인 패턴에서 사용하는 컨트롤러로써 각각의 뷰와 컨트롤러가 연결되어 독립적으로 처리하기보다는 대표 프론트 컨트롤러를 만들어서 뷰에서 들어오는 모든 요청을 담당하여 웹 어플리케이션에 짜져있는 구조를 실행한다. 

//http://localhost8080/blog/user 요청시 이 컨트롤러 작동
@WebServlet("/user")
public class UserController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	//http://localhost8080/blog/user?cmd=...
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
		String cmd = request.getParameter("cmd");
	}
}

*중요포인트

프론트 컨트롤러에서의 핵심은 'request.getParameter'를 통해 모든요청을 'http://localhost8080/blog/user?cmd=...' url로 처리하게 만든다는 것. 

- request.getParameter란?

간단히 말해 클라이언트의 요청을 'String'형태로 받아서 해석을하여 자바가 거기에 맞도록 움직일수있는 역할(e.g. 클라이언트의 모든요청을 "cmd"로 해석해서 처리)

 

-기본 프로젝트 구조

1. UserController

@WebServlet("/user")
public class UserController extends HttpServlet {
*doGet
*doPost
	//http://localhost8080/blog/user?cmd=...
	protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doProcess(request, response);
		String cmd = request.getParameter("cmd");
		
		//http://localhost8080/blog/user?cmd=loginForm
		if(cmd.equals("loginForm")) {
			//서비스 호출
          //http://localhost8080/blog/user?cmd=login    
		} else if (cmd.equals("login")) {
	}
}

 코드에 나와있듯이 컨트롤러는 요청만 받으면 그 요청을 해석해서 서비스만 호출하는 역할. 

 

 

 

 

2. 서비스의 데이터 및 로직이 되는 Model 

- Model의 역할은 DB에 만든 테이블과 똑같이 세팅을 한 후 DB로부터 데이터를 받기 위한 Object가 되는 것

모델링 끝!

2-1. 서비스의 또 다른 데이터 및 로직이 되는 DTO

- DTO의 역할은 DB에 만든 테이블과 똑같이 세팅을 한 후 클라이언트로부터 데이터를 요청 받아 DB에 꺼내올 때 것

- 요청/응답 DTO를 잘구분해야한다. (e.g. 회원가입/로그인 등은 request, 게시판리스트 response)

- DTO가 필요한 이유 3가지 1)Validation 체크 2)리플렉션 3)DB조인용

 

3. 컨트롤러의 호출 핵심, Service

  • Service의 핵심은 '한 웹에 어떤 기능이 필요한가'로 부터 시작이 된다. 즉 기능을 세팅하는 것.
  • User/Board/Reply는 각각 가지고 있는 기능이 다르다. 
  • 서비스는 모델로부터 데이터를 주고받고 한다!
//사용자에 대한 서비스 기능 - 회원가입/회원수정/로그인/로그아웃/아이디증복체크
public class UserService {
	
	//회원가입시에 정해진 데이터가 필요하기때문에 DTO와 똑같이 받아야함
	//insert --> 정해진 데이터 삽입
	public int 회원가입(JoinReqDto dto) {
		return -1;
	}
	//단순로그인이니 User model로 받으면 됨
	//select --> model과 맵핑 즉 User model
	public User 로그인(LoginReqDto dto) {
		return null;
	}
	
	public int 회원수정(UpdateReqDto dto) {
		return -1;
	}
//	로그아웃은 세션만 날리면 되기때문에 컨트롤러에서 처리
//	즉 response 관련은 컨트롤러에서 처리
//	public void 로그아웃() {}
	
	public int 아이디중복체크(String username) {
		return -1;
	}
}

4. 데이터베이스 연결 (DB연결부터 해도 상관없다)

  • WEB-INF에 'web.xml' 생성 후 세팅
  • META-INF에 'context.xml' 생성 후
  • Connection pulling을 이용해서 연결 세팅
  • contex.xml/web.xml = (https://tomcat.apache.org/tomcat-9.0-doc/jndi-datasource-examples-howto.html#MySQL_DBCP_2_Example) -> 'Resource name...>, <resource-ref...> 만 복사 수정
    *context.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <Context>
      <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
                   maxTotal="100" maxIdle="30" maxWaitMillis="10000"
                   username="bloguser" password="bitc5600" driverClassName="com.mysql.cj.jdbc.Driver"
                   url="jdbc:mysql://localhost:3306/blog?serverTimezone=Asia/Seoul"/>
    </Context>
    
    *web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee; http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd">
      <resource-ref>
          <description>DB Connection</description>
          <res-ref-name>jdbc/TestDB</res-ref-name>
          <res-type>javax.sql.DataSource</res-type>
          <res-auth>Container</res-auth>
      </resource-ref>
    </web-app>

 

public class DBConn {
	public static Connection getConnection() {
		try {
			Context initContext = new InitialContext();
			Context envContext = (Context) initContext.lookup("java:/comp/env");
			DataSource ds = (DataSource) envContext.lookup("jdbc/TestDB"); // contex.xml의 name 과 동일하게
			Connection conn = ds.getConnection();
			return conn;
		} catch (Exception e) {
			System.out.println("DB connection fail" + e.getMessage());
		}
		return null;
	}
}

4-1 web.xml에 필터 추가 + 필터를 작동시킬 CharConfig.java 추가

  • 필터가 필요한 이유는 이름에서 알 수 있듯이 무언가를 걸러내는 역할을 하는데 JSP에서는 클라이언트와 서버간에 요청과 응답시에 서로에게 필요한것만 남기도록 필터링을 해준다고 보면된다
  • 예로 인코딩정보/로그인정보 등 반복사용하는 자원을 이용할때 JSP파일 혹은 JAVA파일에 이에대한 코드를 전부다 넣어 처리해야하지만 이런일을 필터를 만들어놓으면 필터가 알아서 처리한다. 
	<filter>
		<filter-name>charConfig</filter-name>
		<filter-class>com.cos.blog.config.CharConfig</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>charConfig</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
    
    *url패턴이 /* 이므로 모든 페이지에 적용이 된다

 

public class CharConfig implements Filter {
	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html; charset=utf-8");
//		String username = request.getParameter("username");
//		System.out.println("username: " + username);
//		PrintWriter out = response.getWriter();
//		out.println("안녕");
//		out.flush();
		chain.doFilter(request, response);
	}
}

필터가 작동이 잘 된다.

5 다시 controller로 돌아가서 로직을 되새겨보자

  • 컨트롤러는 서비스로 보내기만 하기때문에 항상 service를 탄다고 생각해야한다. 
  • 컨트롤러에서 호출시에 페이지가 어떻게 생겼는지 생각을 잘해야한다. 예로 loginForm vs login은 어떻게 다른가?
  • form이 붙으면 그냥 그 페이지를 달라는 것이고 form이 없는것은 그 기능을 수행하는 페이지이다. 
  • '...form'이 붙으면 단순 response(응답).sendRedirect(...)로 응답을 주면 된다
  • '...form'이 붙지않으면 서비스에서 필요한 기능을 불러온다.
  • 서비스가 필요한 데이터가공은 서비스에서 하는게아닌 컨트롤러에서 미리하고 서비스로 가공된걸 같이 던져준다. 즉 서비스를 설계했던 데이터 타입을 불러와서 가공처리 후 다시 서비스로 보낸다. (리플렉션을 쓰면 더 간단해진다)
    @WebServlet("/user")
    public class UserController extends HttpServlet {
    *doGet
    *doPost
    protected void doProcess(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    		String cmd = request.getParameter("cmd");
    		UserService userSerivce = new UserService();
    		//http://localhost8080/blog/user?cmd=loginForm
    		//서비스 호출
    		if(cmd.equals("loginForm")) {
    			response.sendRedirect("user/loginForm.jsp");
    			
    		} else if (cmd.equals("login")) {
    			String username = request.getParameter("username");
    			String password = request.getParameter("password");
    			LoginReqDto dto = new LoginReqDto();
    			dto.setUsername(username);
    			dto.setPassword(password);
    			userSerivce.로그인(dto);
    			
    		} else if (cmd.equals("joinForm")) {
    			response.sendRedirect("user/joinForm.jsp");
    			
    		} else if (cmd.equals("join")) {
    			String username = request.getParameter("username");
    			String password = request.getParameter("password");
    			String email = request.getParameter("email");
    			String address = request.getParameter("address");
    			JoinReqDto dto = new JoinReqDto();
    			dto.setUsername(username);
    			dto.setPassword(password);
    			dto.setEmail(email);
    			dto.setAddress(address);
    			userSerivce.회원가입(dto);
    	}
    	}
    }​

6 Model에서 데이터를 받기위한 object를 만들었다면 실제로 DB와 데이터를 주고받는 DAO 생성

  • DAO를 보면 DB와 무엇을 할 지 잘 보여준다 
  • 회원가입이면 insert, 수정이면 update 등 말 그대로 DB와 연동하여 데이터를 주고 받고 하는 식.
public class UserDao {

	public void save() { //회원가입
	}
	public void update() { //수정
	}
	public void usernameCheck() { //아이디 중복 체크
	}
	public void findById() { //회원정보보기
	}
}

 

전체 구조 짜기가 끝이 났다. 요약해 보자면...

1) 필수 파일 및 세팅들을 끝난 후

2) DB연결 확인을 하고

3) 컨트롤러/서비스/모델 (그외 DTO/DAO 등) 등 필요 기능 추가