2013-09-22 3 views
30

मुझे समस्याएं समझ रही हैं कि स्प्रिंग 3 एमवीसी काम में कोई फॉर्म कैसे सबमिट करता है।फॉर्म स्प्रिंग एमवीसी 3 में सबमिट करें - स्पष्टीकरण

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

@Controller 
public class HomeController { 

    @RequestMapping(value = "/", method = RequestMethod.GET) 
    public String showHelloPage(Model model) { 
     model.addAttribute("person", new Person()); 
     return "home"; 
    } 

    @RequestMapping(value = "/", method = RequestMethod.POST) 
    public String sayHello(Person person, Model model) { 
     model.addAttribute("person", person); 
     return "home"; 
    } 
} 

एक उपयोगकर्ता मैं उपयोग करने के लिए एक स्वागत संदेश प्रदर्शित करने के लिए:

<form:form method="post" modelAttribute="person"> 
    <form:label path="firstName">First name</form:label> 
    <form:input path="firstName" /> 
    <br /> 

    <form:label path="lastName">Last name</form:label> 
    <form:input path="lastName" /> 
    <br /> 

    <input type="submit" value="Submit" /> 
</form:form> 

मैं भी एक नियंत्रक जो इस तरह दिखता है: तो ..

मैं एक रूप है जो इस तरह दिखता है जेएसपी पृष्ठ में निम्नलिखित कोड:

<c:if test="${not empty person.firstName and not empty person.lastName}"> 
    Hello ${person.firstName} ${person.lastName}! 
</c:if> 

और यह काम करता है (मैं XML कॉन्फ़िगरेशन फ़ाइलों को छोड़ देता हूं क्योंकि वे ar ई समस्या के लिए अप्रासंगिक)।

मैंने सोचा था कि एक फॉर्म में "मॉडल एट्रिब्यूट" विशेषता बीन वैरिएबल को इंगित करती है जिसे इनपुट के मानों के साथ पॉप्युलेट किया जाना चाहिए (जैसा कि उनके "पथ" गुणों में सेट किया गया है)। लेकिन लगता है, यह एक बहुत ही अलग तरीके से काम करता है। अगर मैं "showHelloPage" विधि से लाइन

model.addAttribute("person", new Person()); 

को दूर मैं एक (सामान्य) अपवाद "न तो BindingResult है और न ही ..." मिलता है।

इसके अलावा, शुरुआत पर, "sayHello" विधि देखा की तरह:

