๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Java·๏ปฟServlet·๏ปฟJSP

๋ฆฌํ”Œ๋ž™์…˜ API๋ฅผ ์ด์šฉํ•œ Front Controller ์ž๋™ํ™”

by Leica 2020. 2. 20.
๋ฐ˜์‘ํ˜•

๋ณธ ๋‚ด์šฉ์€ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.

 

๋ฆฌํ”Œ๋ž™์…˜ API๋ฅผ ์ด์šฉํ•œ Front Controller ์ž๋™ํ™”

 

์•„๋ž˜์™€ ๊ฐ™์€ ์‹ ๊ทœ ํ•™์ƒ(ํšŒ์›)์„ ๋“ฑ๋กํ•˜๋Š” ํผ์ด ์žˆ๋‹ค.

 

 

์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ณ  [๋“ฑ๋ก] ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด์„œ ์‹ ๊ทœ ํ•™์ƒ ๋“ฑ๋ก์„ ์š”์ฒญํ•˜๋ฉด ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•œ๋‹ค.

 

1
2
3
4
5
6
7
8
9
10
11
12
// ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ’์„ ๊บผ๋‚ด์„œ Map์— ๋‹ด์Œ
model.put("student"new Student()
        .setStudentNo(req.getParameter("student_no"))
    .setStudentName(req.getParameter("student_name"))
    .setAddress(req.getParameter("address"))
    .setAge(Integer.parseInt(req.getParameter("age")))
    .setDepartment(req.getParameter("department"))
    .setGender(req.getParameter("gender"))
    .setGrade(Integer.parseInt(req.getParameter("grade")))
    .setPassword(req.getParameter("password"))
    .setPhoneNumber(req.getParameter("phone_number"))
);
cs

 

์ด๋ฅผ ์œ„ํ•ด ์œ„์™€ ๊ฐ™์ด VO ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  setter()๋ฅผ ํ†ตํ•ด ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์„ธํŒ…ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•œ๋‹ค๋ฉด ์ถ”ํ›„ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๊ฒŒ ๋œ๋‹ค.

์ด ๋•Œ ๋ฆฌํ”Œ๋ž™์…˜ API๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์„ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ž๋™ํ™” ์‹œ๋‚˜๋ฆฌ์˜ค

์‹ ๊ทœ ํ•™์ƒ์„ ๋“ฑ๋กํ• ๋•Œ ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ ์ค€๋น„๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

โ‘  ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ํ•™์ƒ ๋“ฑ๋ก์„ ์š”์ฒญํ•˜๋ฉฐ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์„œ๋ธ”๋ฆฟ์— ์ „๋‹ฌํ•œ๋‹ค.
โ‘ก ์„œ๋ธ”๋ฆฟ(Front controller)์ด ํ•™์ƒ ๋“ฑ๋ก์„ ์ฒ˜๋ฆฌํ•˜๋Š” StudentAddController์—๊ฒŒ ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ์ง€ ๋ฌผ์–ด๋ณธ๋‹ค.
โ‘ข StudentAddController๋Š” ์ž‘์—…ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ์˜ ์ด๋ฆ„๊ณผ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด์€ ๋ฐฐ์—ด์„ ๋ฆฌํ„ดํ•œ๋‹ค.
โ‘ฃ Front controller๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ StudentAddController๊ฐ€ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค.
โ‘ค Front controller๋Š” StudentAddController๋ฅผ executeํ•˜๋ฉด์„œ โ‘ฃ์—์„œ ๋งŒ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•œ๋‹ค.

 

์ž๋™ํ™” ๊ตฌํ˜„

1. DataBinding ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜ ๋ฐ ๊ตฌํ˜„

๋ชจ๋“  controller๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฑด ์•„๋‹ˆ๋ฏ€๋กœ DataBinding ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ •์˜ํ•ด์„œ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ controller์—๊ฒŒ๋งŒ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด ์ „๋‹ฌํ•  ๊ฒƒ์ด๋‹ค.

