स्प्रिंग बूट में प्रतिक्रिया के रूप में JSON वस्तु लौटना


85

मेरे पास स्प्रिंग बूट में एक नमूना RestController है:

@RestController
@RequestMapping("/api")
class MyRestController
{
    @GetMapping(path = "/hello")
    public JSONObject sayHello()
    {
        return new JSONObject("{'aa':'bb'}");
    }
}

मैं JSON लाइब्रेरी का उपयोग कर रहा हूं org.json

जब मैंने एपीआई को मारा /hello, तो मुझे एक अपवाद मिला:

सर्विसलेट [) सर्वलेट के लिए (dispatcherServlet] पथ के संदर्भ में [] अपवाद फेंक दिया [अनुरोध प्रसंस्करण विफल रहा; नेस्टेड अपवाद java.lang.IllegalArgumentException है: प्रकार के वापसी मूल्य के लिए कोई भी कनवर्टर नहीं मिला: मूल के साथ वर्ग org.json.JSONObject]

java.lang.IllegalArgumentException: कोई भी कनवर्टर प्रकार का वापसी मान नहीं मिला: class org.json.JSONObject

मामला क्या है? क्या कोई समझा सकता है कि वास्तव में क्या हो रहा है?


जैक्सन JSONObject को जेन्स में परिवर्तित नहीं कर सकता है।
पौ

ठीक है, मैं समझता हूँ कि इसे ठीक करने के लिए क्या किया जा सकता है?
इवेकेसी

1
मैं चाहता हूं कि मक्खी पर प्रतिक्रिया का निर्माण किया जाए। मैं प्रत्येक प्रतिक्रिया के लिए विशिष्ट कक्षाएं बनाना नहीं चाहता।
इवेकेसी

2
स्ट्रिंग के रूप में अपनी विधि वापस करना बेहतर होगा। इसके अतिरिक्त, आप इस तरीके से एनोटेशन @ResponseBody को भी जोड़ सकते हैं, यह आपकी प्रतिक्रिया को अनुरोध के रूप में निपटा देगा :-)@GetMapping(path = "/hello") @ResponseBody public String sayHello() {return"{'aa':'bb'}";}
vegaasen

@vegaasen क्या आप रिस्पॉन्सबॉडी के बारे में थोड़ा विस्तार से बता सकते हैं
iwekesi

जवाबों:


103

जैसा कि आप स्प्रिंग बूट वेब का उपयोग कर रहे हैं, जैक्सन निर्भरता निहित है और हमें स्पष्ट रूप से परिभाषित करने की आवश्यकता नहीं है। यदि आप pom.xmlग्रहण का उपयोग कर रहे हैं तो आप निर्भरता पदानुक्रम टैब में अपने लिए जैक्सन निर्भरता की जांच कर सकते हैं ।

और जैसा कि आपने एनोटेट किया @RestControllerहै कि स्पष्ट जोंस रूपांतरण करने की आवश्यकता नहीं है। बस एक पीओजेओ और जैकसन सीरियलाइज़र को जोंस में बदलने का ख्याल रखेगा। यह @ResponseBody@Controller के साथ प्रयोग करने के बराबर है । @ResponseBodyप्रत्येक नियंत्रक पद्धति पर रखने के @RestControllerबजाय हम वेनिला के स्थान पर @Controllerऔर @ResponseBodyडिफ़ॉल्ट रूप से उस नियंत्रक के सभी संसाधनों पर लागू होते हैं।
इस लिंक को देखें: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody

आपके द्वारा सामना की जा रही समस्या इसलिए है क्योंकि लौटी हुई वस्तु (JSONObject) में कुछ गुणों के लिए गटर नहीं है। और आपका इरादा इस JSONObject को अनुक्रमित करना नहीं है, बल्कि एक POJO को क्रमबद्ध करना है। तो बस POJO लौटाएं।
इस लिंक को देखें: https://stackoverflow.com/a/35822500/5039001

यदि आप एक जरीन क्रमबद्ध स्ट्रिंग वापस करना चाहते हैं, तो बस स्ट्रिंग वापस करें। स्प्रिंग इस मामले में JSON कनवर्टर के बजाय StringHttpMessageConverter का उपयोग करेगा।


अगर json string वह है जो आप java से लौटाना चाहते हैं तो आप एक string वापस कर सकते हैं यदि यह पहले से ही json serialized है। स्ट्रिंग को json और json में वापस स्ट्रिंग में बदलने की आवश्यकता नहीं है।
कुमार

5
यदि आप एक कठोर संकलन समय संरचना के बिना नाम-मूल्य जोड़े का एक सेट वापस करना चाहते हैं, तो आप एक Map<String,Object>या एक Propertiesवस्तु वापस कर सकते हैं
विहंग

