Ajax का उपयोग कर एक स्प्रिंग एमवीसी नियंत्रक @RequestBody में कई चर पासिंग


113

क्या बैकिंग ऑब्जेक्ट में लपेटना आवश्यक है? मैं यह करना चाहता हूँ:

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody String str1, @RequestBody String str2) {}

और इस तरह एक JSON का उपयोग करें:

{
    "str1": "test one",
    "str2": "two test"
}

लेकिन इसके बजाय मुझे उपयोग करना होगा:

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody Holder holder) {}

और फिर इस JSON का उपयोग करें:

{
    "holder": {
        "str1": "test one",
        "str2": "two test"
    }
}

क्या वो सही है? मेरा दूसरा विकल्प क्वेरी स्ट्रिंग में या तो उपयोग RequestMethodकरना GETऔर उसके साथ बदलना @RequestParamया @PathVariableदोनों का उपयोग करना होगा RequestMethod

जवाबों:


92

आप सही हैं, @RequestBody एनोटेट पैरामीटर से अपेक्षा की जाती है कि वह अनुरोध के संपूर्ण निकाय को रखे और एक वस्तु से बंधे, इसलिए आपको अनिवार्य रूप से अपने विकल्पों के साथ जाना होगा।

यदि आप पूरी तरह से अपना दृष्टिकोण चाहते हैं, तो एक कस्टम कार्यान्वयन है जिसे आप हालांकि कर सकते हैं:

कहो यह आपका जसन है:

{
    "str1": "test one",
    "str2": "two test"
}

और आप इसे यहां दो पारमों से बांधना चाहते हैं:

@RequestMapping(value = "/Test", method = RequestMethod.POST)
public boolean getTest(String str1, String str2)

पहले एक कस्टम एनोटेशन को परिभाषित करें @JsonArg, जो JSON पथ के साथ उस सूचना को पथ के रूप में बताए जो आप चाहते हैं:

public boolean getTest(@JsonArg("/str1") String str1, @JsonArg("/str2") String str2)

अब एक कस्टम हैंडलरमैथोडरगमेंटइंडोल्वर लिखें जो वास्तविक तर्क को हल करने के लिए ऊपर परिभाषित JsonPath का उपयोग करता है:

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.jayway.jsonpath.JsonPath;

public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver{

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonArg.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String body = getRequestBody(webRequest);
        String val = JsonPath.read(body, parameter.getMethodAnnotation(JsonArg.class).value());
        return val;
    }

    private String getRequestBody(NativeWebRequest webRequest){
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        String jsonBody = (String) servletRequest.getAttribute(JSONBODYATTRIBUTE);
        if (jsonBody==null){
            try {
                String body = IOUtils.toString(servletRequest.getInputStream());
                servletRequest.setAttribute(JSONBODYATTRIBUTE, body);
                return body;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return "";

    }
}

अब बस इसे स्प्रिंग एमवीसी के साथ पंजीकृत करें। थोड़ा सा शामिल है, लेकिन यह सफाई से काम करना चाहिए।


2
मैं कस्टम एनोटेशन कैसे बनाऊं, @JsonArg कृपया कहें?
सुरेंद्र ज्ञानवाली

ऐसा क्यों है? अब मुझे बैकएंड में बहुत सारे अलग-अलग रैपर क्लास बनाने हैं। मैं स्प्रिंगबूट के लिए एक Struts2 एप्लिकेशन को माइग्रेट कर रहा हूं और इसमें बहुत सारे मामले थे जहां JSON ऑब्जेक्ट्स को अजाक्स का उपयोग करके भेजा गया था, वास्तव में मॉडल के दो या अधिक ऑब्जेक्ट हैं: उदाहरण के लिए उपयोगकर्ता और एक गतिविधि
जोस ऑस्पिना

इस लिंक पर आप "कैसे इस वसंत MVC के साथ रजिस्टर करने के लिए" दिखाने geekabyte.blogspot.sg/2014/08/...
बोडिल

3
अभी भी बीच में क्यों इस विकल्प को वसंत में नहीं जोड़ा गया है। यह एक तार्किक विकल्प की तरह लगता है जब आपको 2 लोंग पसंद होते हैं और इसके लिए एक रैपर ऑब्जेक्ट बनाने के लिए अभ्यस्त नहीं होते हैं
टिबि

@SurendraJnawali आप इसे इस तरह कर सकते हैं@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface JsonArg { String value() default ""; }
Epono

88

हालांकि यह सच है कि @RequestBodyकिसी एक वस्तु के लिए मैप करना होगा, वह वस्तु ए हो सकती है Map, इसलिए यह आपको एक अच्छा तरीका है जो आप प्राप्त करने का प्रयास कर रहे हैं (बैकिंग ऑब्जेक्ट लिखने की आवश्यकता नहीं है):

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody Map<String, String> json) {
   //json.get("str1") == "test one"
}

