programing

컨트롤러에서 json 및 xml을 반환하는 스프링 부트

telebox 2023. 3. 23. 22:37
반응형

컨트롤러에서 json 및 xml을 반환하는 스프링 부트

대부분의 UI에서 Tymeleaf를 사용하는 Spring-boot 1.1.7 애플리케이션을 사용하고 있기 때문에 컨트롤러의 응답은 그다지 문제가 되지 않습니다.다만, 유저가 URL 를 사용해 요구를 송신했을 경우는, XML 응답을 제공할 필요가 있습니다.

일반적인 요청은 다음과 같습니다.

http://localhost:9001/remote/search?sdnName=Victoria&address=123 Maple Ave

그래들 구성의 대부분을 다음에 나타냅니다.

project.ext {
    springBootVersion = '1.1.7.RELEASE'
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
    compile("org.springframework.boot:spring-boot-starter-thymeleaf")
    compile("org.springframework.boot:spring-boot-starter-security")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion")
    compile("org.springframework.security:spring-security-web:4.0.0.M1")
    compile("org.springframework.security:spring-security-config:4.0.0.M1")
    compile('org.thymeleaf.extras:thymeleaf-extras-springsecurity3:2.1.1.RELEASE')
    compile("org.springframework.boot:spring-boot-starter-actuator")
    compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.5.0')
}

컨트롤러는 다음과 같습니다.

@Controller
public class RemoteSearchController {

    @Autowired
    private SdnSearchService sdnSearchService;

    @RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = MediaType.APPLICATION_XML_VALUE)
    public List<Sdn> search(@ModelAttribute SdnSearch sdnSearch) {
        List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );
        return foundSdns;
}

다음은 반환해야 할 객체입니다.

@Entity
public class Sdn {

    @Id
    private long entNum;
    private String sdnName;
...
//getters & setters here
}

REST 클라이언트(Coco REST 등)를 통해 의뢰를 받아 대응할 수 있습니다.그러나 SDN 목록을 반환하면 Classpath에 Jackson & jackson-dataformat-xml이 있는데 다음과 같은 예외가 발생합니다.

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
    at org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:229)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:301)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:248)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:57)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:299)

REST 클라이언트에는 "text/xml"의 Accept Header가 포함되어 있습니다(솔직히 말하면 이 설정을 하지 않아도 됩니다).이 컨트롤러에 대한 콜은 헤더에 관계없이 항상 XML을 취득하는 것이 이상적입니다).

이 문제를 해결할 방법이 있을까요?미디어 컨버터도 포함된 줄 알았는데 컨트롤러가 시키는 대로 돌려줬나?

해결책: 제가 올린 답변에 대해서는 아래를 참조하십시오.

저도 같은 문제가 있어서 Spring 문서 웹사이트에서 해결책을 찾았습니다.여기서

저는 다음과 .pom.xml다음을 수행합니다.

<dependency>
     <groupId>com.fasterxml.jackson.dataformat</groupId>
     <artifactId>jackson-dataformat-xml</artifactId>
 </dependency>

그런 다음 서비스에서 반환해야 하는 클래스에 다음 코드 블록을 추가했습니다.

 import javax.xml.bind.annotation.XmlRootElement;

 @XmlRootElement
 public class Greeting {...}

그리고 그것은 성공하였다.

해결책: 아래 두 답변을 조합하여 사용했습니다(감사합니다).혹시 도움이 필요하신 분이 계실까 봐 글을 올립니다.

변경된 컨트롤러:

@Controller
public class RemoteSearchController {

    @Autowired
    private SdnSearchService sdnSearchService;

    @RequestMapping(value = "/remote/search", method = RequestMethod.GET, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )
    @ResponseBody
    public SdnSearchResults search(@ModelAttribute SdnSearch sdnSearch) {
        List<Sdn> foundSdns = sdnSearchService.find( sdnSearch );
        SdnSearchResults results = new SdnSearchResults();
        results.setSdns( foundSdns );
        return results;
    }
}

그리고 내 클라이언트에서 요청 헤더를 설정합니다.

Content-type: application/text Accept: text/xml 최종적으로는 클라이언트헤더가 올바르게 설정되어 있지 않기 때문에 이러한 변경을 할 필요가 없었다고 생각합니다.그러나 결과 목록을 포함하는 SearchResults 클래스의 아이디어는 마음에 들었습니다.

@XmlRootElement
public class SdnSearchResults {
    private List<Sdn> sdns;
...
}

새 클래스를 만드는 것이 더 나을 수 있습니다.

public class SdnSearchResult {
  private List<Sdn> sdns;
  ...
}

그런 다음 기존 클래스를 다음과 같이 약간 변경해야 합니다.

public interface SdnSearchService {
  SdnSearchResult find(SdnSearch sdnSearch);
}

@Controller
public class UISearchController {
  @Autowired
  private SdnSearchService sdnSearchService;

  @RequestMapping("/search")
  public ModelAndView search(@ModelAttribute SdnSearch sdnSearch) {
    return new ModelAndView("pages/search/results", "sdns", sdnSearchService.find(sdnSearch).getSdns());
  }
}

이 작업이 완료되면 다른 컨트롤러는 다음과 같이 코딩해야 합니다.

@Controller
public class RemoteSearchController {
  @Autowired
  private SdnSearchService sdnSearchService;

  @RequestMapping("/remote/search")
  @ResponseBody
  public SdnSearchResult search(@RequestBody SdnSearch sdnSearch) {
    return sdnSearchService.find(sdnSearch);
  }
}

