स्प्रिंग एमवीसी - रेस्ट कंट्रोलर में JSON के रूप में सरल स्ट्रिंग कैसे लौटाएं


137

मेरा प्रश्न अनिवार्य रूप से इस प्रश्न का अनुवर्ती है ।

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

उपरोक्त में, स्प्रिंग प्रतिक्रिया शरीर में "हैलो वर्ल्ड" जोड़ देगा। मैं एक JSON प्रतिक्रिया के रूप में एक स्ट्रिंग कैसे लौटा सकता हूं? मैं समझता हूं कि मैं उद्धरण जोड़ सकता हूं, लेकिन यह हैक की तरह लगता है।

कृपया इस अवधारणा को समझाने में मदद करने के लिए कोई उदाहरण प्रदान करें।

नोट: मैं इसे सीधे HTTP रिस्पॉन्स बॉडी के लिए नहीं लिखना चाहता, मैं स्ट्रिंग को JSON फॉर्मेट में वापस करना चाहता हूं (मैं अपने कंट्रोलर का उपयोग रेस्टग्वॉट के साथ कर रहा हूं जिसके लिए मान्य JSON फॉर्मेट में प्रतिक्रिया की आवश्यकता है)।


आप मानचित्र या कोई भी वस्तु / इकाई वापस कर सकते हैं जिसमें आपका तार शामिल है
डेनिस डेनिसियुक

तो आप का मतलब है कि आप स्ट्रिंग मान को JSON स्ट्रिंग से क्रमबद्ध करना चाहते हैं?
सोतिरियोस डेलिमोलिसिन

जवाबों:


150

या तो रिटर्न text/plain( स्प्रिंग एमवीसी 3 नियंत्रक से केवल स्ट्रिंग संदेश के रूप में ) या अपनी स्ट्रिंग लपेटें कुछ वस्तु है

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")बिना रैपर क्लास बनाए भी उसी परिणाम को प्राप्त कर सकते हैं ।
बोहुस्लाव बरगार्ड

@ बोहुस्लाव यह एक शानदार टिप है।
शॉन

6
यह सच नहीं है कि इसके लिए एक कुंजी और एक मूल्य की आवश्यकता होती है। एकल स्ट्रिंग या स्ट्रिंग्स की एक सरणी दोनों वैध JSON हैं। यदि आप असहमत हैं, तो आप यह समझा सकते हैं कि jsonlint वेबसाइट उन दोनों को मान्य JSON के रूप में क्यों स्वीकार करती है।
काइलएम

2
रैपर क्लास को JSON में कैसे बदला जाता है?
रॉकी इंड

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 प्रतिक्रिया के लिए आपको शॉन द्वारा वर्णित रैपर क्लास का उपयोग करना चाहिए।


7
यह उत्तर स्वीकार किया जाना चाहिए, क्योंकि यह ओपी के प्रश्न का सटीक उत्तर था।
एसआरआई

धन्यवाद, @ResponseBody मैं क्या जरूरत थी
7

जिज्ञासु जो सार्वजनिक कीवर्ड से पहले या बाद में @ResponseBody के लिए "बेहतर" स्थिति है? मैंने हमेशा इसे बाद में रखा है, क्योंकि यह रिटर्न वैल्यू के साथ अधिक पहचाना जाता है।
डेविड ब्रैडले

26

एक परियोजना में हमने इसे JSONObject ( मावेन निर्भरता जानकारी ) का उपयोग करके संबोधित किया । हमने इसे चुना क्योंकि हमने एक रैपर ऑब्जेक्ट के बजाय एक साधारण स्ट्रिंग को वापस करना पसंद किया। यदि आप एक नई निर्भरता नहीं जोड़ना चाहते हैं, तो इसके बजाय एक आंतरिक सहायक वर्ग आसानी से उपयोग किया जा सकता है।

उदाहरण उपयोग:

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

1
हो सकता है कि आपको अपने उत्तर में उल्लेख करना चाहिए, कि "\"Hello World\""अतिरिक्त निर्भरता के साथ ही w / o काम करेगा - जो कि JSONObject.quote()सही है?
jerico

मुझे समाधान पसंद नहीं है, लेकिन यह मेरे लिए काम करता है। :-)
माइकल हेगनर

22