bind ํŒจํ‚ค์ง€์— ์•„๋ž˜์™€ ๊ฐ™์€ DataBinding ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

 

DataBinding.java

1
2
3
4
5
6
7
8
9
10
11
/**
 * ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ controller๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
 */
public interface DataBinding {
    /**
     * ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ •์˜
     * @return ๋ฐ์ดํ„ฐ์˜ ์ด๋ฆ„๊ณผ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด์€ Object[]
     * Ex) new Object[]{"๋ฐ์ดํ„ฐ์ด๋ฆ„", ๋ฐ์ดํ„ฐํƒ€์ž…, "๋ฐ์ดํ„ฐ์ด๋ฆ„", ๋ฐ์ดํ„ฐํƒ€์ž…, ...}
     */
    Object[] getDataBinders();
}
cs

 

getDataBinders()์˜ ๋ฆฌํ„ด๊ฐ’์€ ๋ฐ์ดํ„ฐ ์ด๋ฆ„๊ณผ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด์€ Object ๋ฐฐ์—ด์ด๋‹ค.

 

์ด์ œ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ controller์—์„œ ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•œ๋‹ค.

 

StudentAddController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * ์‹ ๊ทœ ํ•™์ƒ ๋“ฑ๋ก
 */
public class StudentAddController implements Controller, DataBinding {
 
    /**
     * ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ •์˜
     * @return ๋ฐ์ดํ„ฐ์˜ ์ด๋ฆ„๊ณผ ํƒ€์ž… ์ •๋ณด๋ฅผ ๋‹ด์€ Object[]
     */
    @Override
    public Object[] getDataBinders() {
        return new Object[]{"student", com.atoz_develop.spms.vo.Student.class};
    }
cs

์œ„์™€ ๊ฐ™์ด ๋ฐ˜ํ™˜ํ•˜๋ฉด ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ Student ๊ฐ์ฒด์— ๋‹ด์•„์„œ "student"๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ „๋‹ฌํ•ด ๋‹ฌ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

 

2. Front controller ๋ณ€๊ฒฝ

์ด์ œ front controller์—์„œ ์ง์ ‘ Student ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  setter()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•œ๋’ค controller์—๊ฒŒ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฌป๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋ณผ ์ˆ˜ ์žˆ๋„๋ก ๊ด€๋ จ ์—†๋Š” ์ฝ”๋“œ๋Š” ์ƒ๋žตํ•˜์˜€๋‹ค.

 

DispatcherServlet.java

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
38
39
40
41
42
/**
 * Front Controller
 */
@WebServlet("*.do")
public class DispatcherServlet extends HttpServlet {
 
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
        // DataBinding ๊ตฌํ˜„ ์—ฌ๋ถ€ ํ™•์ธ ํ›„ ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๋Š” prepareRequestData() ํ˜ธ์ถœ
        if(pageController instanceof DataBinding) {
            prepareRequestData(req, model, (DataBinding) pageController);
        }
 
        // PageController์— ์‹คํ–‰ ์š”์ฒญ
        String viewUrl = pageController.execute(model);
    }
 
    /**
     * ๋ฐ์ดํ„ฐ ์ค€๋น„
     * @param request
     * @param model
     * @param dataBinding
     * @throws Exception
     */
    private void prepareRequestData(HttpServletRequest request, Map<String, Object> model, DataBinding dataBinding) throws Exception {
 
        // ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ํ™•์ธ
        Object[] dataBinders = dataBinding.getDataBinders();
        String dataName = null;
        Class<?> dataType = null;
        Object dataObj = null;
 
        for(int i=0; i<dataBinders.length; i+=2) {
            dataName = (String) dataBinders[i];
            dataType = (Class<?>) dataBinders[i+1];
            // dataName๊ณผ ์ผ์น˜ํ•˜๋Š” ์š”์ฒญ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ dataType ์ธ์Šคํ„ด์Šค์— ์ €์žฅํ•˜๊ณ  ๋ฐ˜ํ™˜
            dataObj = ServletRequestDataBinder.bind(request, dataType, dataName);
            model.put(dataName, dataObj);
        }
    }
}
cs

 

