[Spring] ์คํ๋ง MVC 1 - Servlet
๐กRefferecne [์ธ๋ถ ๋งํฌ]์คํ๋ง MVC 1ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์
- Spring MVC 1 - Servlet
1. ๊ฐ์
์คํ๋ง ํ๋ ์์ํฌ๊ฐ ์๋ ์์ ๋ก ๋์๊ฐ์ ์ด๋ป๊ฒ ์ฌ์ฉ์๊ฐ ์์ฒญํ ํ์ด์ง๋ฅผ ์ฐพ์๋ด๊ณ ํ์ํ ๋ฐ์ดํฐ(Payload) ๋ฅผ ๊ฐ๊ณตํ์ฌ ์ฒ๋ฆฌ, ์๋ตํ์๋์ง ์์๋ณด์. ๋ํ ์คํ๋ง ํ๋ ์์ํฌ์ ํต์ฌ์ ์ธ ์ญํ ์ ํ์ ํ๊ธฐ ์ํด ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ํํ์ ๋๋ง์ ํ๋ ์์ํฌ๋ฅผ ์ง์ ์ ์ํด๋ณด์.
2. Servlet
์ฐ์ ๋ค์ ๋ ๊ฐ์ง ์ฉ์ด๋ฅผ ์ ๋ฆฌํ๊ณ ๋์ด๊ฐ์.
- Web Server
- ์ ์ ๋ฆฌ์์ค ํ์ผ์ ์ ๊ณต
- ์ ๋ค์ด๋์ง ์๊ณ ๋น์ฉ์ด ์ ์
- Nginx, Apache ๋ฑ
- WAS (Web Application Server)
- ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ์ด์ฉํ์ฌ ๋์ ์ธ ๋ฐ์ดํฐ ๋ฐํ (์ ์ ๋ฆฌ์์ค๋ ์ ๊ณตํ ์ ์์)
- ํ๋ก๊ทธ๋จ ์ฝ๋๋ฅผ ์คํ (JAVA์ ๊ฒฝ์ฐ Servlet)
- ๋ค์ด ๋น๋๊ฐ ๋๊ณ ๋น์ฉ์ด ๋น์
- Tomcat, Jetty ๋ฑ
[Servlet ์ด๋?]
์๋๋๋ก๋ผ๋ฉด ๊ฐ๋ฐ์๋ HTTP ํต์ ์ ์ํด ๋ค์๊ณผ ๊ฐ์ ์์ ๋ค์ ํด์ผ ํ๋ค.
- ์์ผ ์ฐ๊ฒฐ
- ์ ๋ฌธ ํ์ฑ
- ํค๋ ํ์ธ
- ์์ ์์น ํ์ธ
- ๋น์ง๋์ค ๋ก์ง ์คํ
- ์๋ต ์ ๋ฌธ ์์ฑ
- ์์ผ ์ข ๋ฃ
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ๊ณผ์ ๋ค์ ๋ชจ๋ ํต์ ๋ง๋ค ์ง์ฝ์ ์ผ๋ก ๊ด๋ฆฌ/๋ฐ๋ณต ํด์ฃผ๋ ๊ฒ์ ์์ฐ์ฑ์ด ๋งค์ฐ ๋จ์ด์ง๋ ์์
์ด ๋ ๊ฒ์ด๋ค.
์ด๋ฅผ ์ํด Servlet ์์๋ ์์ฒญ๊ณผ ์๋ต์ Request
์ Response
๋ก ์ถ์ํ ํ์ฌ ๊ฐ๋ฐ์๊ฐ ๋น์ง๋์ค ๋ก์ง ์์ฒด์ ์ง์คํ๋๋ก ๋์์ค๋ค.
์์ WAS๊ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ์ด์ฉํ์ฌ ์ฌ์ฉ์์ ์์ฒญ์ ๋ํด ๋์ ์ผ๋ก ์๋ต์ ๋ฐํํ๋ค๊ณ ํ์๋ค.
์ด ๋ JAVA ๋ฅผ ์ด์ฉํ์ฌ ์ฌ์ฉ์์ ์์ฒญ์ ์๋ตํ๊ธฐ ์ํ ์ปดํฌ๋ํธ๊ฐ ๋ฐ๋ก Servlet
์ด๋ค.
ํ๋์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ๋ฌ๊ฐ์ ์์ฒญ์ ๋ฐ์ ์ ์์ผ๋ฏ๋ก (ํ์๊ฐ์ ์์ฒญ, ๊ฒ์๊ธ ์กฐํ ์์ฒญ ๋ฑ) ๋ณต์ ๊ฐ์ ์๋ธ๋ฆฟ์ WAS ์ ๋ฑ๋กํ๊ณ ๊ด๋ฆฌํ ํ์๊ฐ ์๋ค. ์ด์ฒ๋ผ ๋ณต์์ ์๋ธ๋ฆฟ์ ์์ฉํ๋ฉฐ ์ง์ํ๋ ํฐ์บฃ๊ณผ ๊ฐ์ WAS ๋ฅผ ์๋ธ๋ฆฟ ์ปจํ ์ด๋๋ผ๊ณ ํ๋ค.
์๋ธ๋ฆฟ ์ปจํ ์ด๋๊ฐ ํ๋ ์์ธํ ์ญํ ๋ค์ ๋ค์๊ณผ ๊ฐ๋ค.
- ๊ฐ ์์ฒญ์ ๋ํ ์ฐ๋ ๋ ์์ฑ ๋ฐ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ
- ์์ฒญ๋ฐ์ ์์ ์์น์ ์๋ธ๋ฆฟ ๋งคํ (URL ๋งคํ)
- ์๋ธ๋ฆฟ ์๋ช ์ฃผ๊ธฐ ๊ด๋ฆฌ (์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌ ๋จ)
์ฌ๊ธฐ์ ์๋ธ๋ฆฟ์ ์๋ช
์ฃผ๊ธฐ ๊ด๋ฆฌ์ ๋ํด ์กฐ๊ธ ๋ ์์ธํ ์์๋ณด์๋ฉด, ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ํน์ ์๋ธ๋ฆฟ์ ๋ก์ง์ ์ํํด๋ฌ๋ผ๋ ์์ฒญ์ ๋ฐ๊ณ ๋ ๋ค ํด๋น ์๋ธ๋ฆฟ์ด ์ด๊ธฐํ(์ธ์คํด์ค ์์ฑ) ๋์ด์์ง ์๋ค๋ฉด init()
๋ฉ์๋๋ฅผ ์คํํ์ฌ ์ธ์คํด์ค๋ฅผ ์์ฑํ์ฌ ๊ด๋ฆฌํ๊ณ , ์ด๋ฏธ ์์ฑ ๋ ์ธ์คํด์ค๊ฐ ์กด์ฌํ๋ค๋ฉด ์๋ธ๋ฆฟ์ service()
๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋น์ง๋์ค ๋ก์ง์ ์ํํ๋ค.
์ด ๋ ์๋ธ๋ฆฟ ๋ด์์ ์ด๋ค HTTP ๋ฉ์๋๋ฅผ ์ฒ๋ฆฌํ ์ง ๋ถ๊ธฐํ ์ ์๋ค. ์์ฑ ๋ ์๋ธ๋ฆฟ์ ์์๋ก ์ข
๋ฃํ์ง ์์ผ๋ฉด ํฐ์บฃ์ด ์ข
๋ฃ๋ ๋ destroy()
๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ์ข
๋ฃํ๋ค.
[Servlet ์๋ช ์ฃผ๊ธฐ]
์๋ธ๋ฆฟ์ ๋ํ ์์ฒญ์ด ๋ฐ์ํ๋ฉด ์๋ธ๋ฆฟ ์ปจํ ์ด๋๋ ์ฐ์ ํด๋น ์๋ธ๋ฆฟ์ด ์์ฑ(์ธ์คํด์ค ํ) ๋์๋์ง ํ์ธํ๋ค.
์์ฑ ๋ ์๋ธ๋ฆฟ์ด ์กด์ฌํ์ง ์๋๋ค๋ฉด init()
๋ฉ์๋๋ฅผ ์คํํ์ฌ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
์๋ธ๋ฆฟ์ ์ฑ๊ธํค์ผ๋ก ๊ด๋ฆฌ๋๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด์ ๋ง๋ค์ด์ง ์๋ธ๋ฆฟ์ด ์กด์ฌํ๋ค๋ฉด service()
๋ฉ์๋๋ก ๋น์ง๋์ค ๋ก์ง๋ง์ ์ํํ๋ค.
๋ง๋ค์ด์ง ์๋ธ๋ฆฟ๋ค์ ํฐ์บฃ ์ข
๋ฃ ์ destroy()
๋ฅผ ํธ์ถํ์ฌ ์ข
๋ฃํ๋ค.
[Servlet ์ง์ ์ฌ์ฉํ๊ธฐ]
์ด์ ๋ถํฐ ์๋ธ๋ฆฟ์ ์ง์ ์ฌ์ฉํ์ฌ ์์ฒญ์ ์๋ตํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด๋ณด์. ์ฐ์ start.spring.io Spring Web ๋ฐ Lombok ์ ๋ ์ถ๊ฐํ์ฌ ํ๋ก์ ํธ๋ฅผ ์ธํ ํ๋ค. (gradle, Java 11, Spring 2.7.x, war)
SpringBoot ์์๋ ๋ฉ์ธ ์คํ ์ง์ ์ @SpringBootApplication
์ ๋
ธํ
์ด์
์์ @ServletComponentScan
์ ๋
ธํ
์ด์
์ ์ถ๊ฐํด์ฃผ๋ ๊ฒ์ผ๋ก ์๋ธ๋ฆฟ ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํ ์ ์๋๋ก ์ค์ ํ๋ค.
1
2
3
4
5
6
7
@ServletComponentScan
@SpringBootApplication
public class FrameworkApplication {
public static void main(String[] args) {
SpringApplication.run(FrameworkApplication.class, args);
}
}
์ฒซ๋ฒ์งธ ์๋ธ๋ฆฟ ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด @WebServlet
์ ๋
ธํ
์ด์
์ ์ถ๊ฐํด์ฃผ๊ณ HttpServlet
์ถ์ ํด๋์ค๋ฅผ ์์๋ฐ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ธ๋ฆฟ์ ๋น์ง๋์ค ๋ก์ง ์คํ๋ถ์ธ service()
๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ ํ์ฌ ๋ก์ง์ ๊ตฌํํ๋ค.
์ฐ์ ๊ฐ๋จํ๊ฒ ์์ฒญ๊ณผ ์๋ต ์ ๋ณด, ์ฟผ๋ฆฌ์คํธ๋ง ํ๋ผ๋ฏธํฐ ์ ๋๋ฅผ ์ถ๋ ฅํด๋ณด์. ์๋ธ๋ฆฟ์ ์๋ต์ ์ ๋ฌํ ๋์๋ response ๊ฐ์ฒด์ ์ง์ ์๋ต ๋ด์ฉ์ ์์ฑํ๋ฉด ๋๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Slf4j
@WebServlet(name = "hello", urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
log.info("HelloServlet.service");
log.info("request : {}", request);
log.info("response: {}", response);
String parameter = request.getParameter("parameter");
log.info("parameter : {}", parameter);
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.getWriter().write("response :" + parameter);
}
}
1
2
3
4
2023-10-19 14:43:07.538 INFO 7851 --- [nio-8080-exec-3] me.jwjung.framework.basic.HelloServlet : HelloServlet.service
2023-10-19 14:43:07.538 INFO 7851 --- [nio-8080-exec-3] me.jwjung.framework.basic.HelloServlet : request : org.apache.catalina.connector.RequestFacade@7d506757
2023-10-19 14:43:07.538 INFO 7851 --- [nio-8080-exec-3] me.jwjung.framework.basic.HelloServlet : response: org.apache.catalina.connector.ResponseFacade@17537908
2023-10-19 14:43:07.539 INFO 7851 --- [nio-8080-exec-3] me.jwjung.framework.basic.HelloServlet : parameter : hello
3. Servlet ํ์ฉ
์ด์ ๋ถํฐ ๋ณธ๊ฒฉ์ ์ผ๋ก ์๋ธ๋ฆฟ์ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ ํ์๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด ๋ณผ ์์ ์ด๋ค. ์๋ธ๋ฆฟ์ MVC ํจํด์์ ์ปจํธ๋กค๋ฌ ์ญํ ์ ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ฉ์ธ์ ๋ด๋นํ ํ์๊ณผ ํ์๊ฐ์ฒด์ ๋ํ ์ ์ฅ์๋ฅผ ๋จผ์ ๊ตฌํํด๋ณด์.
- ํ์ ๊ฐ์ฒด
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Getter
@EqualsAndHashCode
public class Member {
private long id;
private String name;
private int age;
private Member() {};
public Member(String name, int age) {
this.name = name;
this.age = age;
}
}
์์ด๋, ์ด๋ฆ, ๋์ด๋ฅผ ๊ฐ์ง ๊ฐ๋จํ ํ์ ๊ฐ์ฒด๋ฅผ ์์ฑ ํ๋ค. ๋ค์์ผ๋ก ์ ์ฅ, ์กฐํ์ ๋๋ฅผ ์ง์ํ๋ ์ ์ฅ์ ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ณด์.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MemberRepository {
private static Map<Long, Member> store = new ConcurrentHashMap<>();
private static AtomicLong sequence = new AtomicLong(0L);
@Getter
private static MemberRepository instance = new MemberRepository();
public void save(Member member) {
setIdWithReflection(member);
store.put(member.getId(), member);
}
private void setIdWithReflection(Member member) {
try {
Class<Member> memberClass = Member.class;
Field id = memberClass.getDeclaredField("id");
id.setAccessible(true);
id.set(member, sequence.incrementAndGet());
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException("Reflection Exception", e);
}
}
public Member findById(Long id) {
return store.get(id);
}
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore() {
store.clear();
}
}
๋ท๋จ์ ๋น์ง๋์ค ๋ก์ง์ด ์์ฑ๋์์ผ๋ฏ๋ก ์ด์ ํด๋ผ์ด์ธํธ๊ฐ ์ง์ ํธ์ถ ํ view ๋ฅผ ์ ๊ณตํด์ผ ํ๋ค.
์ฐ์ ์ HTML ์ ์ด์ฉํ์ฌ ๊ฐ๋จํ ํผ์ ํตํด ๊ฐ์ ์ ์ฒ๋ฆฌ ํ ์์ ์ด๋ฏ๋ก HTML Form ์ ์ ๊ณตํ๋ ์๋ธ๋ฆฟ์ ์์ฑํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Slf4j
@WebServlet(name = "memberFormServlet", urlPatterns = "/servlet/members/new-form")
public class MemberFormServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter w = response.getWriter();
StringBuilder htmlBuilder = new StringBuilder();
String html = htmlBuilder
.append("<!DOCTYPE html>\n")
.append("<html>\n")
.append("<head>\n")
.append(" <meta charset=\"UTF-8\">\n")
.append(" <title>Title</title>\n")
.append("</head>\n")
.append("<body>\n")
.append("<form action=\"/servlet/members/save\" method=\"post\">\n")
.append(" username: <input type=\"text\" name=\"username\" />\n")
.append(" age: <input type=\"text\" name=\"age\" />\n")
.append(" <button type=\"submit\">์ ์ก</button>\n")
.append("</form>\n")
.append("</body>\n")
.append("</html>\n").toString();
w.write(html);
}
}
๋จผ์ ์์ฑํด ๋ณธ ์๋ธ๋ฆฟ๊ณผ ๋์ผํ๊ฒ html ๋ด์ฉ์ ๋ฌธ์์ด๋ก ์์ฑํ์ฌ response ๊ฐ์ฒด์ ๋ฐํํด์ฃผ๋ฉด ๋๋ค.
๋ค์์ผ๋ก form ์ post ์์ฒญ์ ์ฒ๋ฆฌํด ์ค ์๋ธ๋ฆฟ๋ ํ๋ ์์ฑํ์.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@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);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter w = response.getWriter();
StringBuilder htmlBuilder = new StringBuilder();
String html = htmlBuilder
.append("<!DOCTYPE html>\n")
.append("<html>\n")
.append("<body>\n")
.append("์ฑ๊ณต\n")
.append("<ul>")
.append(" <li>id=" + member.getId() + "</li>\n")
.append(" <li>username=" + member.getName() + "</li>\n")
.append(" <li>age=" + member.getAge() + "</li>\n")
.append("</ul>\n")
.append("</body>\n")
.append("</html>").toString();
w.write(html);
}
}
์ด๋ก์จ Servlet ์ ํ์ฉํ ์ฐ๋ฆฌ์ ์ฒซ๋ฒ์งธ ๋ณต์กํ(?) ๋น์ง๋์ค ๋ก์ง์ด ์์ฑ๋์๋ค. ๐
[๋ฌธ์ ์ ๋ค]
์๋ธ๋ฆฟ์ ํตํด ๋น์ง๋์ค ๋ก์ง์ ๊ตฌํํ๋ฉด์ HTTP ์คํ์ ์ถ์ํ ํ์ฌ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์๋ ์๊ฒ ๋์์ง๋ง, ์๋ธ๋ฆฟ ํ๋์ ํ๋ฉด๊ณผ ๋น์ง๋์ค ๋ก์ง์ด ํตํฉ๋์ด ์์ผ๋ฏ๋ก ์ง์์ ์ธ ๊ฐ๋ฐ์ ๋ถํธํ ์ ๋ค์ด ๋ช๊ฐ์ง ์กด์ฌํ๋ค.
- Java ๋ฌธ์์ด ํ์ ์ผ๋ก HTML ์ ๊ด๋ฆฌํ๋ฏ๋ก ๋์ ์ธ HTML ์ ๊ทธ๋ฆฌ๊ธฐ๊ฐ ํ๋ค๋ค.
- ํ๋ฉด์ ๋ณ๊ฒฝํ๋๋ฐ ์๋น์ค ๋ก์ง์ด ์๋ก ๋น๋๋๊ฑฐ๋, ์๋น์ค ๋ก์ง์ ๋ณ๊ฒฝํ๋๋ฐ ํ๋ฉด๋ ๊ฐ์ด ๋น๋๊ฐ ๋์ด์ผ ํ๋ค.
- ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ง๋ค.
๊ฒฐ๊ตญ ์ด๋ ํ๋ฉด(View)๊ณผ ์๋น์ค(Service)์ ์ฑ ์์ด ๋ถ๋ฆฌ๋์ง ์์์ ๋ฐ์ํ๋ ์ผ๋ก, ์ด๋ฅผ ๋ถ๋ฆฌํ๊ธฐ ์ํด ํ ํ๋ฆฟ ์์ง ์ ์ฌ์ฉํ๋ค. ์ต๊ทผ์๋ ์คํ๋ง ์ง์์์ ๋ํ์ ์ธ ํ ํ๋ฆฟ ์์ง์ผ๋ก ํ์๋ฆฌํ๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋น์์๋ JSP ๋ฅผ ๋ง์ด ์ฌ์ฉํ์์ผ๋ฏ๋ก ์ด๋ฒ ํ๋ก์ ํธ์์๋ JSP ๋ฅผ ์ด์ฉํด๋ณด์.
4. JSP
์ฐ์ Spring Boot ํ๋ก์ ํธ์์ JSP ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ build.gradle ์ ๋ค์ ์์กด์ฑ๋ค์ ์ถ๊ฐํด์ผ ํ๋ค.
1
2
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'
๊ทธ๋ฆฌ๊ณ ๋ ์์์ ๋ฌธ์์ด๋ก ๊ด๋ฆฌํ๋ HTML ์์ค๋ฅผ JSP ํ์ผ๋ก ์ฎ๊ฒจ๋ณด์.
- ํ์๊ฐ์ ์์
1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/jsp/members/save.jsp" method="post">
username: <input type="text" name="username"/>
age: <input type="text" name="age"/>
<button type="submit">์ ์ก</button>
</form>
</body>
</html>
- ํ์๊ฐ์ ์๋ฃ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ page import="me.jwjung.framework.basic.domain.member.MemberRepository" %>
<%@ page import="me.jwjung.framework.basic.domain.member.Member" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
//request, response ์ฌ์ฉ ๊ฐ๋ฅ
MemberRepository memberRepository = MemberRepository.getInstance();
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.getName()%></li>
<li>age=<%=member.getAge()%></li>
</ul>
</body>
</html>
ํด๋น jsp ํ์ผ๋ค์ main/webapp/ ํ์ ๊ฒฝ๋ก์ ์์น์ํค๊ณ ํ์ฅ์๋ฅผ ํฌํจํ์ฌ ํธ์ถํ ์ ์๋ค.
์) localhost:8080/jsp/members/new-form.jsp
5. MVC ํจํด
[๋ฑ์ฅ ๋ฐฐ๊ฒฝ]
jsp ํ์ผ์ HTML ์ฝ๋ ๋ฐ ๋ช๊ฐ์ง ๋น์ง๋์ค ๋ก์ง์ ์ด๊ดํ ๊ฒฐ๊ณผ ๋์ ์ผ๋ก HTML ์ ๊ทธ๋ฆฌ๋ ๋ฌธ์ ๋ ํด๊ฒฐ๋์๋ค. ํ์ง๋ง ๋์์ด servlet ์ฝ๋์์ jsp ๋ก ์ฎ๊ฒจ์์ ๋ฟ HTML ์ฝ๋์ ๋น์ง๋์ค ๋ก์ง, ํนํ ์ ์ฅ์๋ฅผ ์ค๊ณ ๊ฐ๋ ๋ก์ง๊น์ง ๋๋ฌด ๋ง์ ์ญํ ์ ํ์ชฝ(JSP) ์์ ๋ด๋นํ๊ณ ์์ผ๋ฏ๋ก ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๋ค์ ์ฌ์ ํ ํด๊ฒฐ๋์ง ์์๋ค.
- ์ฌ์ ํ ํ ์ชฝ์ ์ฝ๋๊ฐ ๋๋ฌด ๊ธธ์ด์ง ์ ์์ ๋ฟ๋๋ฌ, ์ฐ๊ด ์๋ ๋ ์ด์ด์ ์ฝ๋๋ค์ด ํผ์ฌํด์๋ค.
- View ์ ๋น์ง๋์ค ๋ก์ง์ ๋ณ๊ฒฝ์ ๋ผ์ดํ์ฌ์ดํด ์ด ์๋ก ๋ค๋ฅด๋ค๋ ์ ์ด๋ค. ๋ฐ๊ฟ ๋งํ์๋ฉด ๋น์ง๋์ค ๋ก์ง๋ฅผ ์์ ํ๋ ์ฃผ๊ธฐ์ ํ๋ฉด์ ๋ณ๊ฒฝํด์ผ ํ๋ ์ฃผ๊ธฐ๊ฐ ์์ ํ ์ผ์นํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค.
- ๋ฐ์ดํฐ๋ฅผ ๋์ ์ผ๋ก ์ถ๋ ฅํ๋ ๋ฐ์ ํนํ๋์ด ์๋ ๊ฒ์ด ํ ํ๋ฆฟ ์์ง์ด์ง๋ง ๋๋ฌธ์ ๊ฐ์ ์ํ๋ ๊ธฐ๋ฅ๋ง ๋งก์์ ํ ์๊ฐ ์๋ค.
์ด๋ฐ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ๊ธฐ ์ํด ๊ตฌ์กฐ์ ๊ฐ์ ๋ฐฉ์์ผ๋ก MVC ํจํด์ด ๋ฑ์ฅํ๊ฒ ๋๋ค.
[MVC ํจํด ๊ตฌ์กฐ]
MVC ํจํด์๋ ๋ค์๊ณผ ๊ฐ์ ์์๋ค์ด ํ์ํ๋ค.
Controller
HTTP ํต์ ์ ์ฐฝ๊ตฌ๊ฐ ๋๋ฉฐ, ํ๋ฉด์ ์ ๋ฌํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๋ค. ์ด๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ฑฐ๋ ์กฐํํ๋ ๋ฑ์ ๋ณต์กํ ๋น์ง๋์ค ๋ก์ง์ ์ญํ ์ ๋ค์ ๋ถ์ฐํ๊ธฐ ์ํด ์๋น์ค ๋ ์ด์ด์ ์์ํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค. ์ปจํธ๋กค๋ฌ๋ Model
์ ์๋ต ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ์ฌ ์ ๋ฌํ๋ ์ญํ ๋ง์ ์ํํ๋ค.
View
์์ JSP ์ ๊ฐ์ด Model ์ ํตํด ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๋ ฅํ๋ค. ์ด ๋, ๋์ ์ผ๋ก ํ๋ฉด์ ๋ ๋๋ง ํ ์ ์๋๋ก ํ
ํ๋ฆฟ ์์ง์์ ์ฌ๋ฌ ๊ธฐ๋ฅ์ ์ง์ํ๋ค.
Model
Controller ์ View ์ฌ์ด์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๊ธฐ ์ํ ๋งค๊ฐ์ฒด ์ญํ ์ ํ๋ค.
[MVC ํจํด ์ ์ฉ]
์์ ์์ฑํ ์ฝ๋๋ค์ MVC ํจํด์ ๋ง์ถฐ ๋ณ๊ฒฝํด๋ณด์. ์ฐ์ MemberFormServlet
์ MVC ์ญํ ์ ๋ง๊ฒ ๋ทฐ์ ์ฐ๊ฒฐํด์ค๋ค. ์ด๋, ์๋ก ๋ง๋ค jsp ํ
ํ๋ฆฟ์ WEB-INF ํ์ ๊ฒฝ๋ก์ ์์น์์ผ์ค๋ค. WEB-INF ํ์ ์์๋ค์ ๊ธฐ์กด์ฒ๋ผ ๊ฒฝ๋ก๋ง ์
๋ ฅํ์ฌ ์ฌ์ฉ์๊ฐ ์ ๊ทผํ๋ ๊ฒ์ ๋ง์ ์ ์๋ค. ์ฆ, ๋ฌด์กฐ๊ฑด ์ปจํธ๋กค๋ฌ๋ฅผ ํตํด ๋ฐํ๋์ด์ผ ํ๋ค.
1
2
3
4
5
6
7
8
9
10
11
@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 {
String viewPath = "/WEB-INF/views/new-form.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
}
์๋ธ๋ฆฟ์ ์ด์ view ์ ๊ฒฝ๋ก๋ง dispatcher ๋ฅผ ํตํด ๋๊ฒจ์ค๋ค. dispatcher.forward()
๋ฉ์๋๋ redirect ์ ๋ค๋ฅด๊ฒ ์๋ฒ ๋ด์์ ์ฌํธ์ถ์ด ์ผ์ด๋๋ฏ๋ก ํด๋ผ์ด์ธํธ๊ฐ ํธ์ถ์ด ๋ณ๊ฒฝ๋ ๊ฒ์ ์ธ์งํ์ง ๋ชปํ๋ค.
๋ค์์ผ๋ก ๊ธฐ์กด์ /members/new-form.jsp ํ์ผ์ ๋ณต์ฌํด์ WEB-INF ํ์์ ์ ๋นํ ๊ฒฝ๋ก๋ก ์ฎ๊ฒจ์ฃผ๊ณ , Form ํ๊ทธ ๋ด์ action ์์ฑ ๊ฒฝ๋ก๋ฅผ ์ ๋๊ฒฝ๋ก๋ก ๋ณ๊ฒฝํด์ค๋ค. ์ด๋ ๊ฒ ์๋ ๊ฒฝ๋ก๋ก ๋ณ๊ฒฝํ๋ฉด ํ์ฌ url ๊ฒฝ๋ก์์ ๊ณ์ธต ๊ฒฝ๋ก๋ฅผ ์ ์งํ์ฑ ๋ง์ง๋ง ์์ ์์น๋ง ๋ณ๊ฒฝ๋๋ค.
- ๊ธฐ์กด Url: /servlet-mvc/members/new-form
- ์ด๋ Url: /servlet-mvc/members/save
1
2
3
4
5
<form action="save" method="post">
username: <input type="text" name="username"/>
age: <input type="text" name="age"/>
<button type="submit">์ ์ก</button>
</form>
๋ค์์ผ๋ก ์ ์ฅ์ ์ค์ ๋ก ์คํํ๋ ์๋ธ๋ฆฟ๋ MVC ํจํด์ ์ ์ฉํด๋ณด์.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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);
System.out.println("member = " + member);
memberRepository.save(member);
//Model ์ ์ ์ฅ๋ ๋ฐ์ดํฐ ์ ์ฅ
request.setAttribute("member", member);
String viewPath = "/WEB-INF/views/save-result.jsp";
RequestDispatcher dispatcher = request.getRequestDispatcher("viewPath");
dispatcher.forward(request, response);
}
}
์๋ธ๋ฆฟ์ด ๋น์ง๋์ค ๋ก์ง๋ง์ ๋ค๊ณ ๊ฐ๊ณ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ Model ์ ํตํด view ๋ก ๋๊ธฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ด์ view ์์๋ ๋์ด์จ model ์ ๋ฐ์ดํฐ๋ฅผ ๋จ์ํ ๋ ๋๋ง ํ๋ ์ญํ ๋ง์ ์ํํ๋ฉด ๋๋ค. ๋ค์ ์ฝ๋๋ฅผ ๋ณด์
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta charset="UTF-8">
</head>
<body> ์ฑ๊ณต
<ul>
<li>id=${member.id}</li>
<li>username=${member.username}</li>
<li>age=${member.age}</li>
</ul>
<a href="/index.html">๋ฉ์ธ</a>
</body>
</html>
model ์ ๊ฐ์ el ํํ์์ผ๋ก ๊ฐ์ ธ์ ๋ ๋๋ง ํด์ฃผ๋ ์ ๋ ์ด์ธ์ ๋ก์ง์ ์ ๋ถ ์ ๊ฑฐ๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
[ํ๊ณ]
MVC ํจํด์ ์ ์ฉํจ์ผ๋ก์จ ์ด๊ธฐ ๋ฌธ์ ์๋ ์ญํ ์ด ๋ถ์ฐ๋์ง ๋ชปํ๋ ๋ฌธ์ ๋ฅผ ์ด๋์ ๋ ํด๊ฒฐํ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ํ์ง๋ง ์์ง ๋ช ๊ฐ์ง ๋ฌธ์ ์ ๋ค์ด ๋จ์์๋ค.
- ์ค๋ณต๋๋ ์ฝ๋๋ค
dispatcher.forward()
ํธ์ถ์ด๋, viewPath ์ ์ธ ๋ฑ, ์ปจํธ๋กค๋ฌ๋ณ๋ก ์ค๋ณต๋๋ ์ฝ๋๋ค์ด ์ฌ์ ํ ๋ง์ด ๋จ์์๋ค.
- viewPath ๋ฅผ ๋ค๋ฃจ๋ ๋ฐฉ์
- ์ ์ฒด๊ฒฝ๋ก์ ํ์ฅ์๋ฅผ ๋ฌธ์์ด๋ก ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์ jsp ํ์ผ์ ์ด๋์ํค๊ฑฐ๋, ํ ํ๋ฆฟ ํ์ฅ์๋ฅผ html ์ด๋ ๋ค๋ฅธ ํ์ผ๋ก ๋ณ๊ฒฝํ๋ฉด ์ฝ๋๋ฅผ ์์ ํด์ผ ํ๋ค.
- request ๊ฐ์ฒด์ response ๊ฐ์ฒด ์ ์ธ์ด ๊ฐ์
- request, response ๊ฐ์ฒด๋ฅผ ์์ ์ฌ์ฉํ๋๊ฒ์ด ์๋๋ฐ ์ ์ธ์ด ๋์ด์ผ ํ๋ค. ์ด๋ก ์ธํด ํ ์คํธ์ฝ๋ ์์ฑ๋ฑ๋ ์ด๋ ค์์ง๋ค.
- ๊ณตํต์ฒ๋ฆฌ์ ์ด๋ ค์
- ๊ฐ ์ปจํธ๋กค๋ฌ๋ค์ด ๊ณตํต์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ ๋ถ๋ถ์ด ๋ง์์ ธ๋ ๊ฐ๊ฐ์ ์๋ธ๋ฆฟ(์ปจํธ๋กค๋ฌ)์ ์ฒ๋ฆฌํด์ฃผ์ด์ผ ํ๋ฏ๋ก ๊ณตํต๊ธฐ๋ฅ์ ๋ฌถ๊ธฐ๊ฐ ์ด๋ ต๋ค.
๋ค์ ์๊ฐ์๋ ์ด๋ฌํ ๋ฌธ์ ๋ค์ ํ๋ก ํธ ์ปจํธ๋กค๋ฌ ํจํด์ ์ ์ฉํ ๋๋ง์ ํ๋ ์์ํฌ๋ฅผ ์ ์ํด๋ณด๋ฉด์ ํด๊ฒฐํด๋ณด๊ณ , ์คํ๋ง์ด ์ด๋ฌํ ๋ฌธ์ ๋ค์ ์ด๋ป๊ฒ ํด๊ฒฐํ์๋์ง ์์๋ณด๋๋ก ํ๊ฒ ๋ค.