@prem कुमार यादृच्छिक प्रश्न: 'वेनिला कंट्रोलर और रेस्पॉन्सबॉडी के बजाय' से आपका क्या तात्पर्य है? क्या यहाँ वेनिला है?
ओरकुन ओजेन

मेरा मतलब था एक सामान्य नियंत्रक और प्रत्येक अनुरोध पद्धति पर रखा गया ResponseBody एनोटेशन के साथ।
प्रीमियर कुमार

66

जैक्सन को डिफ़ॉल्ट रूप से क्रमबद्ध करने और ऑब्जेक्ट्स को डीसिएराइज़ करने के लिए उपयोग करने के कारण आपका वर्तमान दृष्टिकोण काम नहीं करता है। हालाँकि, यह पता नहीं है कि कैसे क्रमबद्ध करना है JSONObject। यदि आप एक गतिशील JSON संरचना बनाना चाहते हैं, तो आप Mapउदाहरण के लिए a का उपयोग कर सकते हैं :

@GetMapping
public Map<String, String> sayHello() {
    HashMap<String, String> map = new HashMap<>();
    map.put("key", "value");
    map.put("foo", "bar");
    map.put("aa", "bb");
    return map;
}

यह निम्नलिखित JSON प्रतिक्रिया की ओर ले जाएगा:

{ "key": "value", "foo": "bar", "aa": "bb" }

यह थोड़ा सीमित है, क्योंकि बाल वस्तुओं को जोड़ना थोड़ा और मुश्किल हो सकता है। जैक्सन का अपना तंत्र है, हालांकि, उपयोग ObjectNodeऔर ArrayNode। इसका उपयोग करने के लिए, आपको ObjectMapperअपनी सेवा / नियंत्रक में ऑटो करना होगा । तो आप का उपयोग कर सकते हैं:

@GetMapping
public ObjectNode sayHello() {
    ObjectNode objectNode = mapper.createObjectNode();
    objectNode.put("key", "value");
    objectNode.put("foo", "bar");
    objectNode.put("number", 42);
    return objectNode;
}

यह दृष्टिकोण आपको बाल वस्तुओं, सरणियों को जोड़ने और सभी विभिन्न प्रकारों का उपयोग करने की अनुमति देता है।


2
यहाँ मैपर क्या है?
इवेकेसी

1
@ आईवेसी वह जैक्सन है ObjectMapperजिसे आपको ऑटोवॉयर करना चाहिए (मेरे अंतिम कोड स्निपेट के ऊपर पैराग्राफ देखें)।
g00glen00b

1
यह जानना आश्चर्यजनक है कि सार्थक JSON वस्तुओं के उत्पादन के लिए किसी को इतनी लंबाई तक जाना पड़ता है! यह भी दुखद है कि इन सीमाओं को पुकारने के लिए पिवटल ने कोई प्रयास नहीं किया है ( spring.io/guides/gs/actuator-service )। सौभाग्य से, हमारे पास SO है! ;)
cogitoergosum

आयात java.util.HashMap हल नहीं किया जा सकता
Hikaru Shindo

@HikaruShindo java.util.HashMapजावा 1.2 के बाद से जावा की एक मुख्य कार्यक्षमता है।
g00glen00b

43

आप या तो एक प्रतिक्रिया वापस कर सकते हैं Stringजैसा कि @vagaasen द्वारा सुझाया गया है या आप ResponseEntityनीचे दी गई स्प्रिंग द्वारा प्रदान की गई वस्तु का उपयोग कर सकते हैं । इस तरह से आप वापसी भी कर सकते हैं Http status codeजो कि वेबसर्विस कॉल में अधिक सहायक है।

@RestController
@RequestMapping("/api")
public class MyRestController
{

    @GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Object> sayHello()
    {
         //Get data from service layer into entityList.

        List<JSONObject> entities = new ArrayList<JSONObject>();
        for (Entity n : entityList) {
            JSONObject entity = new JSONObject();
            entity.put("aa", "bb");
            entities.add(entity);
        }
        return new ResponseEntity<Object>(entities, HttpStatus.OK);
    }
}

1
अगर मैं संस्थाओं में JSONObject जोड़ता हूं, तो यह मुझे फिर से समान अपवाद दे रहा है
iwekesi

@Sangam आपके जवाब से मुझे जैकसन-डेटाफ़ॉर्मेट-xml से संबंधित एक और समस्या के लिए मदद मिली
दिव्य

यह एक बड़ी मदद थी! धन्यवाद!
जॉन्स-क्रिस

