DevLog ๐Ÿ˜ถ

[Spring] MVC ํŒจํ„ด์ด๋ž€, V1~V5๋กœ MVC ํ”„๋ ˆ์ž„์›Œํฌ ๋งŒ๋“ค๊ธฐ ๋ณธ๋ฌธ

Back-end/Spring

[Spring] MVC ํŒจํ„ด์ด๋ž€, V1~V5๋กœ MVC ํ”„๋ ˆ์ž„์›Œํฌ ๋งŒ๋“ค๊ธฐ

dolmeng2 2022. 8. 16. 15:44

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ '์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š

 

์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์Šคํ”„๋ง MVC์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๊ณ , ๋” ๊นŠ์ด์žˆ๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., -

www.inflearn.com


- ์ง€๋‚œ ํฌ์ŠคํŒ…๊ณผ ์ด์–ด์ง‘๋‹ˆ๋‹ค :D

 

[Spring] ์„œ๋ธ”๋ฆฟ์ด๋ž€? HttpServletRequest, HttpServletResponse

- ๊น€์˜ํ•œ ๋‹˜์˜ '์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ '์„ ๋ณด๊ณ  ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค ๐Ÿ˜Š ์Šคํ”„๋ง MVC 1ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ•ต์‹ฌ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ

cl8d.tistory.com

 

- ๊ฐ„๋‹จํ•˜๊ฒŒ ํšŒ์› ๊ด€๋ฆฌ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค์–ด๋ณด์ž.

[SMember.java]

@Getter @Setter
@NoArgsConstructor
public class SMember {
    private Long id;
    private String username;
    private int age;

