본문 바로가기

프로그래밍/Spring Boot

[Spring Boot] REST API response XML로 반환하기


보통 REST API에 대해 받아오는 형식은 JSON 타입인 것이 익숙하다.

공공데이터 포탈 등의 사이트에서 제공하는 Open API들 중에는 리턴을 XML 형식으로 보내는 사양도 존재한다.

Spring Boot로 구축한 REST API로 XML은 어떻게 반환할 수 있을지에 대해 알아본다.

 

<글의 순서>

1. Jackson Dataformat XML dependency 추가 
2. 출력할 데이터 형식 정의 
3. API Controller에 xml을 반환할 메소드 추가(produces 속성 지정)

 

1. Jackson Dataformat XML dependency 추가

xml 형식 데이터 ↔ Java 오브젝트 상호 변환이 가능하게 하는

Jackson Dataformat XML을 pom.xml에 추가해야 한다.

Maven Repository에서 가져온 아래 소스를 복사하여 dependencdependencies에 추가한다.

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.11.2</version>
</dependency>

 

 

2. 출력할 데이터 형식 정의

데이터 클래스를 작성하여 xml 출력 형식을 정해야 한다. 
MemberXml이라 하는 데이터 통신용 클래스를 작성한다고 하자. 사용할 필드는 다음과 같다.

<MemberXml.java>

@Data 
@NoArgsConstructor
@AllArgsConstructor
public class MemberXml {
	private Integer id;
	private String name;
	private Integer age;
	private String dept;
}

※ 여기서는 데이터용 클래스에 Lombok(롬복) 라이브러리를 사용하고 있기 때문에,  
   getter setter 생성자 등등 기본적으로 필요한 메소드는 어노테이션으로 자동으로 작성하고 있다. 
   롬복에 관하여 더 알고 싶다면 여기를 참고! → https://binit.tistory.com/21 

 

[Java] Lombok(롬복) 설치와 사용법 - getter/setter 빠르게 작성하기

Java 개발자라면 클래스 생성자, Getter와 Setter, 그리고 toString 메서드 등에 있어서만큼은 아마 조건반사적으로 작성을 하고 있을 것이다. 이를 조금이나마 편하게 작성할 수 있도록 해 주는 라이브

binit.tistory.com

 

이제 xml 형식으로 Serialize 하기위해(우리말로 적당한 표현이 떠오르지 않는다.. 😅)

pom.xml에 추가한 jackson 라이브러리를 이용해야한다.

<MemberXml.java>

@Data
@NoArgsConstructor
@AllArgsConstructor
@JacksonXmlRootElement(localName = "xmember")
public class MemberXml {
	@JacksonXmlProperty(isAttribute = true) private Integer id;
	@JacksonXmlProperty private String name;
	@JacksonXmlProperty private Integer age;
	@JacksonXmlProperty private String dept;
}

💡 어노테이션 설명

@JacksonXmlRootElement(localName = "xmember") 
- localName으로 설정한 값을 루트 요소로 지정한다. 
- localName을 지정하지 않으면 클래스명이 지정된다.
@JacksonXmlProperty 
- 루트 요소 안에 들어갈 하위 요소들을 지정한다.  
- 이 때, 위의 id처럼 isAttribute = true를 지정하면 루트태그의 속성으로 들어가게 된다. 
- localName 속성을 지정하면 지정한 값으로 요소가 표기된다.

설명만으로는 이해가 어려울 수 있으니, 
이 클래스를 xml로 직접 써보면 이런 형식이 될 것이다.

<xmember id="00">
	<name>AAA</name>
	<age>22</age>
	<dept>ZZZ</dept>
</xmember>

이제 대강 감이 올 것 같다. 
이제 API 요청이 오면 이 xmember 여럿을 리스트로 뽑기 위해 MemberXmlList라는 데이터 클래스를 하나 더 추가한다.

<MemberXmlList.java>

@Data
@JacksonXmlRootElement(localName = "xmemberlist")
public class MemberXmlList {
	
	@JacksonXmlProperty(localName = "xmember")
	@JacksonXmlElementWrapper(useWrapping = false)
	List<MemberXml> members = new ArrayList<>();
}

💡 어노테이션 설명

