이어서 CURD가 가능한 React View를 구성해보도록 하겠습니다 

View는 지난 전자정부 프로젝트 때 제작했던 소스를 재사용하겠습니다

 

추가된 패키지 구성은 다음과 같습니다 

application.yml (Spring Boot 내장 logger 설정을 추가하였습니다)

 

지난 프로젝트의 기존 소스를 그대로 사용하기 위해서

Controller에서 사용했던 Object Mapper와 Dozer Mapper의 의존성을 추가하겠습니다

 

build.gradle

1
2
3
4
    exclude group: 'org.slf4j'
}
 
 

 

우선 CURD 서비스를 수행할 method들을 추가하겠습니다

 

CustomerService.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
 
import org.springframework.stereotype.Service;
 
@Service
public class CustomerService {
    
    @Autowired
    CustomerRepository customerRepository;
 
    public Iterable<Customer> findAll() {
        return customerRepository.findAll();
    }
 
    public Iterable<Customer> selectList(Customer customer) {
        return customerRepository.findAll();
    }
 
    public Customer insert(Customer customer) {
        return customerRepository.save(customer);
    }
 
    public boolean update(Customer customer) {
        return true;
    }
 
    public boolean delete(Customer customer) {
        return true;
    }
}
 
 

 

페이지의 메인단 화면입니다

기존에 사용했던 tiles 대신에 mustache의 include를 이용해 레이아웃을 나눠봤습니다

 

react.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{{>layout/ref}}
 
<script data-plugins="transform-es2015-modules-umd" type="text/babel" src="/resources/script/others.jsx"></script>
<script data-plugins="transform-es2015-modules-umd" type="text/babel" src="/resources/script/main.jsx"></script>
<script data-plugins="transform-es2015-modules-umd" type="text/babel">
import Layout, {Head, Nav, Foot} from './others';
import Main from './main';
 
{{>layout/head}}
 
 
                <Main list="{{dataList}}"/>
                
                
{{>layout/foot}}
 
ReactDOM.render(html, document.getElementById('mydiv'));
 
</script>
 
</html>
 
 

 

사실 프로젝트를 진행하면서 style.css를 잘 인식 못해서

main.css도 포함해서 html에 옮겨 include 하였습니다

 

ref.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
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <!-- <link rel="stylesheet" href="${pageContext.request.contextpath}/resources/css/style.css"></link>
    <link rel="stylesheet" href="${pageContext.request.contextpath}/resources/css/main.css"></link> -->
    
    <style type="text/css">
        html, body {
            height:100%;
            margin:0;
        }
        
        span, label {
            display:inline-block;margin:6px 25px 8px 25px;
            font-size:18px;
        }
        
        input {
            padding:5px;margin-top:-15px
        }
        
        #head {
            width:100%;height:60px;
            background-color:white;
        }
        
        #head a {
            display: inline-block;margin-left:20px;
            text-decoration: none;color:black;
        }
        
        #head button {
            float: right;margin: 8px 10%;
            font-size: 20px;padding:8px 15px;
            background-color: transparent;
            border:0.1em solid #333;border-radius:8px;
        }
        
        #head button:hover {;
            background-color: #333;
            color:white;
        }
        
        #nav {
            width:100%;
            border-top:1px solid lightgrey;
            background-color: #333;
            text-align:center;
            margin-bottom: -5px;
        }
        
        ul {
          display:inline-block;
          list-style-type:none;
          margin:0;padding:0;overflow:hidden;
          background-color: transparent;
        }
        
        li {
          float: left;
        }
        
        li a {
          display: block;
          text-align: center;
          padding: 14px 26px;
          text-decoration: none;
          color: black;
        }
        
        li a:hover {
        
        }
        
        #nav ul {
        }
        
        #nav li {
        }
        
        #nav li a {
          color: white;
        }
        
        #nav li a:hover {
          background-color: #111;
          border-bottom:0.1em solid blue;
        }
        
        #body{
            width:80%;height:76%;padding:2% 10% 2% 10%;
            background-color:lightgrey;
        }
        
        #main {
            width:88%;height:90%;min-width:800px;min-height:490px;
            padding:2% 6%;border-radius:0.5%;
            background-color:white;
        }
        
        #main table {
            display:inline-block;
            background-color:lightgrey;
            border-collapse: collapse;
            font-size: 18px;width:50%;height:58%;
        
        }
        
        #main th {
            padding:10px 24px;
            background-color: grey
        }
        
        #main td {
            padding:10px 24px;
            border-bottom:1px solid grey;
        }
        
        #main ul {
        }
        
        #main li {
        }
        
        #main li a {
            border:1.5px solid grey;
            color:white;
            border-radius:5px;
            margin:8px 8px 0px 8px;
        }
        
        #main li a:hover {
          background-color: grey;
        }
        
        #foot {
            display: table;
            width:96.1%;height:150px;padding:2%;
            background-color:grey;
            color:rgb(32,32,32);
        }
        
        #foot p {
          display: table-cell;
          line-height: 1.5;
          text-align: right;
          vertical-align: bottom;
        }
        
        .default {
            background-color: white
        }
        .hover {
            background-color: lightblue
        }
        .clicked {
            background-color: blue;
            color:white;
        }
    </style>
    