    public SMember(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

- ์ด์ „์˜ ์Šคํ”„๋ง ํ•ต์‹ฌ์›๋ฆฌ ๊ฐ•์˜์™€ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์„œ ๋„๋ฉ”์ธ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค. Member๋ผ๊ณ  ํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

 

[SMemberRepository.java]

public class SMemberRepository {
    private static Map<Long, SMember> store = new ConcurrentHashMap<>();
    private static AtomicLong sequence = new AtomicLong(0L);

    private static final SMemberRepository repository
            = new SMemberRepository();

    private SMemberRepository() {
    }

    public static SMemberRepository getRepository() {
        return repository;
    }

    public SMember save(SMember member) {
        member.setId(sequence.incrementAndGet()); // ++sequence์™€ ๋™์ผํ•œ ์˜๋ฏธ
        store.put(member.getId(), member);
        return member;
    }

    public SMember findById(Long id) {
        return store.get(id);
    }

    public List<SMember> findAll() {
        return new ArrayList<>(store.values());
    }

    public void clearStore() {
        store.clear();
    }
}

- ์ „๋ฐ˜์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค. ์ƒ์„ฑ์ž๋ฅผ private๋กœ ๋ง‰์•˜๊ณ , repository ์—ญ์‹œ getRepository()๋กœ๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

- ์‹ฑ๊ธ€ํ†ค์ด๋‹ค ๋ณด๋‹ˆ๊นŒ ๋™์‹œ์„ฑ ์ด์Šˆ ๋•Œ๋ฌธ์— ConcurrentHashMap๊ณผ AtomicLong์„ ์‚ฌ์šฉํ•ด์ฃผ์—ˆ๋‹ค. ์˜ˆ์ œ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.

- static์œผ๋กœ๋„ ๊ด€๋ฆฌํ•  ํ•„์š”๋Š” ์—†๋‹ค. static์€ ๊ณต์œ  ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์“ฐ์ด์ง€๋งŒ, ์‹ฑ๊ธ€ํ†ค์ด๋ฉด ์–ด์ฐจํ”ผ ์ด์— ๋Œ€ํ•ด์„œ ๋ณด์žฅ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

- ์ถ”๊ฐ€์ ์œผ๋กœ, findAll()์˜ ๊ฒฝ์šฐ new ArrayList<>()๋กœ store.values()์˜ ๊ฐ’์„ ๋ณต์‚ฌํ•ด์„œ ์ „๋‹ฌํ•˜๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” ์ž๋ฐ”์˜ ๋ ˆํผ๋Ÿฐ์Šค ์ฐธ์กฐ๋กœ ์ธํ•ด์„œ store ์ž์ฒด๋ฅผ ๋„˜๊ฒจ๋ฒ„๋ฆฌ๋ฉด store์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์ด ์„ ์–ธํ•˜์˜€๋‹ค.

 

 

โœ” Test

class SMemberRepositoryTest {
    SMemberRepository repository = SMemberRepository.getRepository();

    @AfterEach
    void afterEach() {
        repository.clearStore();
    }

    @Test
    public void save() throws Exception {
        // given
        SMember member = new SMember("hi", 22);

        // when
        SMember savedMember = repository.save(member);

        // then
        SMember findMember = repository.findById(savedMember.getId());
        assertThat(findMember).isEqualTo(member);
    }

    @Test
    public void findAll() throws Exception {
        // given
        SMember member1 = new SMember("hi", 22);
        SMember member2 = new SMember("hihi", 22);

        repository.save(member1);
        repository.save(member2);

        // when
        List<SMember> all = repository.findAll();

        // then
        assertThat(all.size()).isEqualTo(2);
        assertThat(all).contains(member1, member2);

    }

}

- ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์ด๋‹ค. ๋‘˜ ๋‹ค ์ž˜ ๋Œ์•„๊ฐ€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

- ์ด์ œ, ๋ทฐ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ JSP, ํƒ€์ž„๋ฆฌํ”„๋ฅผ ์ด์šฉํ•ด์„œ ์ง„ํ–‰์„ ํ•ด๋ณด์ž. 

    - ๋‹จ์ˆœ ์„œ๋ธ”๋ฆฟ๊ณผ ์ž๋ฐ” ์ฝ”๋“œ๋กœ๋„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์—„์ฒญ๋‚œ ํ•˜๋“œ์ฝ”๋”ฉ์ด ํ•„์š”ํ•˜๊ณ  ์ž˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋žตํ•˜๊ฒ ๋‹ค.

    - ๋‹จ์ˆœ JSP๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ทฐ์— ์ž๋ฐ” ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ๊ต‰์žฅํžˆ ๋ณต์žกํ•˜๋‹ค. ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” MVC ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

 


| MVC ํŒจํ„ด์ด๋ž€?

- JSP์˜ ๊ฒฝ์šฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ๋ทฐ ๋ Œ๋”๋ง๊นŒ์ง€ ๋“ค์–ด๊ฐ€๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€๋ณด์ˆ˜ ๊ด€์ ์—์„œ ๋งค์šฐ ์ข‹์ง€ ์•Š๋‹ค.

- MVC๋Š” ๋ชจ๋ธ - ๋ทฐ - ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•ด์„œ ๊ฐ๊ฐ์˜ ์—ญํ• ์— ๋” ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

 

โœ” ๋ชจ๋ธ (Model)

- ๋ทฐ์— ์ถœ๋ ฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ์—ญํ• ๋กœ, ๋ชจ๋ธ์„ ํ†ตํ•ด ๋ทฐ์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

 

โœ” ๋ทฐ (View)

- ๋ชจ๋ธ์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•œ๋‹ค. HTML์„ ํ†ตํ•ด ๋ทฐ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•œ๋‹ค.

 

โœ” ์ปจํŠธ๋กค๋Ÿฌ (Controller)

- HTTP ์š”์ฒญ์„ ๋ฐ›์•„์„œ ๊ฒ€์ฆ ๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‹คํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์ด๋‹ค. ๋ทฐ์— ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋ธ์— ๋‹ด์•„์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

- ๋ณดํ†ต ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ๊ฒฝ์šฐ ๋ณ„๋„์˜ Service ๋ ˆ์ด์–ด๋ฅผ ํ†ตํ•ด์„œ ์‹คํ–‰ํ•œ๋‹ค.

    - ๊ฐœ์ธ์ ์ธ ๊ฒฝํ—˜์œผ๋กœ๋Š” entity - repository - service - controller ๊ตฌ์กฐ๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ๊ฐ™๋‹ค.

- ์ด ๊ทธ๋ฆผ์ด ๊ฐ€์žฅ ์ •ํ™•ํ•˜๊ฒŒ ๋กœ์ง์„ ์„ค๋ช…ํ•ด์ฃผ๋Š” ๊ฒƒ ๊ฐ™๋‹ค :D

- ์ด์ œ, ์‹ค์ œ ์ฝ”๋“œ์— ์ ์šฉํ•ด๋ณด์ž.

 

- build.gradle์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์ž. (JSP)

implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
implementation 'javax.servlet:jstl'

 

[new-form.jsp]

- main/webapp/WEB-INF/views ๋ฐ‘์— ์„ค์ •ํ•ด๋‘์—ˆ๋‹ค.

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="save" method="post">
        username: <input type="text" name="username">
        age: <input type="text" name="age">
        <button type="submit">์ „์†กํ•˜๊ธฐ</button>
    </form>
</body>

- ๊ฐ„๋‹จํ•˜๊ฒŒ ์ด๋ฆ„๊ณผ ๋‚˜์ด๋ฅผ ์ž…๋ ฅ๋ฐ›์•„ post ๋ฐฉ์‹์œผ๋กœ ์ „์†กํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

- ํ˜„์žฌ์˜ ๊ณ„์ธต ๊ฒฝ๋กœ + /save (action์— ์ง€์ •ํ•ด์ค€ ๊ฒฝ๋กœ)๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.

 

[save-result.jsp]

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    ์„ฑ๊ณต!
    <ul>
        <li>id=${member.id}</li>
        <li>username=${member.username}</li>
        <li>age=${member.age}</li>
    </ul>
</body>

 

- ํšŒ์› ์ €์žฅ ๊ฒฐ๊ณผ๋ฅผ ๋„์›Œ์ฃผ๋Š” ๋ทฐ์ด๋‹ค.

 

[members.jsp]

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <table>
    <thead>
        <th>id</th>
        <th>username</th>
        <th>age</th>
    </thead>
    <tbody>
        <c:forEach var="item" items="${members}">
        <tr>
            <td>${item.id}</td>
            <td>${item.username}</td>
            <td>${item.age}</td>
        </tr>
        </c:forEach>
    </tbody>
    </table>
</body>

- jsp์—์„œ ์ œ๊ณตํ•˜๋Š” taglib ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ํŽธ๋ฆฌํ•˜๊ฒŒ ๋ฐ˜๋ณต๋ฌธ์„ ์ฒ˜๋ฆฌํ•˜์˜€๋‹ค.

- items = {members}์— ๋‹ด๊ธด ์• ๋“ค์„ 'item'์ด๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉฐ ๊ฐ ์š”์†Œ๋“ค์„ ์ถœ๋ ฅํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

- thead์™€ tbody์˜ ๊ฒฝ์šฐ ํ…Œ์ด๋ธ”์˜ ํ—ค๋”์™€ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ด๋ฉฐ, ๊ทธ๋ƒฅ ์„น์…˜์„ ๋‚˜๋ˆ„๋Š” ์šฉ๋„๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

- th๋Š” ํ‘œ์˜ ์ œ๋ชฉ, tr์€ ์ผ์ข…์˜ ๊ฐ€๋กœ์ค„, td๋Š” ๊ฐ๊ฐ์˜ ์…€ ๋‚ด์šฉ์„ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๋ฌธ๋ฒ•์ด๋‹ค.

 

- ์ด์ œ, ๋ณธ๊ฒฉ์ ์ธ MVC ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ์ž‘ํ•˜์ž!


| MVC ํ”„๋ ˆ์ž„์›Œํฌ

- MVC ํ”„๋ ˆ์ž„์›Œํฌ์˜ ํ•ต์‹ฌ์€ 'ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ(Front Controller)'์ด๋‹ค!

- ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋Š” ์•ž๋‹จ์—์„œ ์„œ๋ธ”๋ฆฟ ํ•˜๋‚˜๋กœ ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋ฐ›์œผ๋ฉฐ, ์š”์ฒญ์— ๋งž๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

- ๊ณตํ†ต์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€๋Š” ์„œ๋ธ”๋ฆฟ์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

    - ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ๊ธฐ์กด์—๋Š” ์„œ๋ธ”๋ฆฟ์„ 3๊ฐœ๋กœ ๊ด€๋ฆฌํ•˜์˜€๋‹ค๋ฉด ์ด์ œ๋Š” 1๊ฐœ๋งŒ ๊ด€๋ฆฌํ•ด๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

- ์Šคํ”„๋ง์—์„œ๋Š” DispatcherServlet์ด FrontController์˜ ์—ญํ• ์„ ํ•ด์ค€๋‹ค!

- ๋‹จ๊ณ„์ ์œผ๋กœ ํ•˜๋‚˜์”ฉ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋‚˜๊ฐ€๋ฉฐ FrontController ํŒจํ„ด์„ ์ตํ˜€๋ณด์ž.


 

โœ” V1 - ์ปจํŠธ๋กค๋Ÿฌ ์ธํ„ฐํŽ˜์ด์Šค ๋„์ž…ํ•˜๊ธฐ

[SMemberController.java] 

public interface SMemberController {
    void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}

- ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์„ ์–ธํ•˜์—ฌ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ์ปจํŠธ๋กค๋Ÿฌ๋“ค์„ ๋งŒ๋“ค์–ด๋ณด์ž.

 

[MemberFormController.java] - ํšŒ์› ๋“ฑ๋ก ์ปจํŠธ๋กค๋Ÿฌ

public class MemberFormController implements SMemberController{
    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String viewPath = "/WEB-INF/views/new-form.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

 

[MemberSaveController.java] - ํšŒ์› ์ €์žฅ ์ปจํŠธ๋กค๋Ÿฌ

public class MemberSaveController implements SMemberController{
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        SMember member = new SMember(username, age);
        repository.save(member);

        // JSP์—๊ฒŒ ๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ
        request.setAttribute("member", member);

        String viewPath = "/WEB-INF/views/save-result.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);

    }
}

HttpServletRequest๋ฅผ ์ผ์ข…์˜ Model๋กœ ์‚ฌ์šฉํ•œ๋‹ค. setAttribute๋ฅผ ์ด์šฉํ•ด request์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๊ด€ํ•˜์—ฌ ๋ทฐ์— ์ „๋‹ฌํ•œ๋‹ค.

์•„๊นŒ, view ๊ตฌ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•œ ${} ๋ฌธ๋ฒ•์ด ์ผ์ข…์˜ getAttribute์™€ ๋™์ผํ•œ ์—ญํ• ์ด๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค :D

 

์—ฌ๊ธฐ์„œ RequestDispatcher๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ JSP๋กœ ๋„˜๊ฒจ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿšฉ ์ด๋•Œ, HttpServletResponse์˜ sendRedirect()๋ฅผ ์ด์šฉํ•˜๋ฉด ์›ํ•˜๋Š” ๊ฒฝ๋กœ๋กœ ์ด๋™์„ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, HTTP์˜ ๋ฆฌ๋‹ค์ด๋ ‰์…˜์„ ์ด์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ง์ ‘์ ์ธ response๋ฅผ ์ค€ ๋‹ค์Œ. ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์ •๋ฐ›์€ ์š”์ฒญ ๊ฒฝ๋กœ๋กœ ๋˜ ๋‹ค์‹œ ์žฌ์š”์ฒญ์„ ํ•˜๊ฒŒ ๋˜์–ด์„œ 2๋ฒˆ์˜ ์—ฐ์‚ฐ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

: ์ฆ‰, ์œ„ ๋ฐฉ๋ฒ•์€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ธ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ URL ๊ฒฝ๋กœ๊นŒ์ง€ ๋ณ€๊ฒฝ๋œ๋‹ค.

๋˜ํ•œ, ์ตœ์ดˆ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ ๋‚ด์šฉ์„ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ๋œ ์š”์ฒญ์—์„œ ๊ณต์œ ๊ฐ€ ์•ˆ ๋˜๊ธฐ ๋•Œ๋ฌธ์— (์ด๋ฏธ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌ) ์ฟ ํ‚ค๋‚˜ ์„ธ์…˜ ๊ฐ™์€ ๋ณ„๋„์˜ ์ƒํƒœ๋ฅผ ๋‹ด์•„๋‘๋Š” ๋ณด๊ด€์†Œ๊ฐ€ ํ•„์š”ํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ด๋Š” cost ์ ์œผ๋กœ ์ƒ๊ฐํ•ด๋ณด์•˜์„ ๋•Œ ๋งค์šฐ ๋‚ญ๋น„์ด๋‹ค. 

 

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, requestDispatcher์˜ forward ๋ฐฉ์‹์„ ์ด์šฉํ•˜๋ฉด ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋Š” ํ˜„์žฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌ ์ค‘์ธ ์„œ๋ธ”๋ฆฟ์ด ์†ํ•ด์žˆ๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฒ”์œ„ ๋‚ด์—์„œ ๋ฒ”์œ„๋ฅผ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค!

์ฆ‰, 1๋ฒˆ์˜ HTTP ์š”์ฒญ ๋‚ด์—์„œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.

๐ŸŽˆ ํด๋ผ์ด์–ธํŠธ๊ฐ€ a.jsp ์š”์ฒญ -> ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ forward๋ฅผ ํ†ตํ•ด b.jsp ํ˜ธ์ถœ -> ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ b.jsp ๊ฒฐ๊ณผ ์‘๋‹ต.

 

 

[MemberListController.java] - ํšŒ์› ๋ชฉ๋ก ์ปจํŠธ๋กค๋Ÿฌ

public class MemberListController implements SMemberController{
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<SMember> members = repository.findAll();
        request.setAttribute("members", members);

        String viewPath = "/WEB-INF/views/members.jsp";
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

 

[FrontController.java] - ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ

@WebServlet(name = "frontController", urlPatterns = "/front-controller/*")
public class FrontController extends HttpServlet {
    private Map<String, SMemberController> controllerMap
             = new HashMap<>();

    public FrontController() {
        controllerMap.put("/front-controller/members/new-form", new
                MemberFormController());
        controllerMap.put("/front-controller/members/save", new
                MemberSaveController());
        controllerMap.put("/front-controller/members", new
                MemberListController());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("FrontController.service");
        String requestURI = req.getRequestURI();
        SMemberController controller = controllerMap.get(requestURI);

        if(controller == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        controller.process(req, resp);
    }
}

- ControllerMap์„ ๋‘์—ˆ๋‹ค. key๋Š” ๋งคํ•‘ URL์„, value๋Š” ํ˜ธ์ถœ๋  ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

- controller๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ 404, ์žˆ๋‹ค๋ฉด process๋ฅผ ํ†ตํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ์—ˆ๋‹ค.

๐Ÿšฉ ์ฐธ๊ณ ๋กœ, FrontController์˜ ๊ฒฝ์šฐ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ์— ๋“ฑ๋ก๋  ๋•Œ ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋˜์–ด ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค :)

 

/front-controller/members/new-form

 

/front-controller/members/save

 

/front-controller/members

- ๋ชจ๋‘ ๋‹ค ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (์‹ค์ˆ˜๋กœ 2๋ฒˆ ๋“ฑ๋กํ•ด์„œ ๊ฐ™์€ ๊ฒŒ 2๋ฒˆ์”ฉ ๋“ค์–ด๊ฐ”๋‹ค...ใ…Žใ…Ž)

 


โœ” V2 - View ์ด๋™ ๋ถ„๋ฆฌํ•˜๊ธฐ

- ์ด์ „์˜ V1 ๊ฐ™์€ ๊ฒฝ์šฐ viewPath๋ฅผ ์ง€์ •ํ•˜์—ฌ RequestDispatcher๋ฅผ ํ™œ์šฉํ•ด ๋ทฐ๋กœ ์ด๋™์‹œ์ผฐ๋‹ค.- ๋‹ค๋งŒ, ์ฝ”๋“œ๊ฐ€ ๋‹ค ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์ด๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๋‹นํžˆ ๋ถˆํŽธํ•˜๋‹ค. ์ด์— ๋Œ€ํ•ด ๋”ฐ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž!

 

[MyView.java]

public class MyView {
    private String viewPath;

    public MyView(String viewPath) {
        this.viewPath = viewPath;
    }

    public void render(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

- render()๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋งŒ๋“ค์–ด์„œ ๊ณตํ†ต์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋‘์—ˆ๋‹ค.

 

[SMemberController.java] - ์ˆ˜์ •

public interface SMemberController {
    MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}

[MemberFormController.java] - ์ˆ˜์ •

public class MemberFormController implements SMemberController{
    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        return new MyView("/WEB-INF/views/new-form.jsp");
    }
}

- viewPath๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” MyView ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กญ๊ฒŒ ์ƒ์„ฑํ•˜์˜€๋‹ค. frontController์—์„œ ํ•ด๋‹น myView ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ render๋ฅผ ์‹คํ–‰ํ•  ์˜ˆ์ •์ด๋‹ค.

- ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‚จ์€ ํŒŒ์ผ๋“ค๋„ ์ˆ˜์ •ํ•ด๋ณด์ž.

 

[MemberSaveController.java] - ์ˆ˜์ •

public class MemberSaveController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        int age = Integer.parseInt(request.getParameter("age"));

        SMember member = new SMember(username, age);
        repository.save(member);

        request.setAttribute("member", member);

        return new MyView("/WEB-INF/views/save-result.jsp");
    }
}

[MemberListController.java] - ์ˆ˜์ •

public class MemberListController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<SMember> members = repository.findAll();
        request.setAttribute("members", members);

        return new MyView("/WEB-INF/views/members.jsp");
    }
}

 