@JacksonXmlRootElement(localName = "xmemberlist") 
- xmember값들의 루트 요소로서 xmemberlist라 이름을 붙인다. 
  이 클래스에서 루트 요소를 선언했기 때문에,  
  앞으로 이 리스트 하위로 출력 될 MemberXml에 지정한 @JacksonXmlRootElement(localName = "xmember")는 무시된다.
@JacksonXmlProperty(localName = "xmember")
- 리스트로 출력될 각각의 아이템 요소들의 요소명을 xmember로 지정한다.
@JacksonXmlElementWrapper(useWrapping = false) 
- 이 어노테이션에 지정된 값을 요소로 묶을 것인지 결정하는 역할을 한다. 기본값은 true이다. 
- 우리는 <xmemberlist>라는 루트 요소 바로 아래에 각 xmember 리스트를 나열할 것이기 때문에 
  이를 또 하나의 요소로 감쌀 필요는 없다. 따라서 여기서는 useWrapping=false로 지정해야 한다.

 

🎯 @JacksonXmlElementWrapper에 대해 조금 더 부연설명 ("더 보기" 클릭)

더보기

@JacksonXmlElementWrapper(useWrapping = false)로 출력되는 xml은 다음과 같다.

<xmemberlist>
	<xmember id="1">
		<name>AAA</name>
		<age>22</age>
		<dept>it</dept>
	</xmember>
	<xmember id="2">
		<name>BBB</name>
		<age>24</age>
		<dept>ia</dept>
		...
		...
</xmemberlist>

 

이번에는 useWrapping = true를 지정하고,

차이점을 보기 위해  localName = "wrapper"도 추가하여 확인해 보도록 한다. 

@JacksonXmlElementWrapper(useWrapping = true, localName = "wrapper")

<xmemberlist>
	<wrapper>
		<xmember id="1">
			<name>AAA</name>
			<age>22</age>
			<dept>it</dept>
		</xmember>
		<xmember id="2">
			<name>BBB</name>
			<age>24</age>
			<dept>ia</dept>
			...
			...
	</wrapper>
</xmemberlist>

<wrapper>라는 요소가 xmember들을 한 번 더 감싸고 있는 형태가 된다.

 

 

3. API Controller에 xml을 반환할 메소드 추가(produces 속성 지정)

xml로 response를 보낼 준비는 끝났다. 이제 컨트롤러에 메소드를 추가한다.

@GetMapping(path = "/xml", produces = MediaType.APPLICATION_XML_VALUE)
public MemberXmlList getAllMembersXML() {
	List<MemberXml> list = new ArrayList<MemberXml>();
	list.add(new MemberXml(1, "AAA", 22, "it"));
	list.add(new MemberXml(2, "BBB", 24, "ia"));
	list.add(new MemberXml(3, "CCC", 25, "ix"));
	list.add(new MemberXml(4, "DDD", 26, "iv"));
	
	MemberXmlList res = new MemberXmlList();
	res.setMembers(list);
	
	return res;
}

@GetMapping으로 GET 메소드를 처리하는 메소드이다.

path는 개발중인 환경에 맞춰 정하고,

produces = MediaType.APPLICATION_XML_VALUE로 작성하여 출력 형식을 xml로 지정한다.

(이런 식으로 MediaType Enum 지정으로 xml 외에 json, text 등으로의 출력이 가능하다.)

 

(참고) 작성한 API의 출력 결과 확인해보기 ("더 보기" 클릭)

더보기
<xmemberlist>
    <xmember id="1">
        <name>AAA</name>
        <age>22</age>
        <dept>it</dept>
    </xmember>
    <xmember id="2">
        <name>BBB</name>
        <age>24</age>
        <dept>ia</dept>
    </xmember>
    <xmember id="3">
        <name>CCC</name>
        <age>25</age>
        <dept>ix</dept>
    </xmember>
    <xmember id="4">
        <name>DDD</name>
        <age>26</age>
        <dept>iv</dept>
    </xmember>
</xmemberlist>

 

이상으로 스프링부트 REST API 개발 환경을 이용한 xml response를 작성해 보았다.


<참고한 페이지>

zetcode.com/springboot/restxml/

 

Spring Boot REST XML tutorial - serving XML data in a RESTFul application

Spring Boot REST XML tutorial last modified July 6, 2020 Spring Boot REST XML tutorial shows how to serve XML data in a Spring Boot RESTFul application. We create test methods for the RESTful controller. Spring is a popular Java application framework for c

zetcode.com