<script type="text/javascript" src="/resources/script/common.js"></script>
    
    
</head>    
 
<div id="mydiv"></div>
 
 
 

 

head.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const html=
    <body>
 
        <div id="head">
            <Head />
        </div>
        
        <div id="nav">
            <Nav />
        </div>
 
        <div id="body">
            <div id="main">
 
 

 

foot.html

1
2
3
4
5
6
7
8
            </div>
        </div>
 
        <div id="foot">
            <Foot />
        </div>
 
    </body>
s

 

이번 프로젝트는 React로 View를 구성하는 것이므로 

주요 소스들이 .jsx 파일에 있습니다 

 

others.jsx (이번 React View에서 Layout 엘리먼트들을 정의하는 소스입니다)

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
export class Head extends React.Component {
    constructor(props) {
        super(props);
    }
 
    render() {
        return (
            <div>
 
                <a href="#"><h2>TEST Site</h2></a>
                <button>메뉴6</button>
 
            </div>
        );
    }
}
 
export class Nav extends React.Component {
    constructor(props) {
        super(props);
    }
 
    render() {
        return (
            <div>
 
                <ul className="hlist">
                    <li><a href="#" onClick={function(){location.href='/react';}}>list</a></li>
                    <li><a href="#">메뉴2</a></li>
                    <li><a href="#">메뉴3</a></li>
                    <li><a href="#">메뉴4</a></li>
                    <li><a href="#">메뉴5</a></li>
                </ul>
 
            </div>
        );
    }
}
 
export class Foot extends React.Component {
    constructor(props) {
        super(props);
    }
 
    render() {
        return (
            <div>
 
                <p>copyright by webman</p>
 
            </div>
        );
    }
}
 
 
export default class Layout extends React.Component {
    constructor(props) {
        super(props);
    }
 
    render() {
        return (
            <div>
 
                <Head />
                <Nav />
                {this.props.list}
                <Foot />
 
            </div>
        );
    }
}
 
 

 

main.jsx (이번 React View에서 Main 화면 엘리먼트를 정의하는 소스입니다)

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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
function Bar() {
    const style1 = {
            display:'inline-block',
            textAlign:'right',
            borderTopLeftRadius:5,
            paddingTop:3+'px',
            paddingLeft:5+'px',
            width:100+'%',
            backgroundColor:'black'
        };
    
        return (
            <div style={style1}>
 
    <span>hi</span>
    <ul className="hlist">
        <li><a href="#" onClick={function(){doAjax('c.do');}}>C</a></li>
        <li><a href="#" onClick={function(){doAjax('u.do');}}>U</a></li>
        <li><a href="#" onClick={function(){r();}}>R</a></li>
        <li><a href="#" onClick={function(){doAjax('d.do');}}>D</a></li>
    </ul>
 
            </div>
          );
}
 
function Input() {
        
        return (
            <div style={{float:'right',height:50+'%',width:46+'%',margin:1.8+'%'}}>
 
        <ul>
            <li>
                <label>id</label><input type="" name="id" placeholder="Id는 자동생성 됩니다" readOnly/>
            </li>
            <li>
                <label>firstName</label><input type="" name="firstName"/>
            </li>
            <li>
                <label>lastName</label><input type="" name="lastName"/>
            </li>
            <li>
                <label>ref</label><input type="" name=""/>
            </li>
        </ul>
 
            </div>
          );
}
 