[FrontController.java] - ์ˆ˜์ •

@WebServlet(name = "frontController", urlPatterns = "/front-controller/*")
public class FrontController extends HttpServlet {
    private Map<String, SMemberController> controllerMap
             = new HashMap<>();

    public FrontController() {
        controllerMap.put("/front-controller/members/new-form", new
                MemberFormController());
        controllerMap.put("/front-controller/members/save", new
                MemberSaveController());
        controllerMap.put("/front-controller/members", new
                MemberListController());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("FrontController.service");
        String requestURI = req.getRequestURI();
        SMemberController controller = controllerMap.get(requestURI);

        if(controller == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        MyView view = controller.process(req, resp);
        view.render(req, resp);
    }
}

- controller.process()๋ฅผ ํ†ตํ•ด service() ํ•จ์ˆ˜๋กœ ๋ฆฌํ„ด๋ฐ›์€ MyView ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ .render()๋ฅผ ํ˜ธ์ถœํ•ด ๋ทฐ๋ฅผ ๊ทธ๋ ค์ฃผ์—ˆ๋‹ค.

- ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์ž˜ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 


โœ” V3 - Model ์ถ”๊ฐ€ํ•˜๊ธฐ

- V2์—์„œ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•ด์„œ ๊ฐ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ฝ”๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ๊น”๋”ํ•ด์กŒ๋‹ค.

- ํ•˜์ง€๋งŒ, HttpServletRequest / Response๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ผญ ์‚ฌ์šฉ์„ ํ•ด์•ผ ํ• ๊นŒ?

