2016-07-17 20 views
6

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

, निम्नलिखित इकाई पर विचार करें एक उदाहरण के रूप:

@Entity 
private class Person { 

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

    /* let's assume the following attributes may be null */ 
    private String firstName; 
    private String lastName; 

    /* getters and setters ... */ 
} 

मेरे व्यक्ति भंडार (स्प्रिंग डाटा):

@Repository 
public interface PersonRepository extends CrudRepository<Person, Long> { 
} 

डीटीओ मैं का उपयोग करें:

private class PersonDTO { 
    private String firstName; 
    private String lastName; 

    /* getters and setters ... */ 
} 

मेरे स्प्रिंग RestController :

@RestController 
@RequestMapping("/api/people") 
public class PersonController { 

    @Autowired 
    private PersonRepository people; 

    @Transactional 
    @RequestMapping(path = "/{personId}", method = RequestMethod.PUT) 
    public ResponseEntity<?> update(
      @PathVariable String personId, 
      @RequestBody PersonDTO dto) { 

     // get the entity by ID 
     Person p = people.findOne(personId); // we assume it exists 

     // update ONLY entity attributes that have been defined 
     if(/* dto.getFirstName is defined */) 
      p.setFirstName = dto.getFirstName; 

     if(/* dto.getLastName is defined */) 
      p.setLastName = dto.getLastName; 

     return ResponseEntity.ok(p); 
    } 
} 

लापता संपत्ति

{"firstName": "John"} 

अपेक्षित व्यवहार के साथ अनुरोध: अद्यतन firstName= "John" (छोड़ lastName नहीं बदला गया)।

अशक्त संपत्ति

{"firstName": "John", "lastName": null} 

अपेक्षित व्यवहार के साथ अनुरोध: अद्यतन firstName="John" और lastName=null निर्धारित किया है।

मैं इन दो मामलों के बीच अंतर नहीं कर सकते हैं, डीटीओ में lastName के बाद से हमेशा जैक्सन ने null को तैयार है।

नोट: मुझे पता है कि बाकी सर्वोत्तम प्रथाओं (RFC 6902) आंशिक अद्यतन के लिए के बजाय PATCH PUT उपयोग करने की अनुशंसा, लेकिन मेरी विशेष परिदृश्य में मैं PUT उपयोग करने के लिए की जरूरत है।

+0

संभावित डुप्लिकेट [@RequestBody कैसे एक शून्य मान से एक नहीं भेजे गए मूल्य अंतर करने के लिए?] (Https://stackoverflow.com/questions/40610604/requestbody-how-to-differentiate-an-unsent-value -from-a-null-value) – laffuste

उत्तर

1

दरअसल, अगर सत्यापन को अनदेखा करते हैं, तो आप इस तरह की अपनी समस्या का समाधान कर सकते हैं।

public class BusDto { 
     private Map<String, Object> changedAttrs = new HashMap<>(); 

     /* getter and setter */ 
    } 
  • पहले, अपने डीटीओ, BusDto की तरह के लिए एक सुपर वर्ग लिखें।
  • दूसरा, सुपर वर्ग का विस्तार करने के लिए अपने डीटीओ बदलने के लिए, और डीटीओ के सेट-प्रक्रिया में परिवर्तन, (जब विशेषता मान कोई बात नहीं अशक्त है changedAttrs को विशेषता नाम और मान डाल करने के लिए beacause वसंत सेट आह्वान होगा या शून्य नहीं)।
  • तीसरा, मानचित्र का भ्रमण।
1

मैंने एक ही समस्या को हल करने का प्रयास किया है। मुझे डीटीओ के रूप में JsonNode का उपयोग करना काफी आसान लगता है। इस तरह आप केवल जो सबमिट करते हैं उसे प्राप्त करते हैं।

आपको MergeService खुद को लिखना होगा जो वास्तविक कार्य करता है, बीनवापर के समान। मुझे एक मौजूदा ढांचा नहीं मिला है जो वास्तव में आवश्यकतानुसार कर सकता है। (यदि आप केवल जेसन अनुरोध का उपयोग करते हैं तो आप जैक्सन readForUpdate विधि का उपयोग करने में सक्षम हो सकते हैं।)

हम वास्तव में एक और नोड प्रकार का उपयोग करते हैं क्योंकि हमें "मानक फॉर्म सबमिशन" और अन्य सेवा कॉल से समान कार्यक्षमता की आवश्यकता होती है। इसके अतिरिक्त संशोधनों को EntityService नामक किसी चीज़ के अंदर लेनदेन के भीतर लागू किया जाना चाहिए।

यह MergeService दुर्भाग्य से, काफी जटिल हो जाएगा के रूप में आप और गुण, सूचियों, सेट को संभालने के लिए की आवश्यकता होगी अपने आप को नक्शे :)