function ListItems(list) {
    const array=[];
    $.each(list, function(idx, val) {
        const list=JSON.parse(val);
        for(var i=0; i<list.length; i++) {
            array.push(list[i]);
        }
    });
    console.log(array[0]);{/**/}
 
      return (
          <tbody>
 
        {array.map(function(value, index){
            return (
                <tr>
                    <td className="default" key={index}>{value.id}</td>
                    <td className="default" key={index}>{value.firstName}</td>
                    <td className="default" key={index}>{value.lastName}</td>
                    <td className="default" key={index}></td>
                </tr>
            );
        })}
 
        </tbody>
      );
}
 
function List({list}) {
 
        return (
            <div>
                
    <form name="form" id="form" style={{margin:0+'px'}}>
 
<div style={{display:'inline-block',height:100+'%',width:100+'%'}}>
    <table cellPadding="0" cellSpacing="0">
        
        <tr>
            <th>id</th>
            <th>firstName</th>
            <th>lastName</th>
            <th>ref</th>
 
        </tr>
 
            <ListItems data={list}/>
        
    </table>
 
    <Input/>
 
</div>
 
</form>
 
            </div>
          );
}
 
export default class Main extends React.Component {
    constructor(props) {
        super(props);
    }
 
    Bar() {}
    Input() {}
    List(props) {}
 
    render() {
        return (
            <div>
            
                <Bar />
                <List list={this.props.list}/>
                {/*{this.props.list}*/}
            </div>
        );
    }
}
 
function r() {
    $('input[name=id]').val($('.clicked:eq(0)').html());
    $('input[name=firstName]').val($('.clicked:eq(1)').html());
    $('input[name=lastName]').val($('.clicked:eq(2)').html());
}
 
function ajaxList() {
    $.ajax({ 
        url: "/list.do"// 클라이언트가 HTTP 요청을 보낼 서버의 URL 주소 
        type: "GET"// HTTP 요청 메소드(GET, POST 등)  
        dataType: "json"// 서버에서 보내줄 데이터의 타입  
        
        success:function(returnMap){
            //console.log(returnMap.api);
            //console.log(returnMap.dbData);
            alert(returnMap.dbData);
            ListItems(returnMap.dbData);
        },
        
        error:function(jqXHR, status, errorThrown){
            //console.log(jqXHR.responseText);
        }
    });
}
 
function doAjax(url){
    var params = $("#form").serialize();
    $.ajax({ 
        url: "/"+url, // 클라이언트가 HTTP 요청을 보낼 서버의 URL 주소 
        data: params, // HTTP 요청과 함께 서버로 보낼 데이터 
        type: "POST"// HTTP 요청 메소드(GET, POST 등)  
        dataType: "json"// 서버에서 보내줄 데이터의 타입  
        
        success:function(returnMap){
            //console.log(returnMap.api);
            ajaxList();
        },
        
        error:function(jqXHR, status, errorThrown){
            //console.log(jqXHR.responseText);
            ajaxList();
        }
    });
}
 
$(document).ready(function() {
    //ajaxList();
 
    $("#main td").mouseover(function(e){
        $(e.target).parent().children('td').removeClass('default');
        $(e.target).parent().children('td').addClass('hover');
    });
    $("#main td").mouseout(function(e){
        $(e.target).parent().children('td').removeClass('hover');
        $(e.target).parent().children('td').addClass('default');
    });
 
    $(document).click(function(e) {
           if($(e.target).is("#main td")) {
        
            if($(e.target).hasClass('clicked')) {
                $('td').removeClass();
                $('td').addClass('default');
            
            } else {
                $('td').removeClass();
                $('td').addClass('default');
            
                $(e.target).parent().children('td').removeClass();
                $(e.target).parent().children('td').addClass('clicked');
            
                //$('input[name=id]').val($(e.target).siblings(':nth-child(1)').html());
                //$('input[name=firstName]').val($(e.target).siblings(':nth-child(2)').html());
                //$('input[name=lastName]').val($(e.target).siblings(':nth-child(3)').html());
            }
        } else {    
 
        }
    });
});    
 
 
 

 

마지막으로 Controller를 구성하도록하겠습니다

 

