Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
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
Archives
Today
Total
관리 메뉴

우리마의 웹 개발

[Spring Boot] REST API 구축과 JSON 데이터 를 GetMapping으로 SELECT문 구현 본문

WEB/Spring Boot

[Spring Boot] REST API 구축과 JSON 데이터 를 GetMapping으로 SELECT문 구현

우리마 2020. 2. 14. 15:00

나도 Spring Boot와 REST API 구축을 처음 접해보는 실정에서 회사 프로젝트로 개발을 할 일이 생겨 REST API를 Boot환경에서 구축하면서 알게 된 것을 끄적여본다..

이 글을 읽는 사람들이 Spring에 대한 전반적인 개념과 Rest가 무엇인지는 대강 알고있다는 전제하에 글을 쓴다. 또한 실무 프로젝트를 기반으로 작성해서 패키지명과 파일명이 좀 불편하더라도 양해 바란다.

 

개발 환경
STS 3.9.11.RELEASE
Spring Boot 2.2.4.RELEASE
DB POSTGRESQL
MyBatis ver 3.4.6
Package 구조

프로젝트 패키지 구조

먼저 프로젝트 패키지 구조인데 기능에 맞게 분류해놨다.

프로젝트의 큰 틀은 Spring MVC 패턴을 벗어나진 않는다. 다만 VO라는 용어 보단 DTO를 사용하며 Spring설정 파일이 없으며 xml파일은 SQL 쿼리문 파일만 있다. 그리고 select문을 실행 할 때 조건으로 받아오는 parameter들을 따로 Class로 정의해 논 DTO가 있고, 결과 화면에 뿌릴, 그러니까 ResultType을 Class로 따로 정의해노은 DTO가 있다.

자세한 소스와 경로는 아래에서 설명하겠다. 대강 살펴보길 바란다.

 

Controller
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
package com.SpringBoot.Default.web.controller;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
 
import com.SpringBoot.Default.web.response.info.GetSopNameListResponseDTO;
import com.SpringBoot.Default.web.service.SopMissionInformationService;
 
@RestController
@RequestMapping("sop")
public class SopMissionInformationController {
    
    private static final Logger log = LoggerFactory.getLogger(SopMissionInformationController.class);
    
    @Resource
    private SopMissionInformationService service;
    
    @GetMapping("/select")
    public GetSopNameListResponseDTO selectSopMisn(@RequestParam String sop_mng_no) throws Exception{
        log.info("/select 호출 @GetMapping");
        try {
            log.info("sop_mng_no : "+sop_mng_no);
        } catch (Exception e) {
            log.debug("error : "+e.getMessage());
        }
        return service.selectSopMisn(sop_mng_no);
    }
}
 
 

파일명 : SopMissionInformationController.java

경로 : com.SpringBoot.Default.web.controller

14 LINE : @RestController 어노테이션은 @Controller에 @ResponseBody를 포함하고 있다. 

이것은 Rest API를 구축하는 핵심중 하나로 데이터가 ViewResolver를 거치지 않고 바로  Client로 전송된다.

15 LINE : Controller 클래스 위에 @RequestMapping 어노테이션으로 공통 요청 URI를 정의할 수 있다.

23 LINE : REST API에서 CRUD를 구축할 때 각각의 기능마다 데이터 전달 방식이 다르다.

 

SELECT - GET

INSERT - POST

UPDATE - PUT 또는 PATCH

DELETE - DELETE

 

현재 SELECT문을 구현하고 있으므로 @GetMapping을 해주도록 한다.

그리고 GET방식으로 전달받은 data인 sop_mng_no를 Service단으로 넘겨준다.

 

Service를 작성하기 전에 DTO들부터 하나하나 작성해보자.

DTO
1
2
3
4
5
6
7
8
9
10
11
package com.SpringBoot.Default.mybatis.model;
 
import lombok.AllArgsConstructor;
import lombok.Data;
 
@Data
@AllArgsConstructor
public class GetSopNameListEntity {
    private String sop_mng_no;
}
 
 

파일명 : GetSopNameListEntity.java

경로 : com.SpringBoot.Default.mybatis.model

