[스프링 MVC 1편] 서블릿, JSP, MVC 패턴 (1-서블릿)
by mini_min
회원 관리 웹 애플리케이션 개발
본격적으로 MVC 패턴을 들어가기 전에, 서블릿과 JSP 를 가지고 회원 관리 웹 애플리케이션을 만들어본다.
요구 기능 : 회원 저장, 회원 목록 조회
회원 정보 : 이름, 나이
회원 도메인 및 저장소 개발
✨ 회원 저장소는 싱글톤 패턴을 사용했다. (private) 스프링을 사용하면 스프링 빈으로 등록하면 되짐나, 최대한 순수 서블릿 만으로 구현하려는 목적으로 싱글톤 패턴을 사용했다.
싱글톤 패턴은 객체를 단 하나만 생성해서 공유해야하기 때문에 생성자를 private 접근자로 막았다.
package hello.servlet.domain.member;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class Member {
private Long id; //db에 저장하면 발급되는것
private String username;
private int age;
public Member() {
}
public Member(String username, int age) {
this.username = username;
this.age = age;
}
}
package hello.servlet.domain.member;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 동시성 문제가 고려되지 않음. 실무에서는 ConcurrentHashMap, AtomicLong 사용 고려
*/
public class MemberRepository {
private static 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(){
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear();
}
}
회원 저장소 테스트 코드
package hello.servlet.domain.member;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
class MemberRepositoryTest {
//싱글톤이라 new 생성 x
MemberRepository memberRepository = MemberRepository.getInstance();
@AfterEach
void afterEach(){
memberRepository.clearStore();
}
@Test
void save(){
//given
Member member = new Member("hello", 20);
//when
Member saveMember = memberRepository.save(member);
//then
Member findMember = memberRepository.findById(saveMember.getId());
assertThat(findMember).isEqualTo(saveMember);
}
@Test
void findAll(){
//given
Member member1 = new Member("member1", 22);
Member member2 = new Member("member2", 30);
memberRepository.save(member1);
memberRepository.save(member2);
//when
List<Member> result = memberRepository.findAll();
//then
assertThat(result.size()).isEqualTo(2);
assertThat(result).contains(member1,member2);
}
}
서블릿으로 회원 관리 웹 애플리케이션 만들기
서블릿 회원 등록 폼부터 만든다.
package hello.servlet.web.servlet;
import hello.servlet.domain.member.MemberRepository;
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 java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "memberFormServlet", urlPatterns = "/servlet/members/new-form")
public class MemberFormServlet extends HttpServlet {
//private 으로 막은 memberRepository
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" );
w.write("</html>");
}
}
다음으로 회원 정보를 저장하는 서블릿을 만든다.
package hello.servlet.web.servlet;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
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 java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "memberSaveServlet", urlPatterns = "/servlet/members/save")
public class MemberSaveServlet extends HttpServlet {
//private 으로 막은 memberRepository
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("MemberSaveServlet.service");
String username = request.getParameter("username");
int age = Integer.parseInt(request.getParameter("age"));
Member member = new Member(username, age);
memberRepository.save(member); //멤버 저장
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" +
"<ul>" +
"<li>id="+member.getId()+"</li>\n" +
"<li>username="+member.getUsername()+"</li>\n" +
"<li>age="+member.getAge()+"</li>\n" +
"</ul>" +
"<a href=\"/index.html\">메인</a>\n" +
"</body>\n" );
w.write("</html>");
}
}
이번에는 저장된 모든 회원을 조회하는 기능을 만든다.
package hello.servlet.web.servlet;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
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 java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
@WebServlet(name = "memberListServlet", urlPatterns = "/servlet/members")
public class MemberListServlet extends HttpServlet {
//private 으로 막은 memberRepository
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");
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>");
/*
w.write(" <tr>");
w.write(" <td>1</td>");
w.write(" <td>userA</td>");
w.write(" <td>10</td>");
w.write(" </tr>");
*/
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>");
}
}
이렇게 서블릿과 자바 코드 만으로 HTML 을 만들 수 있다. 서블릿 덕분에 동적으로 원하는 HTML 을 만들었다!
그러나, 이렇게 짠 코드는 매우 복잡하고 비효율적인 코드다. HTML 문서만을 두고 동적으로 변경해야 하는 부분만 자바 코드로 변경하도록 짜면 더 편리해진다.
💫 이러한 복잡함과 비효율성으로 템플릿 엔진이라는 것이 등장한다. 템플릿 엔진을 사용하면 HTML 문서에 필요한 곳만 코드를 적용해서 동적으로 변경할 수 있다.
템플릿 엔진에는 JSP, Thymeleaf, Freemarker, Velocity 등이 있다.
다음으로 JSP 투비컨티뉴...
'Spring' 카테고리의 다른 글
[스프링 MVC 1편] MVC 프레임워크 만들기 (1) (0) | 2023.06.27 |
---|---|
[스프링 MVC 1편] 서블릿, JSP, MVC 패턴 (2-MVC) (0) | 2023.06.27 |
[스프링 MVC 1편] 서블릿 개요 (기본정보) (0) | 2023.06.20 |
[스프링 MVC 1편] 웹 애플리케이션 이해 (0) | 2023.06.13 |
[Spring 핵심원리 기본편] 웹 스코프 (0) | 2023.05.31 |
블로그의 정보
개발자 미니민의 개발로그
mini_min