यदि आप एक पूर्ण JSON पेड़ चाहते हैं तो आप जैक्सन के ObjectNode से भी बंध सकते हैं:

public boolean getTest(@RequestBody ObjectNode json) {
   //json.get("str1").asText() == "test one"

@JoseOspina ऐसा क्यों नहीं कर सकता। मानचित्र के साथ जुड़ा कोई भी जोखिम <स्ट्रिंग, ऑब्जेक्ट> अनुरोध के साथ
बेन चेंग

@ मेरा मतलब है कि आप Mapकिसी एक वस्तु का उपयोग किसी भी वस्तु को स्टोर करने के लिए कर सकते हैं , लेकिन शीर्ष स्तर की वस्तु अभी भी केवल एक ही होनी चाहिए, दो शीर्ष स्तर की वस्तुएं नहीं हो सकती हैं।
जोस ऑस्पिना

1
मुझे लगता है कि डायनेमिक एप्रोच का नकारात्मक पहलू यह Map<String, String>है: एपीआई डॉक्यूमेंट लाइब्रेरी (स्वैगर / स्प्रिंगस्क्रीन आदि) शायद आपके स्रोत कोड से आपके अनुरोध / प्रतिक्रिया स्कीमा को पार्स नहीं कर पाएंगे।
स्ट्रैटोवेरिक

10

आप सरल डेटा प्रकारों के लिए बॉडी और पाथ वैरिएबल का उपयोग करके पोस्ट तर्क को मिला सकते हैं:

@RequestMapping(value = "new-trade/portfolio/{portfolioId}", method = RequestMethod.POST)
    public ResponseEntity<List<String>> newTrade(@RequestBody Trade trade, @PathVariable long portfolioId) {
...
}

10

कई ऑब्जेक्ट, परम, चर और इतने पर पास करने के लिए। आप जैकसन लाइब्रेरी से ऑब्जेक्ट को अपने पैराम के रूप में गतिशील रूप से उपयोग कर सकते हैं। आप इसे इस तरह से कर सकते हैं:

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody ObjectNode objectNode) {
   // And then you can call parameters from objectNode
   String strOne = objectNode.get("str1").asText();
   String strTwo = objectNode.get("str2").asText();

   // When you using ObjectNode, you can pas other data such as:
   // instance object, array list, nested object, etc.
}

मुझे उम्मीद है कि यह मदद मिलेगी।


2

@RequestParamहै HTTP GETया POSTग्राहक द्वारा भेजे गए पैरामीटर जो चर है यूआरएल का एक खंड, अनुरोध मानचित्रण है:

http:/host/form_edit?param1=val1&param2=val2

var1& var2अनुरोध परमेस हैं।

http:/host/form/{params}

{params}एक अनुरोध मानचित्रण है। आप अपनी सेवा को कॉल कर सकते हैं जैसे: http:/host/form/userया http:/host/form/firm जहां फर्म और उपयोगकर्ता के रूप में उपयोग किया जाता है Pathvariable


यह प्रश्न का उत्तर नहीं देता है और गलत है, आप POST अनुरोधों के साथ एक क्वेरी स्ट्रिंग का उपयोग नहीं करते हैं
NimChimpsky

1
@NimChimpsky: सुनिश्चित करें कि आप कर सकते हैं। POST अनुरोध में अभी भी URL में पैरामीटर शामिल हो सकते हैं।
मार्टिन पीटर्स