이 Class는 GET방식으로 받는 Parameter들을 선언해놓은 클래스이다. 그러니까 Controller에서 @RequestParam으로 받아오는 녀석들이다. SQL에서 #{} 여기에 들어갈 녀석들이란 말이다! 변수명은 DB 테이블의 칼럼명과 같이 해주는 것이 좋다.

@Data 어노테이션은 getter, setter를 자동 생성해주는 녀석이고

@AllArgsConstructor 어노테이션은 생성자를 자동 생성해주는 녀석이다.

저~기 Controller에서 sop_mng_no라는 칼럼명을 GET방식으로 받아오기로 했으니까 똑같이 이 Class에 선언해 주면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
package com.SpringBoot.Default.web.response.info;
 
import java.util.List;
 
import lombok.Data;
 
@Data
public class GetSopNameListResponseDTO {
    int idx;
    List<WebUserListSopNameModel> sop;
}
 
 
 

파일명 : GetSopNameListResponseDTO.java

경로 : com.SpringBoot.Default.web.response.info

이 파일은 SELECT 한 결과를 나타내는 칼럼들을 선언해놓은 Class이다. 여러 행이 나올 수도 있으니까 그 결과 칼럼들을 다시 Class로 작성하고 List로 묶어놨다.

idx는 순번을 매기는 임의적인 변수이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.SpringBoot.Default.web.response.info;
 
 
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
@Data
@AllArgsConstructor
public class WebUserListSopNameModel {
    private String sop_mng_no;
    private String cntrmsr_org_cd;
    private String prcafs_part_sn;
    private String misn_sn;
    private String misn_nm;
}
 
 
 

파일명 : WebUserListSopNameModel.java

경로 : com.SpringBoot.Default.web.response.info

이 Class에 이제 SELECT 할 때 뽑아올 칼럼들을 선언하는 것이다. 물론 변수명은 칼럼명과 동일하게 하는 것이 정신건강에 이롭다.

헉.. 헉.. 거의 다했다...

 

이렇게 뿌리는 데이터와 받는 데이터 들을 Class로 다 작성해 놓은 뒤에 Service를 작성해보자

Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.SpringBoot.Default.web.service;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.SpringBoot.Default.mybatis.mapper.SopMisnMapper;
import com.SpringBoot.Default.mybatis.model.GetSopNameListEntity;
import com.SpringBoot.Default.web.response.info.GetSopNameListResponseDTO;
 
@Service
public class SopMissionInformationService implements SopMissionInformationServiceImp {
    
    @Autowired
    private SopMisnMapper mapper;
    
    @Override
    public GetSopNameListResponseDTO selectSopMisn(String sop_mng_no) {
        return mapper.selectSopMisn(new GetSopNameListEntity(sop_mng_no));
    }
 
}
 
 

파일명 : SopMissionInformationService.java

경로 : com.SpringBoot.Default.web.service

interface 파일은 생량 하겠다. 어차피 함수 원형만 있는 파일이니까.. 다들 알잖아?

14 Line : mapper Class가 있는데 mapper는 DAO랑 비~슷한 역할이다. 얘도 빈등 록 해줘야 되니까 @Autowired 해준 거고 

18 Line : 여기서 재밌는 게 mapper Class호출하는데 파라미터로 Entity의 생성자를 호출해서 Entity의 객체를 mapper로 보낸다.

그럼으로써 여기서 이제 확실해진 거다 Entity Class가 아~까 저~기 위에서 Get방식으로 받는 데이터를 선언해놓은 Class라고 했잖아? 그걸 DAO로 보내는 거니까 SQL을 실행할 수 있게 되는 것이다. 근데 mapper랑 DAO랑 쫌 다른 게 mapper는 interface인데 아무튼 자세한 건 sql을 보면 좀 더 이해가 될 거다ㅋㅋ...

mapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.SpringBoot.Default.mybatis.mapper;
 
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Service;
 
import com.SpringBoot.Default.mybatis.model.GetSopNameListEntity;
import com.SpringBoot.Default.web.response.info.GetSopNameListResponseDTO;
 
@Service
@Mapper
public interface SopMisnMapper {
    //SOP 조회
    GetSopNameListResponseDTO selectSopMisn(GetSopNameListEntity dto);
}
 
 