मेरे लिए सबसे समस्याग्रस्त टुकड़ा एक सूची का एक तत्व के भीतर परिवर्तन के बीच अंतर करना था/सूचियों/सेटों के सेट और संशोधन या प्रतिस्थापन।

और यह भी मान्यता आसान नहीं होगा के रूप में आप एक और मॉडल के खिलाफ कुछ गुण (मेरे मामले में जेपीए संस्थाओं)

संपादित मान्य करने के लिए की जरूरत है - कुछ मानचित्रण कोड (छद्म कोड):

class SomeController { 
    @RequestMapping(value = { "/{id}" }, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) 
    @ResponseBody 
    public void save(
      @PathVariable("id") final Integer id, 
      @RequestBody final JsonNode modifications) { 
     modifierService.applyModifications(someEntityLoadedById, modifications); 
    } 
} 

class ModifierService { 

    public void applyModifications(Object updateObj, JsonNode node) 
      throws Exception { 

     BeanWrapperImpl bw = new BeanWrapperImpl(updateObj); 
     Iterator<String> fieldNames = node.fieldNames(); 

     while (fieldNames.hasNext()) { 
      String fieldName = fieldNames.next(); 
      Object valueToBeUpdated = node.get(fieldName); 
      Class<?> propertyType = bw.getPropertyType(fieldName); 
      if (propertyType == null) { 
       if (!ignoreUnkown) { 
        throw new IllegalArgumentException("Unkown field " + fieldName + " on type " + bw.getWrappedClass()); 
       } 
      } else if (Map.class.isAssignableFrom(propertyType)) { 
        handleMap(bw, fieldName, valueToBeUpdated, ModificationType.MODIFY, createdObjects); 
      } else if (Collection.class.isAssignableFrom(propertyType)) { 
        handleCollection(bw, fieldName, valueToBeUpdated, ModificationType.MODIFY, createdObjects); 
      } else { 
        handleObject(bw, fieldName, valueToBeUpdated, propertyType, createdObjects); 
      } 
     } 
    } 
} 
+0

आपका उत्तर दिलचस्प लगता है, लेकिन मुझे यह बहुत अच्छा नहीं मिला है। क्या आप इसे एक प्रासंगिक उदाहरण के साथ बढ़ा सकते हैं? –

+0

कौन सा हिस्सा, jsonnode requestmapping, विलय सेवा या सत्यापन? –

+0

यह स्पष्ट नहीं है कि नियंत्रक वर्ग में मेरी अद्यतन विधि के भीतर जेसन नोड का उपयोग कैसे करें। क्या मेरे डीटीओ को जेसन नोड से प्राप्त होना चाहिए? –

0

शायद बहुत एक जवाब के लिए देर हो चुकी है, लेकिन आप:

  • डिफ़ॉल्ट रूप से, नहीं सेट नहीं 'अशक्त' मूल्यों से करते हैं। क्वेरी पैराम्स के माध्यम से एक स्पष्ट सूची प्रदान करें जो आप अनसेट करना चाहते हैं। इस तरह से आप अभी भी जेएसओएन भेज सकते हैं जो आपकी इकाई से मेल खाता है और जब आपको आवश्यकता हो तो फ़ील्ड को अनसेट करने में लचीलापन है।

  • आपके उपयोग के मामले के आधार पर, कुछ एंडपॉइंट्स सभी शून्य मानों को अनसेट ऑपरेशन के रूप में स्पष्ट रूप से इलाज कर सकते हैं। पैचिंग के लिए थोड़ा सा खतरनाक है, लेकिन कुछ परिस्थितियों में एक विकल्प हो सकता है।

0

jackson's author recommends के रूप में बूलियन झंडे का उपयोग करें।

class PersonDTO { 
    private String firstName; 
    private boolean isFirstNameDirty; 

    public void setFirstName(String firstName){ 
     this.firstName = firstName; 
     this.isFirstNameDirty = true; 
    } 

    public void getFirstName() { 
     return firstName; 
    } 

    public boolean hasFirstName() { 
     return isFirstNameDirty; 
    } 
} 
की
संबंधित मुद्दे