आप आसानी से निम्नलिखित के रूप में संपत्ति के JSONसाथ वापस आ सकते हैंStringresponse

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

2
जब भी आप dont @RestController ’का उपयोग करते हैं, तो आपको esp @ResponseBody’ का उपयोग करने की आवश्यकता नहीं होती है
जितेन्द्र वार्ष्णेय

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();
}

अंतिम नोट:

  • extendMessageConvertersस्प्रिंग 4.1.3 के बाद से उपलब्ध है, अगर आप पिछले संस्करण पर चल रहे हैं, तो आप उसी तकनीक का उपयोग करके configureMessageConvertersइसे लागू कर सकते हैं , यह बस थोड़ा अधिक काम करता है।
  • यह कई अन्य संभावित दृष्टिकोणों में से एक था, यदि आपका आवेदन केवल JSON और कोई अन्य सामग्री प्रकार नहीं लौटाता है, तो आप डिफ़ॉल्ट कन्वर्टर्स को छोड़ना और एकल जैकसन कनवर्टर जोड़ना बेहतर है। एक और दृष्टिकोण डिफ़ॉल्ट कन्वर्टर्स को जोड़ना है लेकिन अलग-अलग क्रम में ताकि जैकसन कनवर्टर स्ट्रिंग एक से पहले हो। यह नियंत्रक कार्रवाई विधियों को यह निर्धारित करने की अनुमति देना चाहिए कि वे कैसे चाहते हैं कि स्ट्रिंग को मीडिया प्रकार की प्रतिक्रिया के आधार पर परिवर्तित किया जाए।

1
अपने 2 के अंतिम नोट के बारे में एक उदाहरण कोड रखना अच्छा होगा।
टोनी Baguette

1
converters.removeIf(c -> c instanceof StringHttpMessageConverter)
क्राय्लिस -कुट्योपोटेमिमिस्टिक-

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
आप हाशपॅप को वापस करने की विधि क्यों घोषित कर रहे हैं? एलएचएम नक्शा लागू करता है।
JL_SO

6

सरल बनाओ:

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

एक ResponseEntity का उपयोग करना मेरे लिए कला की स्थिति है। +1
अलेक्जेंडर

5

एनोटेशन produces = "application/json"में जोड़ें @RequestMappingजैसे:

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

संकेत: वापसी मूल्य के रूप में, मैं ResponseEntity<List<T>>प्रकार का उपयोग करने की सलाह देता हूं । क्योंकि JSON बॉडी में उत्पादित डेटा को एक साधारण स्ट्रिंग के बजाय अपने विनिर्देशों के अनुसार एक सरणी या ऑब्जेक्ट होने की आवश्यकता होती है । यह कभी-कभी समस्याओं का कारण बन सकता है (जैसे कि Angular2 में वेधशालाएं)।

अंतर:

Stringjson के रूप में लौटा :"example"

List<String>json के रूप में लौटा :["example"]


3

@ResponseBodyएनोटेशन जोड़ें , जो आउटपुट स्ट्रीम में रिटर्न डेटा लिखेंगे।


1
यह मेरे लिए काम नहीं किया। मेरे पास@PostMapping(value = "/some-url", produces = APPLICATION_JSON_UTF8_VALUE)
एलोपियो

0

इस मुद्दे ने मुझे पागल कर दिया है: वसंत एक ऐसा शक्तिशाली उपकरण है और फिर भी, आउटपुट स्ट्रिंग लिखने के रूप में इस तरह की एक सरल चीज के रूप में JSON बदसूरत हैक्स के बिना असंभव लगता है।

मेरा समाधान (कोटलिन में) जो मुझे कम से कम घुसपैठ और सबसे पारदर्शी लगता है एक नियंत्रक सलाह का उपयोग करना है और यह जांचना है कि क्या अनुरोध समापन बिंदुओं के एक विशेष सेट में चला गया है (REST API आमतौर पर जब से हम सबसे अधिक बार चाहते हैं कि JSON के रूप में यहां से सभी उत्तर वापस आ जाएं। और दिए गए डेटा के आधार पर सामने वाले में विशेषज्ञता न बनाएं कि लौटा डेटा एक सादा स्ट्रिंग है ("JSON डेज़रिएलाइज़ेशन मत करो!") या कुछ और ("Do 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")
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.