(...) 
public String sayHello(@ModelAttribute("person") Person person, Model model) { 
(...) 

मेरा मतलब है, यह "ModelAttribute" एनोटेशन था। मैंने इसे जोड़ा, क्योंकि मैंने पढ़े गए ट्यूटोरियल में, यह हमेशा मौजूद था। लेकिन जब मैंने इसे हटा दिया, तो सबकुछ ठीक से काम करता था, जैसा कि पहले हुआ था।

तो मेरा प्रश्न है - "ModelAttribute" anonnatation का उपयोग क्या है? क्या यह किसी रूप में "मॉडल एट्रिब्यूट" विशेषता को छोड़ने का कोई तरीका है? और दूसरा भाग, एक फॉर्म बनाने के लिए तरीका (शायद कुछ एनोटेशन) स्वचालित रूप से इनपुट बीन्स के गुणों को सही बीन के गुणों (जिसे विधि पैरामीटर के रूप में घोषित किया जाएगा) को बांधने का तरीका क्या है? एक फॉर्म भेजने से पहले एक खाली बीन जोड़ने की आवश्यकता के बिना (जैसा कि मुझे अब करना है)।

आपके उत्तरों के लिए धन्यवाद (जो वसंत के दस्तावेज़ीकरण से जुड़े नहीं हैं, क्योंकि मैंने इसे पहले ही पढ़ा है)।

उत्तर

38

@ModelAttribute इस मामले में एनोटेशन का उपयोग किसी ऑब्जेक्ट की पहचान करने के लिए किया जाता है जिसे वसंत को मॉडल विशेषता के रूप में जोड़ना चाहिए। मॉडल विशेषता HttpServletRequest विशेषताओं से एक अमूर्त है। असल में, वे कुछ कुंजी द्वारा पहचाने जाते हैं जिन्हें HttpServletRequest विशेषताओं में अपना रास्ता मिल जाएगा। आप Model#addAttribute(String, Object) के साथ मैन्युअल रूप से एक विशेषता जोड़कर ऐसा कर सकते हैं, @ModelAttribute एनोटेटेड विधि है, या @ModelAttribute के साथ विधि पैरामीटर को एनोटेट करके।

आपको यह समझने की आवश्यकता है कि वसंत आपके हैंडलर विधि पैरामीटर को कैसे हल करता है और तर्कों को इंजेक्ट करता है। ऐसा करने के लिए यह HandlerMethodArgumentResolver इंटरफ़ेस का उपयोग करता है। कई कार्यान्वयन वर्ग हैं (जावाडोक देखें) और प्रत्येक को resolveArgument() की ज़िम्मेदारी है कि इस तर्क को वापस कर लें कि वसंत invoke() प्रतिबिंब के माध्यम से आपके हैंडलर विधि का उपयोग करेगा।HandlerMethodArgumentResolversupportsParameter() विधि विशिष्ट पैरामीटर के लिए true देता है, तो वसंत केवल resolveArgument() विधि को कॉल करेगा।

यहाँ प्रश्न में HandlerMethodArgumentResolver कार्यान्वयन ServletModelAttributeMethodProcessor जो ModelAttributeMethodProcessor जो

हल विधि @ModelAttribute साथ एनोटेट तर्क में कहा गया है और @ModelAttribute साथ एनोटेट तरीकों से वापसी मान हैंडल से फैली हुई है।

स्प्रिंग (3.2) register होगा इस HandlerMethodArgumentResolver और दूसरों

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() { 
     List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>(); 

    // Annotation-based argument resolution 
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false)); 
    resolvers.add(new RequestParamMapMethodArgumentResolver()); 
    resolvers.add(new PathVariableMethodArgumentResolver()); 
    resolvers.add(new ServletModelAttributeMethodProcessor(false)); 
    resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters())); 
    resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters())); 
    resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory())); 
    resolvers.add(new RequestHeaderMapMethodArgumentResolver()); 
    resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory())); 
    resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory())); 

    // Type-based argument resolution 
    resolvers.add(new ServletRequestMethodArgumentResolver()); 
    resolvers.add(new ServletResponseMethodArgumentResolver()); 
    resolvers.add(new HttpEntityMethodProcessor(getMessageConverters())); 
    resolvers.add(new RedirectAttributesMethodArgumentResolver()); 
    resolvers.add(new ModelMethodProcessor()); 
    resolvers.add(new MapMethodProcessor()); 
    resolvers.add(new ErrorsMethodArgumentResolver()); 
    resolvers.add(new SessionStatusMethodArgumentResolver()); 
    resolvers.add(new UriComponentsBuilderMethodArgumentResolver()); 

    // Custom arguments 
    if (getCustomArgumentResolvers() != null) { 
     resolvers.addAll(getCustomArgumentResolvers()); 
    } 

    // Catch-all 
    resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true)); 
    resolvers.add(new ServletModelAttributeMethodProcessor(true)); 

    return resolvers; 
} 

वसंत अपने हैंडलर विधि को लागू करने की जरूरत है है, यह पैरामीटर प्रकार के माध्यम से और ऊपर सूची के माध्यम से पुनरावृति और पहले एक का उपयोग करेंगे supportsParameter()