2

आसान उपाय यह है कि पेलोड क्लास बनाया जाए जिसमें str1 और str2 विशेषता के रूप में हों:

@Getter
@Setter
public class ObjHolder{

String str1;
String str2;

}

और पास होने के बाद

@RequestMapping(value = "/Test", method = RequestMethod.POST)
@ResponseBody
public boolean getTest(@RequestBody ObjHolder Str) {}

और आपके अनुरोध का मुख्य भाग है:

{
    "str1": "test one",
    "str2": "two test"
}

1
इस एनोटेशन का पैकेज क्या है? Autoimport ने केवल आयात किया jdk.nashorn.internal.objects.annotations.Setter; संपादित करें। मुझे लगता है कि यह लोम्बोक प्रोजेक्टलॉम्बोक . org/features/GetterSetter है । कृपया मुझे सही करें अगर मैं गलत हूं
Gleichmut

@ Gleichmut आप अपने चर के लिए सरल गेटर्स और सेटर का उपयोग कर सकते हैं। यह आपकी अपेक्षा के अनुरूप काम करेगा।
जिमनाथ

1

Json का उपयोग करने के बजाय, आप साधारण काम कर सकते हैं।

$.post("${pageContext.servletContext.contextPath}/Test",
                {
                "str1": "test one",
                "str2": "two test",

                        <other form data>
                },
                function(j)
                {
                        <j is the string you will return from the controller function.>
                });

नियंत्रक में अब आपको नीचे दिए गए ajax अनुरोध को मैप करने की आवश्यकता है:

 @RequestMapping(value="/Test", method=RequestMethod.POST)
    @ResponseBody
    public String calculateTestData(@RequestParam("str1") String str1, @RequestParam("str2") String str2, HttpServletRequest request, HttpServletResponse response){
            <perform the task here and return the String result.>

            return "xyz";
}

आशा है कि यह आपकी मदद करता है।


1
यह json है, और यह काम नहीं करता है। आप मेथडपराम को विधि में निर्दिष्ट कर रहे हैं, लेकिन अजाक्स पोस्ट अनुरोध में जस के साथ समानता को परिभाषित कर रहे हैं।
निमचम्पस्की

देखें कि मैंने ajax कॉल में JSON प्रारूप का उपयोग नहीं किया है। मैंने केवल दो अनुरोध पार्म्स का उपयोग किया है और नियंत्रक में हम एनोटेशन @RequestParam के साथ उन पार्म्स प्राप्त कर सकते हैं। यह काम कर रहा है। मैं इसका उपयोग करता हूं। इसे मात्र आजमाएं।
जापान त्रिवेदी

मैंने कोशिश की है, इसके क्वेशटन की बात। यह उस तरह काम नहीं करता है।
निमचम्पस्की

कृपया निर्दिष्ट करें कि आपने वास्तव में क्या प्रयास किया है। अपने प्रश्न में वह दिखाओ। मुझे लगता है कि आपको मेरी समझ से अलग आवश्यकता है।
जापान त्रिवेदी

1
पहली कोशिश में मेरे लिए काम किया। धन्यवाद!
हम्पाकरीसाज

1

मैंने बीजू के हल को अनुकूलित किया है:

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;


public class JsonPathArgumentResolver implements HandlerMethodArgumentResolver{

    private static final String JSONBODYATTRIBUTE = "JSON_REQUEST_BODY";

    private ObjectMapper om = new ObjectMapper();

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(JsonArg.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String jsonBody = getRequestBody(webRequest);

        JsonNode rootNode = om.readTree(jsonBody);
        JsonNode node = rootNode.path(parameter.getParameterName());    

        return om.readValue(node.toString(), parameter.getParameterType());
    }


    private String getRequestBody(NativeWebRequest webRequest){
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);

