Spring MVC-Rest Controller에서 간단한 문자열을 JSON으로 반환하는 방법


137

내 질문은 본질적 으로이 질문에 대한 후속 조치 입니다.

@RestController
public class TestController
{
    @RequestMapping("/getString")
    public String getString()
    {
        return "Hello World";
    }
}

위에서 스프링은 응답 본문에 "Hello World"를 추가 할 것이다. JSON 응답으로 문자열을 어떻게 반환합니까? 나는 따옴표를 추가 할 수 있지만 더 해킹처럼 느껴진다는 것을 이해합니다.

이 개념을 설명하는 데 도움이되는 예를 제공하십시오.

참고 : HTTP 응답 본문에 직접 작성하고 싶지는 않습니다. 문자열을 JSON 형식으로 반환하고 싶습니다 ( 응답이 유효한 JSON 형식 이어야 하는 RestyGWT 와 함께 Controller를 사용 하고 있습니다).


당신은지도 나 문자열을 포함하는 모든 개체 / 엔티티 반환 할 수 있습니다
데니스 Denysiuk

따라서 String 값을 JSON 문자열로 직렬화하려는 것을 의미합니까?
Sotirios Delimanolis 2016 년

답변:


150

반환 text/plain( Spring MVC 3 Controller에서 문자열 메시지 만 반환 에서와 같이 ) 또는 문자열을 객체로 감싸십시오.

public class StringResponse {

    private String response;

    public StringResponse(String s) { 
       this.response = s;
    }

    // get/set omitted...
}


응답 유형을 MediaType.APPLICATION_JSON_VALUE(= "application/json")으로 설정하십시오.

@RequestMapping(value = "/getString", method = RequestMethod.GET,
                produces = MediaType.APPLICATION_JSON_VALUE)

그리고 당신은 JSON처럼 보입니다

{  "response" : "your string value" }

124
Collections.singletonMap("response", "your string value")랩퍼 클래스를 작성하지 않고도 동일한 결과를 얻기 위해 리턴 할 수도 있습니다 .
Bohuslav Burghardt 2016 년

@Bohuslav 좋은 팁입니다.
Shaun

6
키와 값이 필요하다는 것은 사실이 아닙니다. 단일 문자열 또는 문자열 배열은 모두 유효한 JSON입니다. 당신이 동의하지 않는다면 jsonlint 웹 사이트가 두 가지를 모두 유효한 JSON으로 허용하는 이유를 설명 할 수 있습니다.
KyleM

2
래퍼 클래스는 어떻게 JSON으로 변환됩니까?
Rocky Inde

3
돌아 오는 것으로 충분하다고 생각합니다Collections.singleton("your string value")
gauee

54

JSON은 본질적으로 PHP 또는 JAVA 컨텍스트의 문자열입니다. 즉, 유효한 JSON 인 문자열을 응답으로 반환 할 수 있습니다. 다음과 같이 작동합니다.

  @RequestMapping(value="/user/addUser", method=RequestMethod.POST)
  @ResponseBody
  public String addUser(@ModelAttribute("user") User user) {

    if (user != null) {
      logger.info("Inside addIssuer, adding: " + user.toString());
    } else {
      logger.info("Inside addIssuer...");
    }
    users.put(user.getUsername(), user);
    return "{\"success\":1}";
  }

간단한 문자열 응답에는 괜찮습니다. 그러나 복잡한 JSON 응답의 경우 Shaun에서 설명한대로 래퍼 클래스를 사용해야합니다.


7
이것은 OP의 질문에 대한 정확한 답변이므로 받아 들여야합니다.
SRy

감사합니다, @ResponseBody는 내가 필요했던 것
riskop

공개 키워드 전후에 @ResponseBody의 "더 나은"위치가 궁금하십니까? 반환 값으로 더 잘 식별되므로 항상 뒤에 두었습니다.
David Bradley

26

한 프로젝트에서 JSONObject (maven dependency info )를 사용 하여이 문제를 해결했습니다 . 우리는 래퍼 객체가 아닌 간단한 문자열을 반환하는 것을 선호했기 때문에 이것을 선택했습니다. 새 종속성을 추가하지 않으려는 경우 내부 도우미 클래스를 대신 쉽게 사용할 수 있습니다.

사용법 예 :

@RestController
public class TestController
{
    @RequestMapping("/getString")
    public String getString()
    {
        return JSONObject.quote("Hello World");
    }
}

1
아마도 당신은 당신의 대답에 언급해야 할 "\"Hello World\""것인데 , 그것은 여분의 의존성없이 잘 작동 할 것입니다 JSONObject.quote().
jerico

나는 해결책을 좋아하지 않지만 그것은 나를 위해 일했다. :-)
Michael Hegner 2018 년

22

당신은 쉽게 반환 할 수 JSONString속성에 response다음과 같은

@RestController
public class TestController {
    @RequestMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_VALUE)
    public Map getString() {
        return Collections.singletonMap("response", "Hello World");
    }
}

2
당신이 '@RestController'를 사용할 때마다, 당신은 '@ResponseBody'사용에 필요 없어요
jitendra의 varshney

12

기본 StringHttpMessageConverter인스턴스를 등록 취소하면됩니다 .

@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
  /**
   * Unregister the default {@link StringHttpMessageConverter} as we want Strings
   * to be handled by the JSON converter.
   *
   * @param converters List of already configured converters
   * @see WebMvcConfigurationSupport#addDefaultHttpMessageConverters(List)
   */
  @Override
  protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.stream()
      .filter(c -> c instanceof StringHttpMessageConverter)
      .findFirst().ifPresent(converters::remove);
  }
}