코드 변경에 대한 간단한 설명:

  1. @RequestBody를 HTTP로 .SdnSearch은 통상 으로서 요구 하기 때문에, 「HTTP」는 「HTTP를 참조해 주세요.@RequestBody는 Java 오브젝트로의 역직렬화가 자동으로 이루어지도록 합니다.
  2. @ResponseBody는 외부 클라이언트의 기능과 클래스 경로에서 사용 가능한 라이브러리에 따라 반환값을 자동으로 시리얼화합니다.Jackson이 클래스 패스에서 사용 가능하며 클라이언트가 JSON을 받아들일 수 있음을 나타내는 경우 반환값은 자동으로 JSON으로 전송됩니다.JRE가 1.7 이상(JAXB가 JRE에 포함되어 있는 것을 의미)이며, 클라이언트가 XML을 받아들일 수 있는 것을 나타내고 있는 경우, 반환치는 자동적으로 XML로서 송신됩니다.
  3. List<Sdn>로 변경할 필요가 있다SdnSearchResult 형식, 및 ATOM 을 단일 할 수 하기 XML(「XML」)의 경우 출력에 루트태그가 필요합니다.List<Sdn>변환할 수 없습니다.

의 REST 하여 "Crome" Postman에 합니다./remote/search다음 정보를 포함합니다.

  1. 헤더 " " "Acceptsapplication/json.
  2. 헤더 " " "Content-Typeapplication/json.
  3. 문자열 JSON으로 { "sdnName" : "Victoria", "address" : "123 Maple Ave" }.

그러면 JSON 응답이 나타납니다.

을 '생성'으로 application/xmlsyslog(복수(복수(복수)produces = MediaType.APPLICATION_XML_VALUE 헤더 「 Accept 」( ).Accept: text/xml하지 않기 에 Spring은 Spring이 Spring이라고 search이치노

정확한 요건에 따라 서버에서 이 문제를 해결할 수 있는 방법이 몇 가지 있습니다.

  • 떼면 될 것 같아요.produces
  • 할 수 있습니다.예를 들어, 미디어 타입은, 「 」produces = { "application/xml", "text/xml" }

사용하시는 Spring Boot 버전(1.1.7)은 잘 모르겠습니다.RELEASE)는 버전 1.5.2입니다.RELEASE 및 이 xml 변환/시리얼라이제이션은 몇 가지 답변에서 설명한 잭슨 의존관계를 사용하지 않고 자동으로 수행됩니다.

그런 일이 일어나는 이유는org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.51 됩니다.RELEASE는 JRE의 변환 없음 RELEASE & that 컨버터 JRE는 JAXB의 JRE를 사용합니다.

번째, ㅇㅇㅇ,Accept에 의해 는 출력이 같은 단일 포인트)이 합니다.

@RequestMapping(method = RequestMethod.GET, value = "/remote/search", produces = {
        MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE })

xml 및 JSON 응답 생성에 사용할 수 있습니다(Accept 헤더가 다음과 같이 설정되어 있는 경우).text/xml또는application/xml&application/json각각 다음과 같다.

주 1:javax.xml.bind.annotation.XmlRootElementJava 클래스에 대해 xml 응답이 예상되는 경우 루트 클래스에서 지정해야 합니다.이것은 필수입니다.

주 2: Jackson for json은 이미 Spring Boot에 포함되어 있으므로 json 출력에는 명시적으로 포함되지 않습니다.

3 : Accept header - 출력 매치오프는 프레임워크에 따라 자동으로 이루어지며 개발자는 이에 대해 특별히 코드화할 필요가 없습니다.

그래서 제 생각에는, 만약 당신이 단지XmlRootElement기본 클래스로 업그레이드하여 Spring Boot 버전을 업그레이드하면 서버 측 설정이 모두 완료됩니다.올바른 Accept 헤더를 설정할 책임은 클라이언트에 있습니다.

마이클이 답변한 내용 외에 pom.xml에 다음과 같은 의존관계를 추가하였습니다.

<dependency>
    <groupId>org.codehaus.woodstox</groupId>
    <artifactId>woodstox-core-asl</artifactId>
    <version>4.4.1</version>
</dependency>

어떤 이유에서인지 jackson-dataformat-xml만으로는 도움이 되지 않습니다.또한 ResponseEntity가 get call로 반환되는 것을 확인하고 requestMapping 주석에서 products=MediaType을 삭제했습니다.

이러한 변경으로 저는 올바른 데이터를 얻을 수 있었지만, get call 중에 REST URL에 mime 타입의 확장자를 부여해야 했습니다.즉, 브라우저에서 http://localhost:8080/hello.xml 또는 http://localhost:8080/hello.json과 같이 명시적으로 지정합니다.

제 경우 포맷된 XML 문자열을 반환하려고 했는데 모두 한 줄로 결합되어 있었습니다.

추가 중produces = { "application/xml", "text/xml" }문자열이 형식화된 XML( 들여쓰기 포함)로 반환되기에 충분했습니다.

예:

@RequestMapping(method= RequestMethod.GET, value="/generate/{blabla}", produces = { "application/xml", "text/xml" })
    public String getBlaBla(@PathVariable("param") String param) throws IOException {
}

행운을 빌어요.

언급URL : https://stackoverflow.com/questions/27790998/spring-boot-return-json-and-xml-from-controllers

반응형