    - ๋ฌผ๋ก , ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ์ •ํ™•ํ•˜๊ฒŒ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์ด์ง€, req/resp๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

- req ๊ฐ์ฒด๋ฅผ Model๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ณ„๋„์˜ Model ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•ด๋ณด์ž.

    - ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์„œ๋ธ”๋ฆฟ์— ์ข…์†์ ์ด์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋” ๋‹จ์ˆœํ•ด์ง„๋‹ค.

- ์ถ”๊ฐ€์ ์œผ๋กœ, View์˜ ์ด๋ฆ„์ด ์ค‘๋ณต๋˜๋Š” ๋ถ€๋ถ„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— (/WEB-INF/views) ๋ทฐ์˜ ๋…ผ๋ฆฌ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•ด๋ณด์ž.

 

[ModelView.java]

@Getter @Setter
public class ModelView {
    private String viewName;
    private Map<String, Object> model = new HashMap<>();

    public ModelView(String viewName) {
        this.viewName = viewName;
    }
}

- ๋ทฐ์˜ ์ด๋ฆ„๊ณผ ๋ชจ๋ธ ๊ฐ์ฒด๋ฅผ ํ•จ๊ป˜ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์˜๋ฏธ๋กœ ModelView๋ผ๋Š” ์ด๋ฆ„์„ ์ง€์—ˆ๋‹ค.

- ๋ชจ๋ธ์˜ ๋ฐ์ดํ„ฐ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ๋„ค์ž„ - ์‹ค์ œ ๊ฐ’ ํ˜•ํƒœ๋กœ map์— ์ €์žฅํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

 

[SMemberController.java] - ์ˆ˜์ •

public interface SMemberController {
    ModelView process(Map<String, String> paramMap);
}

- ์ด๋ฒˆ์—๋Š” ModelView๋ฅผ ๋ฆฌํ„ดํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค. ๋˜ํ•œ, ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋” ์ด์ƒ ์„œ๋ธ”๋ฆฟ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค!

- HttpServletRequest๋ฅผ model๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , paramMap์„ ์ด์šฉํ•ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์ž.

 

[MemberFormController.java] - ์ˆ˜์ •

public class MemberFormController implements SMemberController{
    @Override
    public ModelView process(Map<String, String> paramMap) {
        return new ModelView("new-form");
    }
}

- ์ด๋Ÿฐ ์‹์œผ๋กœ view์˜ ๋…ผ๋ฆฌ์ ์ธ ์ด๋ฆ„์„ ๋ฆฌํ„ดํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

 

[MemberSaveController.java] - ์ˆ˜์ •

public class MemberSaveController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public ModelView process(Map<String, String> paramMap) {
        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age"));