1) service()

service() ๋ฉ”์†Œ๋“œ์—์„œ ๊ธฐ์กด์˜ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ DataBinding์„ ๊ตฌํ˜„ํ–ˆ๋Š”์ง€ ํ™•์ธํ•œ ๋’ค ๋ฐ์ดํ„ฐ๋ฅผ ์ค€๋น„ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ธ prepareRequestData()๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ํ•œ๋‹ค.

 

if (pageController instanceof DataBinding) {
    prepareRequestData(...)
}

 

2) prepareRequestData()

๋จผ์ € ์ปจํŠธ๋กค๋Ÿฌ์—๊ฒŒ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•œ๋‹ค.

 

Object[] dataBinders = dataBinding.getDataBinders();

getDataBinders()๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ {"๋ฐ์ดํ„ฐ ์ด๋ฆ„", ๋ฐ์ดํ„ฐ ํƒ€์ž…, "๋ฐ์ดํ„ฐ ์ด๋ฆ„", ๋ฐ์ดํ„ฐ ํƒ€์ž…, ...}๊ณผ ๊ฐ™์€ Object ๋ฐฐ์—ด์ด๋‹ค.

 

๋ฐ์ดํ„ฐ ์ด๋ฆ„๊ณผ ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด 1์Œ ์”ฉ ๋“ค์–ด์žˆ์œผ๋ฏ€๋กœ 2์”ฉ ์ฆ๊ฐ€์‹œํ‚ค๋ฉฐ for๋ฌธ์„ ๋Œ๋ฆฐ๋‹ค.

 

for (int i=0; i<dataBinders.length; i+=2) {
    dataName = (String)dataBinders[i];
    dataType = (Class<?>) dataBinders[i+1];
    ...
}

 

3) ServletRequestDataBinder.bind()

๊ณง ๊ตฌํ˜„ํ•  ServletRequestDataBinder๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์ž๋ฐ” ๊ฐ์ฒด์— ๋‹ด์•„์ฃผ๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์ด ๋ฉ”์†Œ๋“œ๋Š” dataName๊ณผ ์ผ์น˜ํ•˜๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฐพ๊ณ  dataType์„ ํ†ตํ•ด ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ฐพ์€ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์„ ์ธ์Šคํ„ด์Šค์— ์ €์žฅํ•˜๊ณ  ๊ทธ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

dataObj = ServletRequestDataBinder.bind(request, dataType, dataName);
model.put(dataName, dataObj);

 

์ตœ์ข…์ ์œผ๋กœ ๋ฐ˜ํ™˜๋ฐ›์€ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ Map ๊ฐ์ฒด model์— ๋‹ด์•„ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•œ๋‹ค.

 

3. ServletRequestDataBinder ํด๋ž˜์Šค ๊ตฌํ˜„

bind ํŒจํ‚ค์ง€์— ServletRequestDataBinder ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•œ๋‹ค.

bind(), isPrimitiveType(), createValueObject(), findSetter()์˜ ์ด 4๊ฐœ ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

 

