본문 바로가기

소프트웨어/웹

[Spring/JPA] RestController에서 텍스트 형태의 JSON string 데이터 처리

 

TL;DR

@JsonRawValue

 

 

 

 

 

 

 

 

다음과 같은 JSON 데이터를 tbl_json_raw_value 테이블의 json 열에 저장하고 있습니다.

{
  "name": "iroiro",
  "version_code": 1,
  "majority": [
  	"Java", "Kotlin", "Spring", "Javascript", "Swift", "Node.js", "Android", "Cpp", "iOS"
  ]
}

 

 

 

 

 

 

 

 

여기서 json열의 stringified된 JSON 데이터를 아래와 같이 응답하고 싶은 경우가 있을 겁니다.

{
    "status": 200,
    "json_data": {
        "name": "iroiro",
        "version_code": 1,
        "majority": [
            "Java",
            "Kotlin",
            "Spring",
            "Javascript",
            "Swift",
            "Node.js",
            "Android",
            "Cpp",
            "iOS"
        ]
    }
}

 

 

 

 

 

 

 

 

 

샘플 코드 작성

 

컨트롤러

 

우선 단순히 tbl_json_raw_value테이블의 json 열의 값을 읽어와 json_data 프로퍼티 하위에 담아 응답하는 Controller를 생성해서 잘 되는지 테스트 해 봅시다.

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/iroiro")
public class IroiroRestController {

    @Autowired
    IroiroJsonRepository jsonRepository;

    @GetMapping("json")
    public ResponseEntity<IroiroJsonResponse> getJson(@RequestParam Long idx) {


        // DB에서 데이터 획득
        IroiroJsonDao dao = jsonRepository.findById(idx).orElse(null);
        
        // 바디 생성
        IroiroJsonResponse body = new IroiroJsonResponse();

        // 바디 데이터 입력
        body.setCode(1234);
        if(dao != null) {
            body.setData(dao.getJson());
        }
    
        // 응답에 바디 실어서 응답
        return new ResponseEntity<>(body, HttpStatus.OK);
    }

}

 

 

 

 

 

 

 

DAO

 

DB 접근 DAO 클래스도 하나 만들어줍니다.

 

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Table(name = "json")
@Entity
public class IroiroJsonDao {
    
    @Id
    @Column(name = "idx", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long idx;

    @Column(name = "json", nullable = false)
    private String json;
}

 

 

 

 

 

 

Repository

 

JpaRepository 인터페이스에 위에서 만든 DAO를 매핑합니다

 

public interface IroiroJsonRepository extends JpaRepository<IroiroJsonDao, Long>  {
}

 

 

 

 

 

VO

 

아래는 HttpEntity의 데이터에 해당하는 응답 객체 클래스입니다.

 

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class IroiroJsonResponse {

    private Integer status;

    private String jsonData;

}

 

 

 

테스트 결과

 

 스프링 서버를 구동 후 컨트롤러에 요청을 하게 되면 아래와 같은 현상이 나타나게 됩니다. 

 

{
    "status": 200,
    "json_data": "{\"name\":\"iroiro\",\"version_code\":1,\"majority\":[\"Java\",\"Kotlin\",\"Spring\",\"Javascript\",\"Swift\",\"Node.js\",\"Android\",\"Cpp\",\"iOS\"]}"
}

 

DB의 json 열의 값을 단순한 String으로 판단했고 추가로 몇몇 특수 문자는 이스케이프 처리 되었습니다. 원래 의도는 IroiroJsonResponsejsonData 항목에 Object 형태로 응답 하고 싶었던 것입니다.

 

 

 

 

 

 

@JsonRawValue

 

 이 때 IroiroJsonResponsejsonData 필드에 @JsonRawValue (com.fasterxml.jackson.annotation.JsonRawValue) 어노테이션을 추가해주면 String 데이터를 JSON으로 직렬화 하여 별도의 VO를 생성하지 않고 응답을 할 수 있습니다.

 

// JsonRawValue import
import com.fasterxml.jackson.annotation.JsonRawValue;

public class IroiroJsonResponse {

    private Integer status;

    // @JsonRawValue 어노테이션을 추가해준다
    @JsonRawValue
    private String jsonData;

}

 

 

 

다른 방법으로는 직접 매퍼를 설계하거나 컨버터를 구현하는 방법 등이 있으나 제가 찾은 방법중에서는 이것이 가장 간단한 방법이었네요 😆

 

 

 

 

참고