/ / वसंत एमवीसी जटिल वस्तु डेटा बाध्यकारी - वसंत, वसंत-एमवीसी, डेटा बाध्यकारी

वसंत एमवीसी जटिल वस्तु डेटा बाध्यकारी - वसंत, वसंत-एमवीसी, डेटा बाध्यकारी

मैं अभी भी स्प्रिंग एमवीसी के साथ संघर्ष कर रहा हूं, जिसमें काफी सीधी समस्या होनी चाहिए लेकिन स्प्रिंग एमवीसी दस्तावेज में क्या स्पष्ट रूप से प्रलेखित किया गया है।

मेरी परियोजना दृश्यों के लिए स्प्रिंग एमवीसी और थाइमेलीफ का उपयोग करती है, लेकिन दृश्य प्रतिपादन इंजन समस्या के लिए वास्तव में प्रासंगिक नहीं है।

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

गतिविधि इकाई वर्ग के लिए कोड निम्नानुसार है, कोड को छोटा करने के लिए गैर प्रासंगिक फ़ील्ड छोड़े गए हैं:

package nl.drsklaus.activiteitensite.model;

//imports

@Entity
@Table(name="activity")
public class Activity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;

@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="organizer_id")
private Member organizer;

@Size(min=5, max=50)
@Column(name = "title", nullable = false)
private String title;

@Size(min=5, max=500)
@Column(name = "description", nullable = false)
private String description;

@ManyToOne
@JoinColumn(name="category_id")
private ActivityCategory category;

@ManyToOne
@JoinColumn(name="region_id")
private ActivityRegion region;


@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name="member_activity_subscription",
joinColumns = {@JoinColumn(name="activity_id")},
inverseJoinColumns={@JoinColumn(name="member_id")})
private List<Member> participants = new ArrayList<Member>();

//getters and setters

@Override
public int hashCode() {
...
}

@Override
public boolean equals(Object obj) {
...
}
}

दृश्य में, उपयोगकर्ता एक चयन बॉक्स से क्षेत्र और श्रेणी का चयन करने में सक्षम होना चाहिए। क्लास स्तर पर @ModelAttribute एनोटेटेड विधि का उपयोग करके मॉडल में इन विकल्पों को रखा जाता है।

यह समस्या लुकअप संपत्ति फ़ील्ड में बॉक्स के बाध्यकारी के साथ है।

उदाहरण के लिए श्रेणी फ़ील्ड ActivityCategory प्रकार का है, जो एक इकाई वर्ग है जिसमें आईडी और विवरण संपत्ति होती है।

दृश्य में, चयन बॉक्स भर गया हैसंभावित विकल्पों की सूची (सभी श्रेणियां जिनमें गतिविधि श्रेणी उदाहरण शामिल हैं), थाइमेलीफ सूची के साथ "मूल्य" विशेषता मान से मेल करके वर्तमान मूल्य का चयन करने का ख्याल रखता है:

<label>Categorie</label>
<select th:field="*{category}">
<option th:each="cat : ${allCategories}"
th:value="${cat}"
th:text="${cat.description}">
</option>
</select>

जेनरेट किया गया HTML इस तरह दिखता है:

<select id="category" name="category">
<option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@20">Actief en sportief</option>
<option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@21">Uitgaan en nachtleven</option>
<option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@22" selected="selected">Kunst en cultuur</option>
<option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@23">Eten en drinken</option>
<option value="nl.drsklaus.activiteitensite.model.lookup.ActivityCategory@24" selected="selected">Ontspanning en gezelligheid</option>
</select>

जैसा कि हम देखते हैं, मान गुणों में एक स्ट्रिंग होती हैऑब्जेक्ट का प्रतिनिधित्व जो स्पष्ट रूप से वांछित नहीं है, आईडी मान दिखाने के लिए हम $ {cat} के बजाय $ {cat.id} का उपयोग कर सकते हैं लेकिन फिर वर्तमान मान का चयन ("चयनित =" चयनित विशेषता " ) अब और काम नहीं करता है। इसलिए मैंने एक कनवर्टर लागू किया जो एक गतिविधि श्रेणी वस्तु को एक int (आईडी मान) में परिवर्तित करता है। Thymeleaf में, कनवर्टर को डबल accolades {{}} का उपयोग करके बुलाया जाता है:

th:value="${{cat}}"

यह कनवर्टर बनाया गया है और वसंत में जोड़ा गया है:

public class LookupConverter implements Converter<LookupEntity, String> {
public String convert(LookupEntity source) {
return String.valueOf(source.getId());
}
}

// एमवीसी कॉनफिग कक्षा में

@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new LookupConverter());
}