ServletRequestDataBinder.java

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
public class ServletRequestDataBinder {
    /**
     * ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์ž๋ฐ” ๊ฐ์ฒด์— ๋‹ด์•„์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
     * Front controller์—์„œ ํ˜ธ์ถœ
     * @param request ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’
     * @param dataType ๋ฐ์ดํ„ฐ ํƒ€์ž…
     * @param dataName ๋ฐ์ดํ„ฐ ์ด๋ฆ„
     * @return ๋ฐ์ดํ„ฐ ๊ฐ์ฒด
     * @throws Exception
     */
    public static Object bind(ServletRequest request, Class<?> dataType, String dataName) throws Exception {
        // ๋ฐ์ดํ„ฐ ํƒ€์ž…์ด primitive type์ธ์ง€ ํ™•์ธ
        if(isPrimitiveType(dataType)) {
            // primitive type์ด๋ฉด ์ฆ‰์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜
            return createValueObject(dataType, request.getParameter(dataName));
        }
 
        // ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…
        Set<String> paramNames = request.getParameterMap().keySet();
        for(String s:paramNames) {
            System.out.println(s);
        }
        // ๊ฐ’์„ ์ €์žฅํ•  ๊ฐ์ฒด ์ƒ์„ฑ
        Object dataObject = dataType.getDeclaredConstructor.newInstance();
        Method m = null;
 
        // ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐœ์ˆ˜๋งŒํผ ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด์— ๊ฐ’์„ ํ• ๋‹น
        for(String paramName: paramNames) {
            // ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…๊ณผ ์ผ์น˜ํ•˜๋Š” setter() ์ฐพ์Œ
            m = findSetter(dataType, paramName);
            if(m != null) {
                // setter()๋ฅผ ์ฐพ์•˜์œผ๋ฉด dataObject์— ๋Œ€ํ•ด ํ˜ธ์ถœ
                // setter() ํ˜ธ์ถœ ์‹œ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ๊ฐ’์„ ํ˜•์‹์— ๋งž์ถฐ ๋„˜๊น€
                // invoke() : ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
                // getParameterTypes() : ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜
                m.invoke(dataObject, createValueObject(m.getParameterTypes()[0], request.getParameter(paramName)));
            }
        }
 
        return dataObject;
    }
 