ध्यान दें कि ServletModelAttributeMethodProcessor के दो उदाहरण जोड़े गए हैं (//catch all टिप्पणी के बाद एक)। ModelAttributeMethodProcessor में annotationNotRequired फ़ील्ड है जो इसे बताता है कि उसे @ModelAttribute या नहीं देखना चाहिए। पहला उदाहरण @ModelAttribute के लिए देखना चाहिए, दूसरा नहीं है। वसंत ऐसा करता है ताकि आप अपना खुद का HandlerMethodArgumentResolver उदाहरण पंजीकृत कर सकें, // Custom arguments टिप्पणी देखें।


विशेष रूप

@RequestMapping(value = "/", method = RequestMethod.POST) 
public String sayHello(Person person, Model model) { 
    model.addAttribute("person", person); 
    return "home"; 
} 

इस मामले में, यह कोई बात नहीं अगर आपके Person पैरामीटर या व्याख्या की नहीं है। एक ModelAttributeMethodProcessor इसे हल करेगा और फार्म फ़ील्ड बाध्य करेगा, यानी। उदाहरण के क्षेत्रों में अनुरोध पैरामीटर। आपको इसे model में जोड़ने की आवश्यकता नहीं है क्योंकि ModelAttributeMethodProcessor कक्षा उस संभाल लेंगी।

अपने showHelloPage() विधि

model.addAttribute("person", new Person()); 

में <form> taglib साथ की जरूरत है। इस तरह यह input फ़ील्ड को हल करता है।


तो मेरे सवाल है - "ModelAttribute" anonnatation के उपयोग क्या है?

मॉडल में निर्दिष्ट पैरामीटर (या विधि वापसी मूल्य) स्वचालित रूप से जोड़ने के लिए।

क्या यह किसी रूप में "मॉडल एट्रिब्यूट" विशेषता को छोड़ने का कोई तरीका है?

नहीं है, Model में एक वस्तु के लिए form बाध्यकारी दिखता है और उसके खेतों बांधता input तत्वों HTML करने के लिए।

और दूसरा हिस्सा है, जिस तरह से (शायद कुछ एनोटेशन) एक फॉर्म स्वतः बनाने के लिए उचित सेम के गुणों (जो एक विधि पैरामीटर के रूप में घोषित किया जाता था) को इनपुट 'मान बाँध क्या है? एक फॉर्म भेजने से पहले एक खाली बीन जोड़ने की आवश्यकता के बिना (जैसा कि मुझे अभी करना है)।

एक स्प्रिंग <form> टैग latches पर एक मॉडल वस्तु को विशिष्ट बनाने और input और label तत्वों को बनाने के अपने क्षेत्रों का उपयोग करता है। इससे कोई फर्क नहीं पड़ता कि ऑब्जेक्ट मॉडल के अंत तक जब तक ऑब्जेक्ट समाप्त हुआ। यदि आपके द्वारा निर्दिष्ट नाम (कुंजी) के साथ कोई मॉडल विशेषता नहीं मिलती है, तो यह देखा गया है कि यह अपवाद फेंकता है।

<form:form method="post" modelAttribute="person"> 

खाली बीन प्रदान करने का विकल्प स्वयं को HTML बनाना है। सभी वसंत <form>input तत्व बनाने के लिए बीन के फ़ील्ड नामों का उपयोग करता है। तो यह

<form:form method="post" modelAttribute="person"> 
    <form:label path="firstName">First name</form:label> 
    <form:input path="firstName" /> 

बनाता है की तरह

<form method="post" action="[some action url]"> 
    <label for="firstName">First name<label> 
    <input type="text" name="firstName" value="[whatever value firstName field had]" /> 
    ... 

स्प्रिंग कुछ name विशेषता का उपयोग कर उदाहरण क्षेत्रों के लिए अनुरोध पैरामीटर बांधता है।

+0

आपके उत्तर के लिए बहुत बहुत धन्यवाद, आपने मुझे बहुत समझाया। "ModelAttribute" एनोटेशन के बारे में सिर्फ एक और सवाल - यदि मैं आपको सही ढंग से समझता हूं, तो विधि पैरामीटर के साथ उपयोग की जाने वाली यह एनोटेशन "model.addAttribute (...)" के बराबर है? –

+0

@ MichałTabor इसे विधि पैरामीटर के रूप में जोड़ने का प्रयास करें। मैं अनिश्चित हूं, अगर अनुरोध में कोई अनुरोध पैरामीटर नहीं है जो बाध्य किया जा सकता है, तो यह 'शून्य' वापस आ जाएगा। अन्यथा, जिस तरह से आप कर रहे हैं वह सही तरीका है। इन्हें डेटा ट्रांसफर ऑब्जेक्ट्स (या स्प्रिंग फॉर्म बैकिंग ऑब्जेक्ट्स/कमांड ऑब्जेक्ट्स) के रूप में जाना जाता है। दस्तावेज में अधिक जानकारी होनी चाहिए। –

+0

+1, महान व्याख्या – rocketboy

संबंधित मुद्दे