파일명 : SopMisnMapper.java

경로 : com.SpringBoot.Default.mybatis.mapper

여기서 함수명이 selectSopMisn인데 이것이 바로 SQL파일에서 select태그의 id가 될 것이란 것이다. 그리고 @mapper 어노테이션 이거 또한 매핑할 때 필요한 중요한 어노테이션인데. 이 어노테이션을 사용하고 main class에서 mapper클래스의 경로를 적어줘야 된다.

@MapperScan("com.SpringBoot.Default.mybatis.mapper") //package path of mapper interface

이렇게...

SQL
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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
<mapper namespace="com.SpringBoot.Default.mybatis.mapper.SopMisnMapper">
    
    <select id="selectSopMisn" resultMap="GetSopNameListResponseDTO" 
parameterType="com.SpringBoot.Default.mybatis.model.GetSopNameListEntity">
        SELECT 1 AS IDX , *
        FROM TN_SOP_MISN_INFO
        WHERE SOP_MNG_NO = #{sop_mng_no}
    </select>
 
    <resultMap id="GetSopNameListResponseDTO" 
type="com.SpringBoot.Default.web.response.info.GetSopNameListResponseDTO">
        <result property="idx" column="idx"/>
        <collection property="sop" javaType="ArrayList" 
ofType="com.SpringBoot.Default.web.response.info.WebUserListSopNameModel">
        <id property="sop_mng_no" column="sop_mng_no" />
        <result property="cntrmsr_org_cd" column="cntrmsr_org_cd"/>
        <result property="prcafs_part_sn" column="prcafs_part_sn"/>
        <result property="misn_sn" column="misn_sn"/>
        <result property="misn_nm" column="misn_nm"/>
        </collection>
    </resultMap>
 
</mapper>
 
>

파일명 : SopMisnMapper.xml

경로 : resources.com.SpringBoot.Default.mybatis.mapper

SQL 파일에서 진짜 진짜 헷갈린다.

일단 mapper 태그의 namespace는 mapper interface의 경로이다.

select 태그의 id는 mapper의 함수 명이고 resultMape의 명은 아무러 캐나 지어줘도 된다. 아래에서 resultMap태그의 id와 동일하게만 해주면 된다. parameterType은 아까부터 말했듯이 Entity클래스인데 그 경로까지 적어줘야 된다.

resultMap을 보자

type 은 아~까 저~기 위에서 GetSopNameListResponseDTO라고 헀자나? 클래스 명과 경로까지 적어주면 된다.

근데 여기서 또 진짜로 중요한 게GetSopNameListResponseDTO 클래스는 List만 있잖아 그래서 List안의 class를 찾아갈 수 있게 해줘야 되는데.... 그래서 collection태그로 propery는 List의 변 수명이고 type 적어주고 ofType은  List안의 class명과 경로이다 즉. WebUserListSopNameModel이 클래스 아~까 저~위에서 말한 거다 함 올려보자....

그리고 이제 idx는 list 아니니까 따로 적어주고 list안에 있는 것들은 칼럼명과 변수명 위에처럼 적어주면 된다. 근데 또 웃긴 게 id 값은 꼭 하나 있어야 되더라.....

 

여기까지 작성해주고 project -> clean 해주고 프로젝트를 시작해보자

일단 테스트 테이블은 저건대 테스트할 데이터를 하나 집어넣어놨다.

POSTMAN 프로그램을 통해서 저 데이터를 SELECT 할 건데 JSON 데이터로 가져올 거다.

 

결과를 보자

이렇게 나오면 잘된 거다.

POSTMAN은 아래 링크를 통해 다운받으면 된다.

https://www.postman.com/downloads/

 

Postman | The Collaboration Platform for API Development

Simplify workflows and create better APIs – faster – with Postman, a collaboration platform for API development.

www.postman.com

 

JSON에서 객체는 {} ,  LIST는 []....... 그렇다!

insert, update, delete는 select에 비해 더 쉽고 간단한 거 같다.

 

또 알게되는 사실이 있으면 꿀팁들고 글 써야지

Comments