18

मैं कुछ ऐसा करने की कोशिश कर रहा हूं जो मुझे लगता है कि वास्तव में सरल होना चाहिए। मेरे पास Question ऑब्जेक्ट है, वसंत-बूट, वसंत-डेटा-आराम और वसंत-नफरत के साथ सेटअप। सभी मूल बातें ठीक काम करती हैं। मैं एक कस्टम नियंत्रक जोड़ना चाहता हूं जो List<Question> को उसी प्रारूप में देता है जो मेरे Repository के /questions यूआरएल को प्राप्त करता है, ताकि दोनों के बीच प्रतिक्रिया संगत हो।क्या मैं एक कस्टम नियंत्रक स्प्रिंग-डेटा-रेस्ट/स्प्रिंग-हेटोएस जेनरेटेड क्लास के स्वरूपण को दर्पण कर सकता हूं?

@Controller 
public class QuestionListController { 

    @Autowired private QuestionRepository questionRepository; 

    @Autowired private PagedResourcesAssembler<Question> pagedResourcesAssembler; 

    @Autowired private QuestionResourceAssembler questionResourceAssembler; 

    @RequestMapping(
      value = "/api/questions/filter", method = RequestMethod.GET, 
      consumes = MediaType.APPLICATION_JSON_VALUE, 
      produces = MediaType.APPLICATION_JSON_VALUE) 
    public @ResponseBody PagedResources<QuestionResource> filter(
      @RequestParam(value = "filter", required = false) String filter, 
      Pageable p) { 

     // Using queryDSL here to get a paged list of Questions 
     Page<Question> page = 
      questionRepository.findAll(
       QuestionPredicate.findWithFilter(filter), p); 

     // Option 1 - default resource assembler 
     return pagedResourcesAssembler.toResource(page); 

     // Option 2 - custom resource assembler 
     return pagedResourcesAssembler.toResource(page, questionResourceAssembler); 
    } 

} 

विकल्प 1::

यहाँ मेरी नियंत्रक है प्रदान की SimplePagedResourceAssembler

इस विकल्प के साथ समस्या यह आवश्यक _links में से कोई भी गाया जाता है पर भरोसा। यदि इसके लिए कोई फिक्स था, तो यह सबसे आसान समाधान होगा।

विकल्प 2: लागू मेरी खुला संसाधन कोडांतरक

इस विकल्प के साथ समस्या यह है कि Spring-Hateoas documentation के अनुसार QuestionResourceAssembler को लागू करने के लिए एक रास्ता नीचे की ओर जाता है, जहां QuestionResourceQuestion की एक लगभग डुप्लिकेट होने समाप्त होता है, और उसके बाद है असेंबलर को दो ऑब्जेक्ट्स के बीच डेटा मैन्युअल रूप से कॉपी करने की आवश्यकता होती है, और मुझे हाथ से सभी प्रासंगिक _links बनाने की आवश्यकता है। यह बहुत बर्बाद प्रयास की तरह लगता है।

क्या करना है?

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

उत्तर

4

मेरा मानना ​​है कि मैंने इस समस्या को काफी सरल तरीके से हल किया है, हालांकि यह बेहतर दस्तावेज हो सकता था।

SimplePagedResourceAssembler के कार्यान्वयन को पढ़ने के बाद मुझे एहसास हुआ कि एक हाइब्रिड समाधान काम कर सकता है। प्रदत्त Resource<?> वर्ग इकाइयों को सही ढंग से प्रस्तुत करता है, लेकिन इसमें लिंक शामिल नहीं हैं, इसलिए आपको बस इतना करना है कि उन्हें जोड़ना है।

@Component 
public class QuestionResourceAssembler implements ResourceAssembler<Question, Resource<Question>> { 

    @Autowired EntityLinks entityLinks; 

    @Override 
    public Resource<Question> toResource(Question question) { 
     Resource<Question> resource = new Resource<Question>(question); 

     final LinkBuilder lb = 
      entityLinks.linkForSingleResource(Question.class, question.getId()); 

     resource.add(lb.withSelfRel()); 
     resource.add(lb.slash("answers").withRel("answers")); 
     // other links 

     return resource; 
    } 
} 

एक बार यह हो, मेरे नियंत्रक में मैं ऊपर विकल्प 2 इस्तेमाल किया :

मेरे QuestionResourceAssembler कार्यान्वयन इस तरह दिखता है

return pagedResourcesAssembler.toResource(page, questionResourceAssembler); 

यह अच्छी तरह से काम करता है, और बहुत अधिक नहीं है कोड। एकमात्र परेशानी है कि आपको आवश्यक प्रत्येक संदर्भ के लिए मैन्युअल रूप से लिंक जोड़ने की आवश्यकता है।

+0

ज़रूर स्प्रिंग की तरह लगता है यह एक बहुत आसान बना दिया है हो सकता है: अब आप कि एक PersistentEntityResourceAssembler

