Java 백엔드 웹 기술의 발전과정에 따라서 순차적으로 적용시켜 볼 예정
서블릿 → JSP → MVC패턴 → 프론트 컨트롤러 패턴 → 스프링MVC
서블릿 방식
- 회원 등록 폼
@WebServlet(name= "memberFormServlet", urlPatterns = "/servlet/members/new-form")
public class MemberFormServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
//회원등록 Html 작성 부분
PrintWriter w = response.getWriter();
w.write("<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Title</title>\n" +
"</head>\n" +
"<body>\n" +
"<form action=\"/servlet/members/save\" method=\"post\">\n" +
" username: <input type=\"text\" name=\"username\" />\n" +
" age: <input type=\"text\" name=\"age\" />\n" +
" <button type=\"submit\">전송</button>\n" +
"</form>\n" +
"</body>\n" +
"</html>\n");
}
}
- 회원 등록 결과 저장 Servlet
@WebServlet(name = "memberSaveServlet", urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//회원등록한 정보를 저장하는 로직
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
//저장이 된 결과를 html로 응답해주는 로직
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter w= response.getWriter();
w.write("<html>\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
"</head>\n" +
"<body>\n" +
"성공\n" +
"<ul>\n" +
" <li>id="+member.getId()+"</li>\n" +
" <li>username="+member.getUsername()+"</li>\n" +
" <li>age="+member.getAge()+"</li>\n" +
"</ul>\n" +
"<a href=\"/index.html\">메인</a>\n" +
"</body>\n" +
"</html>");
}
}
- 저장된 모든 member들을 List로 보여주는 Html
@WebServlet(name = "memberListServlet", urlPatterns = "/servlet/members")
public class MemberListServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Member> members = memberRepository.findALl(); //멤버 객체 생성
response.setContentType("text/html"); //응답 설정
response.setCharacterEncoding("utf-8");
//저장된 member를 출력해주는 HTML부분
PrintWriter w = response.getWriter();
w.write("<html>");
w.write("<head>");
w.write(" <meta charset=\"UTF-8\">");
w.write(" <title>Title</title>");
w.write("</head>");
w.write("<body>");
w.write("<a href=\"/index.html\">메인</a>");
w.write("<table>");
w.write(" <thead>");
w.write(" <th>id</th>");
w.write(" <th>username</th>");
w.write(" <th>age</th>");
w.write(" </thead>");
w.write(" <tbody>");
//반복문을 통해서 저장된 member수만큼 출력
for (Member member : members) {
w.write(" <tr>");
w.write(" <td>" + member.getId() + "</td>");
w.write(" <td>" + member.getUsername() + "</td>");
w.write(" <td>" + member.getAge() + "</td>");
w.write(" </tr>");
}
w.write(" </tbody>");
w.write("</table>");
w.write("</body>");
w.write("</html>");
}
}
서블릿 방식의 문제점
- java코드만으로 HTML을 만들어야 하므로 매우 복잡, 비효율적
→ 템플릿 엔진의 등장한 이유 - 템플릿 엔진이란? - HTML 문서에서 필요한 곳만 코드를 적용해서 동적으로 변경
- 템플릿 엔진 : JSP, Thymeleaf, Freemarker, Velocity 등
JSP 방식
- Java언어를 기반으로 하는 Server Side 스크립트 언어
- HTML 코드에 Java언어를 넣어서 동적인 웹 페이지 생성
- Java코드에 HTML을 작성하는 비효율적인 문제를 개선
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
: 첫 줄은 JSP문서라는 뜻이다. JSP 문서는 이렇게 시작해야 한다.<%@ page import="hello.servlet.domain.member.MemberRepository" %>
: 자바의 import- 자바 코드 삽입 :
<% ~~ %>
- 자바 코드 출력 :
<%= ~~ %>
JSP 예제
- 회원 등록 폼
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!-- 상대경로 사용, [현재 URL이 속한 계층 경로 + /save] -->
<form action="save" method="post">
username: <input type="text" name="username"/>
age: <input type="text" name="age"/>
<button type="submit">전송</button>
</form>
</body>
</html>
- 회원 저장
- 회원 목록 조회
JSP방식의 문제점
- Java의 비즈니스 로직이 모두 JSP에 노출
- JSP가 비즈니스 로직 + 뷰 역할을 모두 담당
→ 규모가 커지면 유지보수가 힘들다 - 비즈니스 로직과 뷰를 따로 관리 하기위해 MVC패턴이 등장
MVC패턴
개요
- 변경의 라이프 사이클이 다르다
비즈니스 로직수정
/UI 수정
은 각각 다르게 발생할 가능성이 높고 서로에게 영향을 주지 않는다.- 변경의 라이프사이클이 다른 부분을 하나의 코드로 관리하는것은 유지보수에 좋지 않다.
- 기능 특화
- JSP같은 뷰 템플릿은 화면 렌더링에 최적화 되어있기 때문에 화면 렌더링 역할만 하는것이 가장 효과적이다.
MVC 패턴의 등장
Model
: View에 출력할 데이터를 담아두는 역할View
: Model에 담겨있는 데이터를 통해 화면에 렌더링 하는 역할Controller
: HTTP 요청 파라미터를 검증 / 비즈니스 로직 실행 / 결과데이터를 Model에 담기
MVC패턴 적용
- Servlet을 Controller로 사용
- JSP를 View로 사용
- HttpServletRequest를 Model로 사용 →
request.setAttribute()
,request.getAttribute()
메서드를 이용
예제
- 회원 등록 폼 요청
@WebServlet(name ="mvcMemberFormServlet", urlPatterns = "/servlet-mvc/members/new-form")
public class MvcMemberFormServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//viewPath의 경로에 있는 jsp파일을 Dispatcher에 넘겨서 요청
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
}
- /WEB-INF : 해당 경로에 존재하는 jsp 파일은 외부에서 접근할수 없고, dispatcher를 통해서만 접근이 가능하다.
- dispatcher : 다른 Servlet이나 JSP로 이동하는 기능을 담당
💡 Redirect 와 forward의 차이점?
redirect : 실제 클라이언트에 응답이 갔다가, 클라이언트가 redirect경로로 다시 요청 → url경로 변경 O
forward : 서버 내부에서 일어나는 호출 → url 경로 변경 X
- 회원 정보 저장 로직
@WebServlet(name = "mvcMemberSaveServlet", urlPatterns = "/servlet-mvc/members/save")
public class MvcMemberSaveServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member);
//Model에 데이터를 보관
request.setAttribute("member", member);
//view로 데이터 전달
String viewPath="/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
- 회원 리스트 조회
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMemberListServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Member> members = memberRepository.findALl();
request.setAttribute("members", members);
String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
MVC패턴의 문제점
- forward 부분의 중복 : view로 이동하는 코드가 중복 호출된다.
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
- viewPath 중복 : 모든 절대경로를 입력해야 하기 때문에 중복이 발생
String viewPath = "/WEB-INF/views/new-form.jsp";
- 사용하지 않는 코드 :
HttpServletRequest
/HttpServletResponse
객체를 사용하지 않아도 객체로 받는 경우가 있다. - 공통처리의 어려움 : 공통으로 중복되는 부분을 하나로 처리하지 못해서 중복되는 부분이 많이 발생
정리
- 공통부분을 효율적으로 처리하는 프론트 컨트롤러 패턴의 등장
반응형