        SMember member = new SMember(username, age);
        repository.save(member);
        ModelView mv = new ModelView("save-result");
        mv.getModel().put("member", member);
        return mv;
    }
}

- ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋ฅผ map์—์„œ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

- ๋ทฐ์—๊ฒŒ ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ModelView์— model ํ•„๋“œ์— put์„ ํ†ตํ•ด ์ง‘์–ด๋„ฃ๋Š” ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

 

[MemberListController.java] - ์ˆ˜์ •

public class MemberListController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public ModelView process(Map<String, String> paramMap) {
        List<SMember> members = repository.findAll();
        ModelView mv = new ModelView("members");
        mv.getModel().put("members", members);
        return mv;
    }
}

 

[FrontController.java] - ์ˆ˜์ •

@WebServlet(name = "frontController", urlPatterns = "/front-controller/*")
public class FrontController extends HttpServlet {
    private Map<String, SMemberController> controllerMap
             = new HashMap<>();

    public FrontController() {
        controllerMap.put("/front-controller/members/new-form", new
                MemberFormController());
        controllerMap.put("/front-controller/members/save", new
                MemberSaveController());
        controllerMap.put("/front-controller/members", new
                MemberListController());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("FrontController.service");
        String requestURI = req.getRequestURI();
        SMemberController controller = controllerMap.get(requestURI);

        if(controller == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Map<String, String> paramMap = createParamMap(req);
        ModelView mv = controller.process(paramMap);
        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        view.render(mv.getModel(), req, resp);
    }

    private Map<String, String> createParamMap(HttpServletRequest req) {
        Map<String, String> paramMap = new HashMap<>();
        req.getParameterNames().asIterator()
                .forEachRemaining(paramName -> {
            paramMap.put(paramName, req.getParameter(paramName))
        });
        return paramMap;
    }

    private MyView viewResolver(String viewName) {
        MyView view = new MyView("/WEB-INF/views/" + viewName + ".jsp");
        return view;
    }

}

 

createParamMap์ด๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋‘์–ด์„œ HttpServletRequest์— ์žˆ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ •๋ณด๋ฅผ ๊บผ๋‚ด ๋งต์— ๋‹ด์•˜๋‹ค. 

์ฆ‰, ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ URL๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ request์— ๋‹ด๊ฒจ์žˆ๋Š”๋ฐ, ์ด๋ฅผ ๊บผ๋‚ด์„œ ์“ด๋‹ค๋Š” ๊ฒƒ!

: ์ฐธ๊ณ ๋กœ, asIterator().forEachRemaining()์„ ์“ฐ๋Š” ์ด์œ ๋Š” req.getParameterNames()๋ฅผ ํ–ˆ์„ ๋•Œ ๋‚˜์˜ค๋Š” ํƒ€์ž…์ด Enumerationํ˜•์ด์–ด์„œ ๊ทธ๋ ‡๋‹ค.

 

๋งŒ๋“  ๋งต์„ controller.process()๋ฅผ ์ด์šฉํ•ด์„œ ์ „๋‹ฌํ•˜์˜€์œผ๋ฉฐ, ๋ฐ˜ํ™˜ ๊ฒฐ๊ณผ๋กœ ๋‚˜์˜จ ModelView ๊ฐ์ฒด์—์„œ ๋…ผ๋ฆฌ viewName์„ ๊บผ๋‚ด์ค€๋‹ค.

์ดํ›„, ๊บผ๋‚ธ viewName์— ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฌผ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•ด์ฃผ์—ˆ์œผ๋ฉฐ, ์ด๋ฅผ viewResolver๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ง€์—ˆ๋‹ค!

 

[MyView.java] - ์ˆ˜์ •

public class MyView {
    private String viewPath;