अपने @RepositoryRestController अंदर के साथ क्या कर सकते हैं। क्या यह तथ्य नहीं है कि आपको अपने स्वयं के लिंक जोड़ना है, फिर भी संभावित रूप से अलग-अलग एपीआई (जैसे आपने कहीं और बताया) का नेतृत्व किया है? और क्या आपको हर जगह पेजों का उपयोग करना है? जब मैं सिर्फ एक सूची <संसाधन > वापस करने का प्रयास करता हूं> मुझे द्वि-दिशात्मक हाइबरनेट मैपिंग के कारण रिकर्सन मिलता है। इसलिए मुझे या तो @ जेसन इग्नोर जोड़ना है या इसके बजाय एक पेजेड रिसोर्सएस्सेबलर का उपयोग करना है। – gyoder

+0

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

+1

2016 में, नियंत्रक/कस्टम भंडार का उपयोग करते समय वसंत-डेटा-आराम एस्क्यू व्यवहार प्राप्त करने के लिए यह अभी भी सबसे अच्छा/एकमात्र तरीका है? यह काफी परेशान है। – Casey

19

मुझे स्प्रिंग डेटा रेस्ट के व्यवहार को पूरी तरह से अनुकरण करने का एक तरीका मिला है। यह चाल PagedResourcesAssembler के संयोजन और PersistentEntityResourceAssembler का एक तर्क-इंजेक्शन उदाहरण का उपयोग करने में निहित है। बस अपने नियंत्रक को परिभाषित इस प्रकार है ...

@RepositoryRestController 
@RequestMapping("...") 
public class ThingController { 

    @Autowired 
    private PagedResourcesAssembler pagedResourcesAssembler; 

    @SuppressWarnings("unchecked") // optional - ignores warning on return statement below... 
    @RequestMapping(value = "...", method = RequestMethod.GET) 
    @ResponseBody 
    public PagedResources<PersistentEntityResource> customMethod(
      ..., 
      Pageable pageable, 
      // this gets automatically injected by Spring... 
      PersistentEntityResourceAssembler resourceAssembler) { 

     Page<MyEntity> page = ...; 
     ... 
     return pagedResourcesAssembler.toResource(page, resourceAssembler); 
    } 
} 

यह PersistentEntityResourceAssemblerArgumentResolver के अस्तित्व है, जो वसंत आप के लिए PersistentEntityResourceAssembler सुई का उपयोग करता है करने के लिए धन्यवाद काम करता है।नतीजा यह है कि आप अपनी रिपोजिटरी क्वेरी विधियों में से एक से क्या अपेक्षा करेंगे!

+0

अच्छा, मैं इसे आज़मा दूंगा। – JBCP

+0

यह भी देखें http://stackoverflow.com/questions/31758862/enable-hal-serialization-in-spring-boot-for-custom-controller-method#31782016। –

+0

छोटे जोड़े: आप अनचेक चेतावनी को रोक सकते हैं, जब आपकी विधि सीधे 'PagedResource ' लौटाती है, यह वही है (paged) resourceAssembler.toResource – Robert

3

इस पुराने सवाल पर अपडेट किया गया जवाब:

@RequestMapping(value = "somePath", method = POST) 
public @ResponseBody PersistentEntityResource postEntity(@RequestBody Resource<EntityModel> newEntityResource, PersistentEntityResourceAssembler resourceAssembler) 
{ 
    EntityModel newEntity = newEntityResource.getContent(); 
    // ... do something additional with new Entity if you want here ... 
    EntityModel savedEntity = entityRepo.save(newEntity); 

    return resourceAssembler.toResource(savedEntity); // this will create the complete HATEOAS response 
} 
+0

क्या नियंत्रक विधि तर्कों में किसी मौजूदा संसाधन के लिंक को स्वीकार करना संभव है और इसे स्वचालित रूप से किसी इकाई में परिवर्तित करना संभव है? – aycanadal

+0

हां, यदि आपकी इकाई किसी अन्य "बच्चे" इकाई से जुड़ी है, तो आप उस लिंक को बनाने के लिए बस एक यूआरआई पोस्ट कर सकते हैं। उदाहरण के लिए HTTP पोस्ट/पथ/से/अभिभावक/इकाई पेलोड ecample '{someAttr:" उदाहरण मान ", linkToChildEntity:"/path/to/child/entity/ "} उम्मीद है कि इससे मदद मिलती है। अधिक जानकारी के लिए [यह स्टैक ओवरफ्लो प्रश्न] देखें (http://stackoverflow.com/questions/25311978/posting-a-onetomany-sub-resource-association-in-spring-data-rest?rq=1) – Robert

+0

कस्टम नियंत्रक मेरा मतलब है। स्प्रिंग डेटा बाकी करता है, मुझे पता है। सवाल यह है कि मैं एक नियंत्रक कैसे लिख सकता हूं जो ऐसा कर सकता है? – aycanadal

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

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