IT recording...
[스프링 MVC1] 3. 서블릿,JSP,MVC 패턴 본문
원문 링크
https://adorable-aspen-d23.notion.site/MVC1-3-JSP-MVC-272054e5d8d34abaa62293af7d98e8f4
김영한님의 [스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술] 강의를 듣고 작성한 글입니다.
1. 요구사항 분석
- 회원 관리 어플리케이션
- 회원 정보
- username, age
- 기능 정보
- 회원 저장
- 회원 목록 조회
- 회원 도메인 제작, 리포지토리 구성
@Getter
@Setter
public class Member {
private Long id;
private String username;
private int age;
public Member(){
}
public Member(String username, int age){
this.username = username;
this.age = age;
}
}
/**
* 동시성 문제가 고려되어 있지 않음, 실무에서는 ConcurrentHashMap, AtomicLong 사용 고려
*/
public class MemberRepository {
private static Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L; //id 하나씩 증가
//싱글톤으로 생성
private static final MemberRepository instance = new MemberRepository();
public static MemberRepository getInstance(){
return instance;
}
private MemberRepository(){}
public Member save(Member member){
member.setId(++sequence);
store.put(member.getId(),member);
return member;
}
public Member findById(Long id){
return store.get(id);
}
public List<Member> findAll(){
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear();
}
}
2. 서블릿으로 회원 관리 웹 어플리케이션 만들기
- 자바 코드로 html을 구성해야 하기 때문에 권장되지 않는다.
- 동적으로 html을 구성하기 위해 템플릿 엔진이 등장했다.
- 템플릿 엔진 : HTML문서에서 필요한 부분만 코드를 적용하여 동적으로 변경 가능
- JSP, Tymeleaf, Freemarker, Velocity 등
@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 {
//응답으로 http 응답이 나가야함
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");
}
}
3. JSP이용
- gradle 추가
//JSP 추가 시작
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'
//JSP 추가 끝
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
// request, response 사용 가능
MemberRepository memberRepository = MemberRepository.getInstance();
System.out.println("save.jsp");
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
System.out.println("member = " + member);
memberRepository.save(member);
%>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
성공
<ul>
<li>id=<%=member.getId()%></li>
<li>username=<%=member.getUsername()%></li>
<li>age=<%=member.getAge()%></li>
</ul>
<a href="/index.html">메인</a>
</body>
</html>
- jsp 안에서는 자바 코드를 그대로 사용 가능하다.
- 서블릿에서 HTML을 생성하는 부분을 자바 코드로 작성해야 했던 단점은 보완되었지만,
- 비즈니스 로직과 뷰가 분리되지 않는 단점이 존재한다.
- → 유지보수 어려움
4. MVC패턴
- 개요
- 너무 많은 역할
- 하나의 서블릿이나 jsp가 비즈니스 로직과 뷰 렌더링까지 가져가게 되면, 유지보수가 어렵다.
- 변경의 라이프사이클
- 결정적으로 비즈니스 로직과 뷰는 라이프 사이클이 다르다.
- 너무 많은 역할
- Model View Controller
- 컨트롤러
- HTTP 요청을 받아 파라미터를 검증하고, 비즈니스 로직을 실행한다.
- 뷰에 전달한 결과 데이터롤 조회해서 모델에 담는다.
- 모델
- 뷰에 출력할 데이터를 담아둔다.
- 뷰가 필요한 데이터를 모두 모델에 담아 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고, 화면을 렌더링 하는 일에 집중할 수 있다.
- 뷰
- 모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중한다.
- HTML 생성
- 적용
@WebServlet(name = "mvcMemberListServlet", urlPatterns = "/servlet-mvc/members")
public class MvcMembeListServlet extends HttpServlet {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Member> members = memberRepository.findAll();
//model에 담기
request.setAttribute("members",members);
String viewPath = "/WEB-INF/views/members.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>"%>
메인
id | username | age |
---|---|---|
${item.id} | ${item.username} | ${item.age} |
- redirect vs forward
- redirect
- 클라이언트에 응답이 나갔다가, redirect 경로로 다시 요청하는 것
- forward
- 서버 내부에서 일어나는 호출, 클라이언트는 알 수 없다.
- redirect
5. MVC패턴 한계
- 포워드 중복
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
- ViewPath 중복
String viewPath = "/WEB-INF/views/new-form.jsp";
prefix : /WEB-INF/views/ 부분
suffix : .jsp 부분
이 중복된다.
- 사용하지 않는 코드들
- request,response를 모두 사용하지 않는 경우가 많다.
- 공통 처리가 어렵다.
- 기능이 복잡해질수록 컨트롤러에서 공통으로 처리해야 하는 부분이 증가한다.
⇒ 프론트 컨틀롤러 패턴 도입
'Spring' 카테고리의 다른 글
[스프링 MVC1] 5. MVC 패턴 (0) | 2022.01.14 |
---|---|
[스프링 MVC1] 4. MVC 프론트 컨트롤러 패턴 (0) | 2022.01.14 |
[스프링 MVC1] 2. 서블릿 (0) | 2022.01.14 |
[스프링 MVC1] 1. 웹 애플리케이션 이해 (0) | 2022.01.14 |
[Spring] GithubAction + S3 + CodeDeploy + NginX를 이용한 무중단 배포 (0) | 2022.01.13 |
Comments