인프런 김영한 님의 스프링 강의이며, 섹션 3 - 서블릿, JSP, MVC 패턴을 정리한다.
실습형 교육으로 서블릿으로 시작하여 개선해나가 MVC패턴까지 오는 게 이번 섹션 3의 목표다.
이번 시간은 간단히 코드만 보고 해당 코드의 불편한 점만 얘기하고 빠르게 넘어가겠다.
자세한 설명이 궁금하면 수강을 권장한다.
회원 관리 웹 애플리케이션 요구사항
회원 정보
이름 : 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;
}
}
기능 요구사항
- 회원 저장
- 회원 목록 조회
public class MemberRepository {
private Map<Long, Member> store = new HashMap<>();
private static long sequence = 0L;
// 싱글톤 사용
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() {
// store를 보호하기 위한 방법
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
}
}
JUnit 프레임워크를 통해 테스트를 해보자.
class MemberRepositoryTest {
MemberRepository memberRepository = MemberRepository.getInstance();
@AfterEach
void afterEach() {
memberRepository.clearStore();
}
@Test
public void save() throws Exception {
//given
Member member = new Member("hello", 20);
//when
Member savedMember = memberRepository.save(member);
//then
Member findMember = memberRepository.findById(savedMember.getId());
assertThat(findMember).isEqualTo(savedMember);
}
@Test
public void findAll() throws Exception {
//given
Member member1 = new Member("member1", 20);
Member member2 = new Member("member2", 30);
//when
Member savedMember1 = memberRepository.save(member1);
Member savedMember2 = memberRepository.save(member2);
List<Member> result = memberRepository.findAll();
//then
assertThat(result.size()).isEqualTo(2);
assertThat(result).contains(member1, member2);
}
}
@AfterEach를 사용하는 이유는 각 테스트 실행 결과로 저장된 데이터가 남아 다른 테스트에 영향을 끼치지 않기 위해서 데이터 삭제를 진행한다. 테스트 일관성을 지키기 위해서다.
서블릿으로 회원관리 웹 애플리케이션 만들기
이제 서블릿으로 웹을 만들어보자.
@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");
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");
}
}
저장과 멤버 내역 조회가 위처럼 비슷한 형태의 코드로 작성한다.
서블릿과 자바 코드만으로 HTML을 만들어봤다. w.write() 안에 수작업으로 하나하나 작성해야 하지만 중간에 잘못되면 찾기가 매우 힘들다.
매우 복잡하고 비효율적이다 보니 등장한게 템플릿 엔진이다. 템플릿 엔진으로 HTML 문서에 필요한 부분만 코드를 적용하여 동적으로 변경한다.
템플릿 엔진에는 JSP, Thymeleaf, Freemarker, Velocity등이 있지만, 현재 JSP는 사장되어간다. 타임리프를 권장한다.
JSP로 회원관리 웹 애플리케이션 만들기
이제 JSP로 만들어보자. gradle에 설정을 추가해준다.
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'
jsp 파일을 만든다.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
</body>
</html>
갓 생성된 뜨끈한 jsp 파일이다. jsp파일의 특징은 맨위에
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
이 코드가 필수적으로 들어간다.
회원 목록을 jsp 방식으로 변경해보자.
<%@ page import="hello.servlet.domain.member.MemberRepository" %>
<%@ page import="hello.servlet.domain.member.Member" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
MemberRepository memberRepository = MemberRepository.getInstance();
List<Member> members = memberRepository.findAll();
%>
<html>
<head>
<title>Title</title>
</head>
<body>
<a href="/index.html">메인</a>
<table>
<thead>
<th>id</th>
<th>username</th>
<th>age</th>
</thead>
<tbody>
<%
for (Member member : members) {
out.write(" <tr>"
+ "<td>" + member.getId() + "</td>"
+ "<td>" + member.getUsername() + "</td>"
+ "<td>" + member.getAge() + "</td>"
+ "</tr>");
}
%>
</tbody>
</table>
</body>
</html>
JSP는 자바 코드를 그대로 다 사용할 수 있다.
HTML 문서를 보면 상단에 서블릿 로직이 그대로 들어간 걸 볼 수 있다.
서블릿과 JSP의 한계
서블릿은 HTML 생성 작업이 자바 코드에 섞여 더럽고 복잡했다.
JSP을 사용해서 뷰를 HTML 가져가서 자바 코드가 깔끔해졌지만, JSP 자체에서 데이터를 저장하고 조회하고 그대로 HTML로 출력하는 등 역할이 너무 거대하다. (실무라면 유지보수 못하는 수준이 될 것이다.)
MVC 패턴의 등장
위와 같은 문제로 모델, 뷰, 컨트롤러로 분리하는 MVC 패턴이 등장한다.
'교육 및 인강 > 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 카테고리의 다른 글
MVC 프레임워크 만들기 - 프론트 컨트롤러 패턴 소개, 도입 (0) | 2021.07.05 |
---|---|
MVC 패턴 - 개요, 적용, 한계 (0) | 2021.06.29 |
서블릿(Servlet) - HttpservletResponse 기본 사용법, HTTP 응답 데이터 단순 텍스트 & HTML & API JSON (0) | 2021.06.28 |
서블릿(Servlet) - API 메시지 바디 : 단순 텍스트, JSON (0) | 2021.06.28 |
서블릿(Servlet) - HTTP 요청 데이터 : 개요, GET 쿼리 파라미터, POST HTML Form (0) | 2021.06.27 |