    public MyView(String viewPath) {
        this.viewPath = viewPath;
    }

    public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // model.forEach((key, value) -> request.setAttribute(key, value));
        model.forEach(request::setAttribute);
        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
        dispatcher.forward(request, response);
    }
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด model์— ๋‹ด๊ธด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ request์— setAttribute๋ฅผ ํ†ตํ•ด view์—๊ฒŒ ๋„˜๊ฒจ์ค€๋‹ค.

์ด๋•Œ, ๋žŒ๋‹ค์‹์„ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ๋” ์‰ฝ๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. - ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋™์ผํ•˜๊ฒŒ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ๋‹ค!

 


โœ” V4 - ๋‹จ์ˆœํ•œ ๊ฒŒ ์ข‹์•„!

- V3 ๋ฒ„์ „์˜ ๊ฒฝ์šฐ ์„ค๊ณ„๊ฐ€ ์ž˜ ๋˜์–ด ์žˆ๋‹ค. ๋‹ค๋งŒ, ์ฝ”๋“œ๊ฐ€ ๋น„๊ต์  ๋ณต์žกํ•˜๊ณ  ModelView๋ฅผ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ณ„์† ๋งŒ๋“ค์–ด์ค˜์•ผ ํ•œ๋‹ค๋Š” ์ ์ด ๋‹จ์ ์ด๋‹ค.

- ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ๋ฆฌ๋Š” ์œ„ ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋” ๋‹จ์ˆœํ™”์‹œ์ผœ๋ณด์ž.

- ModelView ๋Œ€์‹  ViewName๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์„ค๊ณ„ํ•  ๊ฒƒ์ด๋‹ค.

 

[SMemberController.java] - ์ˆ˜์ •

public interface SMemberController {
    String process(Map<String, String> paramMap, Map<String, Object> model);
}

- ๋ฐ˜ํ™˜ํ˜•์„ String์œผ๋กœ ๋ฐ”๊พธ์—ˆ์œผ๋ฉฐ, model ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

 

[MemberFormController.java] - ์ˆ˜์ •

public class MemberFormController implements SMemberController{
    @Override
    public String process(Map<String, String> paramMap, Map<String, Object> model) {
        return "new-form";
    }
}

- new-form์ด๋ผ๋Š” ๋…ผ๋ฆฌ ์ด๋ฆ„๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

 

[MemberSaveController.java] - ์ˆ˜์ •

public class MemberSaveController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public String process(Map<String, String> paramMap, Map<String, Object> model) {
        String username = paramMap.get("username");
        int age = Integer.parseInt(paramMap.get("age"));

        SMember member = new SMember(username, age);
        repository.save(member);
        model.put("member", member);
        return "save-result";
    }
}