अब एचटीएमएल विकल्पों के लिए आईडी मान दिखाता है, जो कि अधिक तार्किक है:

<select id="category" name="category">
<option value="1">Actief en sportief</option>
<option value="2">Uitgaan en nachtleven</option>
<option value="3" selected="selected">Kunst en cultuur</option>
<option value="4">Eten en drinken</option>
<option value="5">Ontspanning en gezelligheid</option>
</select>

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

मेरा हैंडलर विधि इस तरह दिखता है:

@RequestMapping(value = "/{id}/submit", method = RequestMethod.POST)
public String submitForm(@ModelAttribute("activity") Activity activity, BindingResult result, ModelMap model) {

if (result.hasErrors()) {
return "activityform";
} else {

if (activity.getId() == null) {
this.service.saveActivity(activity);
} else {
this.service.mergeWithExistingAndUpdate(activity);
}

return "redirect:/activity/" + activity.getId() + "/detail";
}
}

मैंने कई पदों पर ध्यान दिया है लेकिन अभी भी मिला हैइस आईएमएचओ के लिए बहुत ही मामूली मुद्दा नहीं है। आईडी युक्त स्ट्रिंग मान को हैंडलर विधि द्वारा स्वीकार किया जा सकता है और सही तरीके से परिवर्तित किया जा सकता है? या हम इस उद्देश्य के लिए आईडी मान का उपयोग नहीं कर सकते हैं? कुछ संकेतों की तलाश में ...

उत्तर:

जवाब के लिए 0 № 1

मुझे लगता है कि आप सबमिट करने के लिए अपने इकाई मॉडल का उपयोग नहीं कर सकते हैंआपके फॉर्म से डेटा एमवीसी नियंत्रक के लिए। एक अलग फॉर्म ऑब्जेक्ट बनाने का प्रयास करें जो फ़ॉर्म डेटा से मेल खाता है और डेटाबेस में बने रहने वाली इकाइयों को अनुवाद करने के लिए एक सेवा विधि लिखता है।


जवाब के लिए 0 № 2

मुझे एक और मंच से मदद के साथ मिला हैसबसे सुरुचिपूर्ण समाधान! कनवर्टर के बजाए, हम एक फॉर्मेटर का उपयोग करते हैं जो specfiec ऑब्जेक्ट टाइप से स्ट्रिंग में बदल सकता है और इसके विपरीत। फॉर्मेटर वसंत में पंजीकृत है और स्वचालित रूप से थाइमेलीफ से बुलाया जाता है और आईडी फ़ील्ड को केवल आईडी मान सेट के साथ एक गतिविधि श्रेणी उदाहरण में परिवर्तित करता है। इसलिए हम डेटाबेस से वास्तविक उदाहरण नहीं देखते हैं क्योंकि हमें यहां विवरण की आवश्यकता नहीं है, क्योंकि हबर ने आईडी को क्वेरी बनाने के लिए पर्याप्त खाया है।

मेरा फॉर्मेटर इस तरह दिखता है:

public class ActivityCategoryFormatter implements Formatter<ActivityCategory> {

@Override
public String print(ActivityCategory ac, Locale locale) {
// TODO Auto-generated method stub
return Integer.toString(ac.getId());
}

@Override
public ActivityCategory parse(final String text, Locale locale) throws ParseException {
// TODO Auto-generated method stub
int id = Integer.parseInt(text);
ActivityCategory ac = new ActivityCategory(id);

return ac;
}
}

और स्प्रिंग में पंजीकृत है (अन्य लुकअप फ़ील्ड के लिए ActivityRegionFormatter के साथ) द्वारा:

@Override
public void addFormatters(FormatterRegistry registry) {
//registry.addConverter(new LookupConverter());
registry.addFormatter(new ActivityCategoryFormatter());
registry.addFormatter(new ActivityRegionFormatter());
}

और अब यह उम्मीद के रूप में काम करता है!

एकमात्र शेष मुद्दा यह है कि हमारे पास कुछ हैकोड डुप्लिकेशंस क्योंकि दो फॉर्मेटर वर्ग लगभग समान हैं, वे केवल जेनेरिक वर्ग में भिन्न होते हैं। मैंने एक सामान्य इंटरफ़ेस लुकअप एंटीटी का उपयोग करके इसे हल करने का प्रयास किया जो दो लुकअप इकाई वर्गों (गतिविधि श्रेणी और क्षेत्र श्रेणी) द्वारा कार्यान्वित किया गया है और फ़ॉर्मेटर को परिभाषित करने के लिए इस सामान्य इंटरफ़ेस का उपयोग करता है लेकिन दुर्भाग्य से यह काम नहीं करता है ...