1
मुझे आश्चर्य है कि यह उत्तर अधिक क्यों नहीं उत्कीर्ण किया गया है। मैं स्प्रिंग के लिए भी नया हूं, इसलिए मुझे नहीं पता कि यह एक अच्छा सॉफ्टवेयर इंजीनियरिंग अभ्यास है। इसके साथ ही कहा, इस जवाब से मुझे मदद मिली। हालाँकि, मुझे इससे बहुत परेशानी हुई JSONObject, लेकिन चूंकि स्प्रिंग ने जैक्सन का उपयोग किया इसलिए मैंने इसे बदले में बदल दिया HashMapऔर फिर इस उत्तर में मैंने जो कोड पढ़ा, उसने काम किया।
मेल्विन रोस्ट

2
MediaType.APPLICATION_JSON_VALUE को सुझाव देने के लिए +1 क्योंकि यह सुनिश्चित करता है कि उत्पादित परिणाम को json के रूप में पार्स किया जाए क्योंकि यदि आप परिभाषित नहीं करते हैं तो ऐसा हो सकता है
संदीप मंडोरी

11

आप इसके लिए हैशमैप का उपयोग भी कर सकते हैं

@GetMapping
public HashMap<String, Object> get() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("key1", "value1");
    map.put("results", somePOJO);
    return map;
}

6
@RequestMapping("/api/status")
public Map doSomething()
{
    return Collections.singletonMap("status", myService.doSomething());
}

पुनश्च। केवल 1 मान के लिए काम करता है


3

उपयोग ResponseEntity<ResponseBean>

यहां आप रिस्पॉन्सबिन या किसी भी जावा बीन का उपयोग कर सकते हैं क्योंकि आप अपनी एपीआई प्रतिक्रिया वापस करना चाहते हैं और यह सबसे अच्छा अभ्यास है। मैंने प्रतिक्रिया के लिए Enum का उपयोग किया है। यह एपीआई का स्टेटस कोड और स्टेटस मैसेज लौटाएगा।

@GetMapping(path = "/login")
public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request,
            HttpServletResponse response) {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        loginService.login(username, password, request);
        return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS,
                HttpStatus.ACCEPTED);
    }

प्रतिक्रिया के लिए ServiceStatus या (ResponseBody)

    public enum ServiceStatus {

    LOGIN_SUCCESS(0, "Login success"),

    private final int id;
    private final String message;

    //Enum constructor
    ServiceStatus(int id, String message) {
        this.id = id;
        this.message = message;
    }

    public int getId() {
        return id;
    }

    public String getMessage() {
        return message;
    }
}

प्रतिक्रिया में स्प्रिंग रेस्ट एपीआई की कुंजी नीचे होनी चाहिए

  1. स्थिति का कोड
  2. संदेश

आपको नीचे अंतिम प्रतिक्रिया मिलेगी

{

   "StatusCode" : "0",

   "Message":"Login success"

}

आप अपनी आवश्यकता के अनुसार रिस्पांसबॉडी (जावा पोजो, एनयूएम, आदि) का उपयोग कर सकते हैं।


2

API प्रश्नों के लिए DTO को अधिक सही बनाएं, उदाहरण के लिए ,DDTO:

  1. संस्थाओं की सूची के साथ डिफ़ॉल्ट प्रतिक्रिया ठीक है:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
@ResponseStatus(HttpStatus.OK)
public List<EntityDto> getAll() {
    return entityService.getAllEntities();
}

लेकिन अगर आपको अलग-अलग मैप मापदंडों की ज़रूरत है, तो आप अगले दो उदाहरणों का उपयोग कर सकते हैं
। 2. रिटर्न के लिए एक पैरामीटर जैसे मानचित्र:

@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getOneParameterMap() {
    return ResponseEntity.status(HttpStatus.CREATED).body(
            Collections.singletonMap("key", "value"));
}
  1. और अगर आपको कुछ मापदंडों का रिटर्न मैप चाहिए (जावा 9 के बाद से):
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getSomeParameters() {
    return ResponseEntity.status(HttpStatus.OK).body(Map.of(
            "key-1", "value-1",
            "key-2", "value-2",
            "key-3", "value-3"));
}

1

यदि आपको स्ट्रिंग का उपयोग करके एक JSON ऑब्जेक्ट वापस करने की आवश्यकता है, तो निम्न कार्य करना चाहिए:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
...

@RestController
@RequestMapping("/student")
public class StudentController {

    @GetMapping
    @RequestMapping("/")
    public ResponseEntity<JsonNode> get() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}");
        return ResponseEntity.ok(json);
    }
    ...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.