- ๊ธฐ์กด์—๋Š” ModelView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ทธ ๋‚ด๋ถ€์— ์žˆ๋Š” model ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๋Š” ์‹์œผ๋กœ ์ง„ํ–‰ํ•˜์˜€๋‹ค๋ฉด, ์ด์ œ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋ฐ›์€ model์— ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ๋˜ํ•œ, ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ทฐ์˜ ๋…ผ๋ฆฌ ์ด๋ฆ„๋งŒ ๋ฐ˜ํ™˜ํ•ด์ฃผ์—ˆ๋‹ค.

 

[MemberListController.java] - ์ˆ˜์ •

public class MemberListController implements SMemberController {
    private final SMemberRepository repository
            = SMemberRepository.getRepository();

    @Override
    public String process(Map<String, String> paramMap, Map<String, Object> model) {
        List<SMember> members = repository.findAll();
        model.put("members", members);
        return "members";
    }
}

 

[FrontController.java] - ์ˆ˜์ •

@WebServlet(name = "frontController", urlPatterns = "/front-controller/*")
public class FrontController extends HttpServlet {
    private Map<String, SMemberController> controllerMap
             = new HashMap<>();

    public FrontController() {
        controllerMap.put("/front-controller/members/new-form", new
                MemberFormController());
        controllerMap.put("/front-controller/members/save", new
                MemberSaveController());
        controllerMap.put("/front-controller/members", new
                MemberListController());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("FrontController.service");
        String requestURI = req.getRequestURI();
        SMemberController controller = controllerMap.get(requestURI);

        if(controller == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Map<String, String> paramMap = createParamMap(req);
        Map<String, Object> model = new HashMap<>();
        String viewName = controller.process(paramMap, model);
        MyView view = viewResolver(viewName);
        view.render(model, req, resp);
    }

    private Map<String, String> createParamMap(HttpServletRequest req) {
        Map<String, String> paramMap = new HashMap<>();
        req.getParameterNames().asIterator()
                .forEachRemaining(paramName -> {
            paramMap.put(paramName, req.getParameter(paramName));
        });
        return paramMap;
    }

    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

}

- ์ด์ „๊ณผ ๋‹ฌ๋ผ์ง„ ์ ์€ model ๊ฐ์ฒด๋ฅผ ์—ฌ๊ธฐ์—์„œ ๋งŒ๋“ค์–ด์„œ ๋„˜๊ฒจ์ค€๋‹ค๋Š” ์ ๊ณผ,

์ปจํŠธ๋กค๋Ÿฌ์˜ ์‹คํ–‰๊ฒฐ๊ณผ๋กœ ๋ฆฌํ„ด๋ฐ›์€ viewName์„(๋…ผ๋ฆฌ ์ด๋ฆ„) viewResolver์— ์ „๋‹ฌํ•ด์ค€๋‹ค๋Š” ์ ์ด๋‹ค.

- ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ด์ „๊ณผ ๋™์ผํ•˜๊ฒŒ ์ž˜ ์‹คํ–‰๋œ๋‹ค :D

 


โœ” V5 - ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค๊ธฐ

- ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๊ฐœ๋ฐœํ–ˆ๋˜ ๋ฐฉ๋ฒ•์„ ํ˜ผ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์ข‹์„๊นŒ?

- "์–ด๋Œ‘ํ„ฐ ํŒจํ„ด"์„ ํ™œ์šฉํ•˜์—ฌ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค!

- ์ค‘๊ฐ„์— ํ•ธ๋“ค๋Ÿฌ ์–ด๋Œ‘ํ„ฐ๋ฅผ ๋‘์–ด ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜์˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ณ , ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๊ฐœ๋ฐœํ•˜์˜€๋˜ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ผ์ข…์˜ 'ํ•ธ๋“ค๋Ÿฌ'๋ผ๊ณ  ์ƒ๊ฐํ•˜์ž.

 

[MyHandlerAdapter.java]

public interface MyHandlerAdapter {
    boolean supports(Object handler);
    ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws ServletException, IOException;
}

- supports() ๋ฉ”์„œ๋“œ๋ฅผ ๋‘์–ด์„œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ฐ›์•˜๋‹ค.

    - ์ด๋Š”, ์–ด๋Œ‘ํ„ฐ๊ฐ€ ํ•ด๋‹น ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํŒ๋‹จํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

- ์–ด๋Œ‘ํ„ฐ๋Š” ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœ ํ›„ ๊ฒฐ๊ณผ๋กœ ModelView๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜์ง€ ๋ชปํ•˜๋ฉด ์–ด๋Œ‘ํ„ฐ๊ฐ€ ์ง์ ‘ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

- ์ด์ „์—๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์‹ค์ œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ–ˆ์ง€๋งŒ, ์ด์ œ๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ ํ†ตํ•ด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

 

[ControllerV3HandlerAdapter.java]

public class ControllerV3HandlerAdapter implements MyHandlerAdapter{
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof ControllerV3); // ์ด๋Ÿฐ ์‹์œผ๋กœ!
    }

    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        SMemberController controller = (SMemberController) handler;
        Map<String, String> paramMap = createParamMap(request);
        ModelView mv = controller.process(paramMap);
        return mv;
    }

    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> paramMap.put(paramName,
                request.getParameter(paramName)));
        return paramMap;
    }
}

- ์ด๋Ÿฐ ์‹์œผ๋กœ ์›ํ•˜๋Š” Controller์— ๋งž์ถฐ์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๋„˜๊ฒจ์ฃผ๋ฉด ๋œ๋‹ค. 

(V3, V4์— ๋งž๋„๋ก ๊ฐˆ์•„๋ผ์šด๋‹ค๊ณ  ์ƒ๊ฐํ•ด์ฃผ๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค)

 