    /**
     * type์ด primitive type์ธ์ง€ ํ™•์ธ
     * @param type
     * @return int, long, float, double, boolean, java.util.Date, java.lang.String ํƒ€์ž…์ด๋ฉด true, ์•„๋‹ˆ๋ฉด false
     * byte, short๋Š” ํ•„์š” ์‹œ ์ถ”๊ฐ€
     */
    private static boolean isPrimitiveType(Class<?> type) {
        if(type.getName().equals("int"|| type == Integer.class ||
        type.getName().equals("long"|| type == Long.class ||
        type.getName().equals("float"|| type == Float.class ||
        type.getName().equals("double"|| type == Double.class ||
        type.getName().equals("boolean"|| type == Boolean.class ||
        type == Date.class || type == String.class) {
            return true;
        }
 
        return false;
    }
 
    /**
     * Primitive type์˜ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
     * @param type
     * @param value
     * @return
     */
    private static Object createValueObject(Class<?> type, String value) {
        if(type.getName().equals("int"|| type == Integer.class) {
            return Integer.valueOf(value);
        } else if(type.getName().equals("long"|| type == Long.class) {
            return Long.valueOf(value);
        } else if(type.getName().equals("float"|| type == Float.class) {
            return Float.valueOf(value);
        } else if(type.getName().equals("double"|| type == Double.class) {
            return Double.valueOf(value);
        } else if(type.getName().equals("boolean"|| type == Boolean.class) {
            return Boolean.valueOf(value);
        } else if(type == Date.class) {
            return java.sql.Date.valueOf(value);
        } else {
            return value;
        }
    }
 
    /**
     * ํด๋ž˜์Šค(type)์„ ์กฐ์‚ฌํ•ด์„œ ์ฃผ์–ด์ง„ ์ด๋ฆ„(name))๊ณผ ์ผ์น˜ํ•˜๋Š” setter()๋ฅผ ์ฐพ๋Š”๋‹ค.
     * @param type
     * @param name
     * @return
     */
    private static Method findSetter(Class<?> type, String name) {
        // ๋ฐ์ดํ„ฐ ํƒ€์ž…์—์„œ ๋ฉ”์†Œ๋“œ ๋ชฉ๋ก ์–ป์Œ
        // getMethods() : ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ชจ๋“  public ๋ฉ”์†Œ๋“œ ๋ชฉ๋ก์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜
        Method[] methods = type.getMethods();
 
        String propName = null;
 
        // ๋ฉ”์†Œ๋“œ ๋ชฉ๋ก์„ ๋ฐ˜๋ณตํ•˜์—ฌ setter()์— ๋Œ€ํ•ด์„œ๋งŒ ์ž‘์—… ์ˆ˜ํ–‰
        for(Method m: methods) {
            if(!m.getName().startsWith("set")) continue;
            // setter()์ผ ๊ฒฝ์šฐ
            // ๋ฉ”์†Œ๋“œ ์ด๋ฆ„์—์„œ 'set' ์ œ์™ธ
            propName = m.getName().substring(3);
            // ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธ
            if(propName.toLowerCase().equals(name.toLowerCase())) {
                //์ผ์น˜ํ•˜๋Š” setter()๋ฅผ ์ฐพ์œผ๋ฉด ๋ฐ˜ํ™˜
                return m;
            }
        }
 
        return null;
    }
}
cs

 

1) bind()

Front controller์—์„œ ํ˜ธ์ถœํ•  public ๋ฉ”์†Œ๋“œ์ด๋‹ค. request, ๋ฐ์ดํ„ฐ ํƒ€์ž…, ๋ฐ์ดํ„ฐ ์ด๋ฆ„์„ ๋ฐ›์•„์„œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ์ผ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

public static Object bind(ServletRequest request, Class<?> dataType, String dataName) throws Exception {
    ...
    return dataObject;
}

 

์ฒซ ๋ฒˆ์งธ ์ฝ”๋“œ๋Š” dataType์ด primitive type์ธ์ง€ ํ™•์ธํ•˜๋Š” ์ผ์ด๋‹ค. Primitive type์ผ ๊ฒฝ์šฐ ์ฆ‰์‹œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

if (isPrimitiveType(dataType)) {
    return createValueObject(dataType, request.getParameter(dataName));
}

 

Primitive type์ด ์•„๋‹ˆ๋ฉด ๋จผ์ € request ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„ ๋ชฉ๋ก์„ ์–ป๋Š”๋‹ค.

Set<String> paramNames = request.getParameterMap().keySet();

request.getParameterMap()์€ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„๊ณผ ๊ฐ’์„ ๋งต ๊ฐ์ฒด์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๋•Œ๋ฌธ์— keySet()์œผ๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„ ๋ชฉ๋ก๋งŒ ๊บผ๋‚ธ๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

new ์—ฐ์‚ฐ์ž๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋“ฏ Class.getDeclaredConstructor().newInstance() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด์„œ๋„ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

Object dataObject = dataType.getDeclaredConstructor().newInstance();

 

๋‹ค์Œ์€ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐœ์ˆ˜๋งŒํผ for๋ฌธ์„ ๋Œ๋ ค setter๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๊ฐ’์„ ํ• ๋‹นํ•œ๋‹ค.

Method m = null;

for (String paramName: paramNames) {
    m = findSetter(dataType, paramName);
    if (m != null) {
        m.invoke(dataObject, createValueObject(m.getParameterTypes()[0], request.getParameter(paramName)));
    }
}

findSetter()๋Š” ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ช…์„ ์ „๋‹ฌํ•˜์—ฌ setter()๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

invoke()๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋กœ ์ผ๋ฐ˜์ ์œผ๋กœ ํ•œ ์ธ์Šคํ„ด์Šค์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ

์ธ์Šคํ„ด์Šค.๋ฉ”์†Œ๋“œ(์ธ์ž๊ฐ’)์œผ๋กœ ํ˜ธ์ถœํ•œ๋‹ค๋ฉด invoke() ๋ฉ”์†Œ๋“œ๋Š” invoke(์ธ์Šคํ„ด์Šค, ์ธ์ž๊ฐ’)๊ณผ ๊ฐ™์ด ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.

 

2) isPrimitiveType()

isPrimitiveType() ๋ฉ”์†Œ๋“œ๋Š” ์ด ํด๋ž˜์Šค ๋‚ด๋ถ€์— ์ •์˜๋œ private ๋ฉ”์†Œ๋“œ๋กœ int, long, float, double, boolean, java.util.Date, java.lang.String ํƒ€์ž…์„ primitive type์œผ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ true๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

3) createValueObject()

createValueObject() ๋ฉ”์†Œ๋“œ๋Š” ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ๊ฐ–๊ณ  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

if (type.getName().equals("int) || type == Integer.class) {
    return Integer.valueOf(value);
}
...

 

4) findSetter()

findSetter()๋Š” ํด๋ž˜์Šค๋ฅผ ์กฐ์‚ฌํ•˜์—ฌ ์ฃผ์–ด์ง„ name๊ณผ ์ผ์น˜ํ•˜๋Š” setter() ๋ฉ”์†Œ๋“œ๋ฅผ ์ฐพ๋Š”๋‹ค.

 

๋จผ์ € Class์—์„œ ๋ฉ”์†Œ๋“œ ๋ชฉ๋ก์„ ์–ป๋Š”๋‹ค.

Method[] methods = type.getMethods();

 

๋ฉ”์†Œ๋“œ ๋ชฉ๋ก์„ ๋ฐ˜๋ณตํ•˜์—ฌ setter()๋ฅผ ์ฐพ๋Š”๋‹ค.

for (Method m: methods) {
    if (!m.getName().startsWith("set")) continue;
...

 

Setter()์ผ ๊ฒฝ์šฐ ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์ด name์ด๋ฉด ๋ฉ”์†Œ๋“œ๊ฐ€ setName()์ธ์ง€ ํ™•์ธํ•œ๋‹ค.

propName = m.getName().substring(3);
if (propName.toLowerCase().equals(name.toLowerCase())) {
    return m;
}

์ผ์น˜ํ•˜๋Š” setter()๋ฅผ ์ฐพ์œผ๋ฉด ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

์‚ฌ์šฉ๋œ ๋ฆฌํ”Œ๋ž™์…˜ API

๋ฆฌํ”Œ๋ž™์…˜ API๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์— ์–ด๋–ค ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š”์ง€, ๋ฉ”์†Œ๋“œ์˜ ์ด๋ฆ„์€ ๋ฌด์—‡์ธ์ง€, ํด๋ž˜์Šค์˜ ์ด๋ฆ„์€ ๋ฌด์—‡์ธ์ง€ ๋“ฑ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. Controller๊ฐ€ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์š”์ฒญ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์„ธํŒ…ํ•˜๋Š” ๊ฒƒ์„ ์ž๋™ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ ๋ฆฌํ”Œ๋ž™์…˜ API ๋ชฉ๋ก์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

๋ฉ”์†Œ๋“œ ์„ค๋ช…
Class.getDeclaredConstructor().newInstance() ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑ
Class.getName() ํด๋ž˜์Šค ์ด๋ฆ„ ๋ฐ˜ํ™˜
Class.getMethods() ํด๋ž˜์Šค์— ์„ ์–ธ๋œ ๋ชจ๋“  public ๋ฉ”์†Œ๋“œ ๋ชฉ๋ก์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜
Method.invoke() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ
Method.getParameterTypes() ๋ฉ”์†Œ๋“œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜

 

References

์—ดํ˜ˆ๊ฐ•์˜ ์ž๋ฐ” ์›น ๊ฐœ๋ฐœ ์›Œํฌ๋ถ(ํ”„๋ฆฌ๋ ‰, 2016, ์—„์ง„์˜)

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€