CustomerController.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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
 
 
import javax.annotation.PostConstruct;
 
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
 
import com.fasterxml.jackson.databind.ObjectMapper;
 
@Controller
@RequestMapping("/")
public class CustomerController {
    
    Logger LOGGER = LoggerFactory.getLogger(CustomerController.class);
    
    @Autowired
    AmazonProperties amazonProperties;
    
    @Autowired
    CustomerService customerService;
    
    @RequestMapping(value = "/react", method=RequestMethod.GET)
    public ModelAndView main(/* Map<String, Object> model, */
                                ModelAndView mav) throws JsonProcessingException, ParseException {
        String id=amazonProperties.getAssociateId();
        
        Iterable<Customer> list=customerService.findAll();
        
        ObjectMapper mapper = new ObjectMapper();
        String jsonStr = mapper.writeValueAsString(list);
        JSONParser parser = new JSONParser();
        JSONArray jsonArr = (JSONArray) parser.parse(jsonStr);
        
        mav.addObject("dataList", jsonArr);
        mav.setViewName("main/react");
        return mav;
    }
    
    Customer customer;
    ObjectMapper oMapper;
    DozerBeanMapper dMapper;
    
    @PostConstruct
    public void initController(){
        customer = new Customer();
        oMapper = new ObjectMapper();
        dMapper = new DozerBeanMapper();
    }
    
    public Iterable<Customer> getList(Customer customer) throws Exception {
        
        return customerService.selectList(customer);
    }
    
    @RequestMapping(value = "/list.do")
    public ResponseEntity<?> getlist(@RequestParam Map<String, Object> paramMap
                                   ) throws Exception {
        LOGGER.debug("getlist() called");
        paramMap.put("api""alist");
 
        paramMap.put("dbData", getList(customer));
        System.out.println(getList(customer));
        
        String jsonString = oMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paramMap);
        return new ResponseEntity<String>(jsonString, HttpStatus.OK);
    }
    
    @RequestMapping(value = "/c.do", method={RequestMethod.POST})
    public ResponseEntity<?> create(@RequestParam Map<String, Object> paramMap,
                                    HttpServletRequest request
                                    ) throws Throwable {
        paramMap.put("api""create");
        customer = dMapper.map(paramMap, Customer.class);
        LOGGER.debug("create() sampleVo: "+customer);
        
        Customer result=customerService.insert(customer);
        LOGGER.debug("create() result: "+result);
        paramMap.put("result", result);
        
        String jsonString = oMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paramMap);
        return new ResponseEntity<String>(jsonString, HttpStatus.OK);
    }
    
    @RequestMapping(value = "/u.do", method={RequestMethod.POST})
    public ResponseEntity<?> update(@RequestParam Map<String, Object> paramMap, 
                                    HttpServletRequest request
                                    ) throws Throwable {
        paramMap.put("api""update");
        customer = dMapper.map(paramMap, Customer.class);
        LOGGER.debug("update() sampleVo: "+customer);
 
        boolean result=customerService.update(customer);
        LOGGER.debug("update() result: "+result);
        paramMap.put("result", result);
        System.out.println(result);
        
        String jsonString = oMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paramMap);
        return new ResponseEntity<String>(jsonString, HttpStatus.OK);
    }
    
    @RequestMapping(value = "/d.do", method={RequestMethod.POST})
    public ResponseEntity<?> delete(@RequestParam Map<String, Object> paramMap, 
                                    HttpServletRequest request
                                    ) throws Throwable {
        paramMap.put("api""delete");
        customer = dMapper.map(paramMap, Customer.class);
        LOGGER.debug("delete() sampleVo: "+customer);
        
        boolean result=customerService.delete(customer);
        LOGGER.debug("delete() result: "+result);
        paramMap.put("result", result);
        
        String jsonString = oMapper.writerWithDefaultPrettyPrinter().writeValueAsString(paramMap);
        return new ResponseEntity<String>(jsonString, HttpStatus.OK);
    }
}
 
 
 

 

완성되셨다면 다음과 같은 화면을 확인하실 수 있습니다

 

Ajax로 list를 로딩하는 부분,

MariaDB utf-8 인코딩 설정은 생략되어 있는 점 참고해주시기 바랍니다

수고하셨습니다

 

+ Recent posts