[ControllerV4HandlerAdapter.java]

public class ControllerV4HandlerAdapter implements MyHandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof ControllerV4);
    }
    @Override
    public ModelView handle(HttpServletRequest request, HttpServletResponse
            response, Object handler) {
        ControllerV4 controller = (ControllerV4) handler;
        Map<String, String> paramMap = createParamMap(request);
        Map<String, Object> model = new HashMap<>();
        String viewName = controller.process(paramMap, model);

        ModelView mv = new ModelView(viewName);
        mv.setModel(model);

        return mv;
    }
    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> paramMap.put(paramName,
                request.getParameter(paramName)));
        return paramMap;
    }
}

- ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€, ๊ธฐ์กด์— viewName๋งŒ ๋ฐ˜ํ™˜ํ–ˆ๋˜ V4์˜ ํŠน์ง•์„ ์œ„ํ•ด์„œ '์–ด๋Œ‘ํ„ฐ'์—์„œ ModelView ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.

- ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์•„๋‹Œ, ์–ด๋Œ‘ํ„ฐ์—์„œ ModelView๋ฅผ ๋งŒ๋“ค๊ณ  setModel์„ ํ†ตํ•ด ๋ชจ๋ธ์„ ๋„ฃ์–ด์ฃผ๋Š” ์—ญํ• ๊นŒ์ง€ ํ•ด์ค€๋‹ค.

- ์ฆ‰, ์–ด๋Œ‘ํ„ฐ๊ฐ€ ํ˜•์‹์— ๋งž์ถฐ์„œ ๋ฐ˜ํ™˜ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ๊ฒƒ์ด๋‹ค!!

 

[FrontController.java] - ์ˆ˜์ •

@WebServlet(name = "frontController", urlPatterns = "/front-controller/*")
public class FrontController extends HttpServlet {
    private Map<String, SMemberController> handlerMappingMap
             = new HashMap<>();
    private List<MyHandlerAdapter> handlerAdapters = new ArrayList<>();

    public FrontController() {
        initHandlerMapping();
        initHandlerAdapters();
    }

    private void initHandlerAdapters() {
        handlerAdapters.add(new ControllerV3HandlerAdapter());
        handlerAdapters.add(new ControllerV4HandlerAdapter());
    }

    private void initHandlerMapping() {
        // V3
        handlerMappingMap.put("/front-controller/members/new-form", new
                MemberFormController());
        handlerMappingMap.put("/front-controller/members/save", new
                MemberSaveController());
        handlerMappingMap.put("/front-controller/members", new
                MemberListController());

        // V4
        handlerMappingMap.put("/front-controller/v5/v4/members/new-form", new
                MemberFormControllerV4());
        handlerMappingMap.put("/front-controller/v5/v4/members/save", new
                MemberSaveControllerV4());
        handlerMappingMap.put("/front-controller/v5/v4/members", new
                MemberListControllerV4());
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Object handler = getHandler(req);

        if(handler == null) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        MyHandlerAdapter adapter = getHandlerAdapter(handler);
        ModelView mv = adapter.handle(req, resp, handler);

        MyView view = viewResolver(mv.getViewName());
        view.render(mv.getModel(), req, resp);
    }

    private Object getHandler(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        return handlerMappingMap.get(requestURI);
    }

    private MyHandlerAdapter getHandlerAdapter(Object handler) {
        for (MyHandlerAdapter adapter : handlerAdapters) {
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
        throw new IllegalArgumentException("handler adapter๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. handler=" + handler);
    }

    private MyView viewResolver(String viewName) {
        return new MyView("/WEB-INF/views/" + viewName + ".jsp");
    }

}

- handlerMappingMap์— URI๊ณผ ๋งคํ•‘๋œ ํ•ธ๋“ค๋Ÿฌ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ๋‹ค.

-  getHandler๋ฅผ ํ†ตํ•ด์„œ ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘ ์ •๋ณด์ธ handlerMappingMap์—์„œ URI์— ๋งคํ•‘๋œ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฐพ์•„์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

- getHandlerAdapter์—์„œ support ๋ฉ”์„œ๋“œ๋กœ ํ•ด๋‹น ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์–ด๋Œ‘ํ„ฐ๋ฅผ ์ฐพ๋Š”๋‹ค.

- ๋ฐ˜ํ™˜๋ฐ›์€ ์–ด๋Œ‘ํ„ฐ๋ฅผ ์ด์šฉํ•ด handle ๋ฉ”์„œ๋“œ๋กœ ์‹ค์ œ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ , ํ”„๋กœ์„ธ์Šค๋ฅผ ์ฒ˜๋ฆฌํ•œ ๊ฒฐ๊ณผ์ธ ModelView๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๋Š”๋‹ค.

 

 

- ์šฐ๋ฆฌ๋Š” V1~V5๊นŒ์ง€ ์ ์ง„์ ์œผ๋กœ ๋ฐœ์ „์‹œ์ผœ๋‚˜๊ฐ€๋ฉฐ MVC ๊ตฌ์กฐ๋ฅผ ์ตํ˜”๋‹ค.

- ์—ฌ๊ธฐ์— ๋”๋ถˆ์–ด์„œ, ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋” ๋ฐœ์ „์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค! 

- ์ด์ œ ์Šคํ”„๋ง์—์„œ MVC๋ฅผ ์–ด๋–ป๊ฒŒ ์ง€์›ํ•˜๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž.

Comments