컨트롤러 액션 핸들러 메소드와 컨트롤러 예외 핸들러로 테스트했습니다.

@RequestMapping("/foo")
public String produceFoo() {
  return "foo";
}

@ExceptionHandler(FooApiException.class)
public String fooException(HttpServletRequest request, Throwable e) {
  return e.getMessage();
}

최종 메모 :

  • extendMessageConvertersSpring 4.1.3부터 ​​사용할 수 있습니다. 이전 버전에서 실행중인 경우을 사용하여 동일한 기술을 구현할 수 있습니다 configureMessageConverters. 조금 더 많은 작업이 필요합니다.
  • 응용 프로그램이 JSON 만 반환하고 다른 콘텐츠 유형은 반환하지 않는 경우 이것은 가능한 많은 다른 방법 중 하나입니다. 기본 변환기를 건너 뛰고 단일 잭슨 변환기를 추가하는 것이 좋습니다. 다른 방법은 기본 변환기를 추가하지만 다른 순서로 잭슨 변환기가 문자열 변환기보다 먼저 오도록하는 것입니다. 이를 통해 컨트롤러 조치 메소드가 응답의 매체 유형에 따라 문자열을 변환 할 방법을 지정할 수 있습니다.

1
두 번째 최종 노트와 관련된 예제 코드를 작성하는 것이 좋습니다.
Tony Baguette

1
converters.removeIf(c -> c instanceof StringHttpMessageConverter)
chrylis -cautiouslyoptimistic-

10

나는이 질문이 오래되었다는 것을 알고 있지만 나도 기여하고 싶다 :

다른 응답의 주요 차이점은 해시 맵 리턴입니다.

@GetMapping("...")
@ResponseBody
public Map<String, Object> endPointExample(...) {

    Map<String, Object> rtn = new LinkedHashMap<>();

    rtn.put("pic", image);
    rtn.put("potato", "King Potato");

    return rtn;

}

이것은 다음을 반환합니다 :

{"pic":"a17fefab83517fb...beb8ac5a2ae8f0449","potato":"King Potato"}

2
왜 메소드를 HashMap을 리턴한다고 선언합니까? LHM은 Map을 구현합니다.
JL_SO

6

간단하게 :

    @GetMapping("/health")
    public ResponseEntity<String> healthCheck() {
        LOG.info("REST request health check");
        return new ResponseEntity<>("{\"status\" : \"UP\"}", HttpStatus.OK);
    }

ResponseEntity를 사용하는 것은 나에게 최첨단 인 것 같습니다 . +1
Alexander

5

추가 produces = "application/json"@RequestMapping같은 주석 :

@RequestMapping(value = "api/login", method = RequestMethod.GET, produces = "application/json")

힌트 : 반환 값으로 ResponseEntity<List<T>>type 을 사용하는 것이 좋습니다 . JSON 본문에서 생성 된 데이터 는 단일 단순 문자열이 아니라 사양에 따라 배열 또는 객체 여야 합니다 . 때때로 문제가 발생할 수 있습니다 (예 : Angular2의 Observables).

차:

Stringjson으로 반환 :"example"

List<String>json으로 반환 :["example"]


3

@ResponseBody출력 스트림에 리턴 데이터를 쓰는 주석을 추가하십시오 .


1
이것은 나를 위해 작동하지 않았다. 나는@PostMapping(value = "/some-url", produces = APPLICATION_JSON_UTF8_VALUE)
aliopi

0

이 문제는 저를 화나게했습니다 : Spring은 매우 강력한 도구이지만 JSON과 같은 출력 문자열을 작성하는 것과 같은 간단한 일은 추악한 해킹없이 불가능 해 보입니다.

가장 방해가 적고 가장 투명한 솔루션은 컨트롤러 조언을 사용하고 요청이 특정 엔드 포인트 세트로 갔는지 여부를 확인하는 것입니다 (REST API는 일반적으로 여기에서 모든 답변을 JSON으로 가장 자주 반환하기를 원하기 때문에) 반환 된 데이터가 일반 문자열 ( "JSON deserialization을 수행하지 마십시오!") 또는 다른 항목 ( "JSON deserialization을 수행하십시오!")인지 여부에 따라 프론트 엔드에서 전문화하지 마십시오. 이것의 긍정적 인 측면은 컨트롤러가 해킹없이 동일하게 유지된다는 것입니다.

supports메소드는 StringHttpMessageConverter(예를 들어 일반 문자열을 반환하는 모든 컨트롤러의 출력을 처리하는 변환기와 같이) 처리 된 모든 요청이 처리되도록 하고 beforeBodyWrite메소드에서 출력을 중단하고 JSON으로 변환하려는 경우를 제어합니다. (그리고 헤더를 적절히 수정하십시오).

@ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
    
    override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
        converterType === StringHttpMessageConverter::class.java

    override fun beforeBodyWrite(
        body: Any?,
        returnType: MethodParameter,
        selectedContentType: MediaType,
        selectedConverterType: Class<out HttpMessageConverter<*>>,
        request: ServerHttpRequest,
        response: ServerHttpResponse
    ): Any? {
        return if (request.uri.path.contains("api")) {
            response.getHeaders().contentType = MediaType.APPLICATION_JSON
            ob.writeValueAsString(body)
        } else body
    }
}

앞으로 HttpMessageConverter출력에 사용해야 할 간단한 주석을 얻을 수 있기를 바랍니다 .


-5

이 주석을 메소드에 추가하십시오.

@RequestMapping(value = "/getString", method = RequestMethod.GET, produces = "application/json")
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.