        String jsonBody = (String) webRequest.getAttribute(JSONBODYATTRIBUTE, NativeWebRequest.SCOPE_REQUEST);
        if (jsonBody==null){
            try {
                jsonBody = IOUtils.toString(servletRequest.getInputStream());
                webRequest.setAttribute(JSONBODYATTRIBUTE, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return jsonBody;

    }

}

क्या अलग है:

  • मैं जैक्सन का उपयोग कर रहा हूं कि वह जोंसन में परिवर्तित हो जाए
  • मुझे एनोटेशन में मान की आवश्यकता नहीं है, आप MethodParameter के पैरामीटर का नाम पढ़ सकते हैं
  • मैंने मेथापरमीटर => से बाहर पैरामीटर के प्रकार को भी पढ़ा है, इसलिए समाधान सामान्य होना चाहिए (मैंने इसे स्ट्रिंग और डीटीओ के साथ परीक्षण किया है)

बीआर


0

GET और POST दोनों के लिए अनुरोध पैरामीटर मौजूद है, इसके लिए इसे URL से क्वेरी स्ट्रिंग के रूप में जोड़ा जाएगा लेकिन POST के लिए यह अनुरोध स्वास्थ्य के भीतर है


0

यकीन नहीं है कि आप कहाँ जोड़ते हैं लेकिन अगर मैं इसे इस तरह से कोणीय के साथ करता हूं तो यह अनुरोध के बिना काम करता है।

    const params: HttpParams = new HttpParams().set('str1','val1').set('str2', ;val2;);
    return this.http.post<any>( this.urlMatch,  params , { observe: 'response' } );

जावा:

@PostMapping(URL_MATCH)
public ResponseEntity<Void> match(Long str1, Long str2) {
  log.debug("found: {} and {}", str1, str2);
}

0

अच्छा। मैं सुझाव देता हूं कि एक वैल्यू ऑब्जेक्ट (वीओ) बनाएं जिसमें आपके लिए आवश्यक फ़ील्ड हों। कोड सरल है, हम जैक्सन के कामकाज को नहीं बदलते हैं और इसे समझना और भी आसान है। सादर!


0

जिसे आप इस्तेमाल करके हासिल कर सकते हैं @RequestParam। इसके लिए आपको निम्नलिखित कार्य करने चाहिए:

  1. RequestParams पैरामीटर घोषित करें जो आपकी वस्तुओं का प्रतिनिधित्व करते हैं और requiredयदि आप एक शून्य मान भेजने में सक्षम होना चाहते हैं तो विकल्प को गलत पर सेट करें ।
  2. सीमा पर, उन वस्तुओं को सख्त करें जिन्हें आप भेजना चाहते हैं और उन्हें अनुरोध पैरामीटर के रूप में शामिल करना चाहते हैं।
  3. बैकएंड पर JSON स्ट्रिंग्स को उन वस्तुओं में वापस लाएं, जिनका वे जैक्सन ऑब्जेक्टमैपर या ऐसा कुछ और वॉयला का उपयोग करके प्रतिनिधित्व करते हैं!

मुझे पता है, इसका एक हैक है, लेकिन यह काम करता है! ;)


0

आप उपयोगकर्ता भी कर सकते हैं @RequestBody Map<String, String> params, फिर params.get("key")पैरामीटर का मान प्राप्त करने के लिए उपयोग करें


0

रिक्वेस्ट को होल्ड करने के लिए आप एक मल्टीवैल्यू मैप का भी इस्तेमाल कर सकते हैं। यहां इसके लिए उदाहरण दिया गया है।

    foosId -> pathVariable
    user -> extracted from the Map of request Body 

@RequestBody एनोटेशन के विपरीत, मानचित्र का उपयोग करते समय अनुरोध बॉडी को रखने के लिए हमें @RequestBaram के साथ एनोटेट करने की आवश्यकता होती है

और Json RequestBody में उपयोगकर्ता को भेजें

  @RequestMapping(value = "v1/test/foos/{foosId}", method = RequestMethod.POST, headers = "Accept=application"
            + "/json",
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE ,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ResponseBody
    public String postFoos(@PathVariable final Map<String, String> pathParam,
            @RequestParam final MultiValueMap<String, String> requestBody) {
        return "Post some Foos " + pathParam.get("foosId") + " " + requestBody.get("user");
    }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.