2013-05-10 35 views
6

Có một ứng dụng web Java MV mùa xuân Java và đang thực hiện yêu cầu đăng jquery ajax. Bộ điều khiển của tôi được thiết lập để nhận và gửi dữ liệu json. Mọi thứ hoạt động, chuỗi JSON được định dạng tốt và Bộ điều khiển có thể tạo và điền một đối tượng Command và điền nó với nội dung của dữ liệu yêu cầu JSON. Tuy nhiên, tôi đang cập nhật dữ liệu cho đối tượng Liên hệ và phần tử biểu mẫu JSP của tôi chỉ chứa một tập con của tất cả dữ liệu cần thiết cho bản cập nhật DB. Trong yêu cầu GET ban đầu của tôi cho trang JSP với biểu mẫu tôi lấy tất cả các dữ liệu cần thiết từ DB, điền một đối tượng Contact Command, và sau đó liên kết đối tượng lệnh đó với Mô hình.Spring 3 AJAX POST yêu cầu với @RequestBody và @ModelAttribute và @SessionAttribute được sử dụng cùng nhau?

Nếu tôi đang gửi biểu mẫu gửi POST bình thường, tôi tin rằng chỉ cần khai báo đối tượng lệnh của tôi là @SessionAttribute và tham chiếu đối tượng Command đó bằng cách sử dụng @ModelAttribute trong phương thức POST onSubmit() của tôi là đủ. Spring sẽ lấy đối tượng lệnh đã được điền từ phiên của tôi và sau đó liên kết (ghi đè lên) các giá trị đó đã thay đổi do yêu cầu POST. Sau đó, đối tượng lệnh được cập nhật này có thể được sử dụng làm tham số cho bản cập nhật DB.

Tuy nhiên, tôi đang sử dụng Spring 3 và tận dụng loại tham số @RequestBody. Tôi không thể có được mùa xuân để cả hai cho tôi đối tượng phiên và tự động ràng buộc các giá trị mới từ yêu cầu. Nó cung cấp cho tôi chỉ đối tượng lệnh phiên cũ (không áp dụng các thay đổi) hoặc một Đối tượng Lệnh mới chỉ với các giá trị từ yêu cầu POST.

Đây là một mã số ít - không hoạt động:

@SessionAttributes("contactCommand") 
@Controller 
public class ContactController { 


    @RequestMapping(value = "/editContact", method=RequestMethod.GET) 
public String init(ModelMap model, Locale locale, HttpServletRequest request, HttpServletResponse response) throws GeneralException { 
    final ContactCommand cmd = new ContactCommand(); 
    // populate with data from DB etc 
    model.addAttribute("contactCommand", cmd); 
    // etc 
} 

@RequestMapping(value="/editContact",method=RequestMethod.POST, consumes = "application/json", produces = "application/json") 
public @ResponseBody Map<String, ? extends Object> editContactInfo(@RequestBody @ModelAttribute("contactCommand") ContactCommand cmd, HttpServletRequest request, HttpServletResponse response) throws GeneralException { 

// do business logic with command object here 

} 

bất cứ ai có thể vui lòng cho tôi biết cách "tiêu chuẩn" hay "dễ nhất" để sử dụng @RequestBody với dữ liệu yêu cầu JSON là gì và làm cho điều đó ràng buộc đối với một đối tượng Command/popModelAttribute hiện có để đối tượng Command được cấu thành đầy đủ với cả dữ liệu cũ và mới (giống như cách nó dễ dàng đạt được bằng cách sử dụng một trình gửi POST đầy đủ).

Câu hỏi liên quan là có gì sai với mã ở trên? Có thể @SessionAttribute và @RequestBody với nội dung JSON được sử dụng cùng nhau không? Nếu có, vui lòng giải thích như thế nào! Cảm ơn bạn rất nhiều cho bất kỳ đầu vào.

Công việc của tôi là để Spring tạo đối tượng Command mới và tự động điền dữ liệu biểu mẫu. Sau đó thực hiện một cuộc gọi riêng biệt/truy xuất thủ công từ phiên đối tượng lệnh cũ, cuối cùng sao chép thủ công tất cả các thuộc tính không có trong biểu mẫu gửi vào đối tượng lệnh mới. Bây giờ tôi có tất cả các dữ liệu cần thiết cùng nhau trong một đối tượng lệnh để áp dụng bản cập nhật SQL của tôi với. Phải có một cách dễ dàng hơn ....;)

UPDATE:

Tìm thấy bài SOF này ngày hôm nay trong khi tiếp tục nghiên cứu vấn đề này:

Spring Partial Update Object Data Binding

Có vẻ không có giải pháp SPRING biết ra khỏi hộp nhưng rất nhiều nhu cầu để biết cách tốt nhất để xử lý nó. Trong trường hợp của tôi, có, tôi đang sử dụng các đối tượng miền lồng nhau do đó giải pháp được cung cấp trong bài đăng là không tốt. Có ai có ý tưởng nào khác? Để rõ ràng, tôi muốn POST dữ liệu định dạng JSON cho Bộ điều khiển (không chỉ đơn giản là dữ liệu bài đăng dạng http).

Ok, tôi đã mở một yêu cầu Xuân Nguồn JIRA cho thế này, có lẽ nó là một cải tiến rất cần thiết:

https://jira.springsource.org/browse/SPR-10552

Hoặc nếu không, nó là một trường hợp tận dụng các khả năng chuyển đổi Jackson trong những cách thông minh có vẻ như rất nhiều hệ thống ống nước.

Trả lời

0

Tại sao bạn muốn chú thích ModelAttribute với @RequestBody, Chỉ cần có @SessionAttribute và tham chiếu đối tượng Command bằng cách sử dụng @ModelAttribute cũng đủ trong trường hợp JSON.

động cơ của bạn đằng sau sử dụng @RequestBody

là gì

Xem http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html

http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/RequestBody.html

+0

Cảm ơn bạn đã trả lời. Nghĩ rằng để tận dụng các json tự động để chuyển đổi đối tượng được cung cấp bởi Jackson trên classpath nó đã được thực hành tiêu chuẩn để sử dụng RequestBody. Bạn có thể chỉ cho tôi bất kỳ tài liệu nào mô tả ModelAttribute cũng đủ để xử lý JSON không? Tôi đọc sau đây trên một bài SOF: "ModelAttribute được ràng buộc từ các thông số bài mẫu và RequestBody vượt qua cơ thể thẳng đến bộ chuyển đổi Json": http://stackoverflow.com/questions/13229584/requestbody-or-modelattribute-with-springrest -web-services – arcseldon

1

Đây không phải là một câu trả lời hoàn chỉnh, nhưng tôi hy vọng nó sẽ chỉ cho bạn đi đúng hướng.

Sau đây là lớp mà chúng tôi sử dụng để liên kết sâu từ JSON với đối tượng hiện có bằng cách sử dụng Jackson. Này được chuyển thể từ một báo cáo lỗi cho Jackson ở đây: https://jira.springsource.org/browse/SPR-10552

public class JsonBinder 
{ 
    private ObjectMapper objectMapper; 

    public JsonBinder(ObjectMapper objectMapper) 
    { 
     super(); 
     this.objectMapper = checkNotNull(objectMapper); 
    } 

    public void bind(Object objToBindInto, InputStream jsonStream) throws JsonProcessingException, IOException 
    { 
     JsonNode root = objectMapper.readTree(checkNotNull(jsonStream)); 
     applyRecursively(checkNotNull(objToBindInto), root); 
    } 

    private void applyRecursively(Object objToBindInto, JsonNode node) throws JsonProcessingException, IOException 
    { 
     PropertyAccessor propAccessor = null; 

     for(Iterator<Entry<String, JsonNode>> i = node.fields(); i.hasNext();) 
     { 
      Entry<String, JsonNode> fieldEntry = i.next(); 
      JsonNode child = fieldEntry.getValue(); 
      if(child.isArray()) 
      { 
       // We ignore arrays so they get instantiated fresh every time 
       // root.remove(fieldEntry.getKey()); 
      } 
      else 
      { 
       if(child.isObject()) 
       { 
        if(propAccessor == null) 
        { 
         propAccessor = PropertyAccessorFactory.forDirectFieldAccess(objToBindInto); 
        } 
        Object o2 = propAccessor.getPropertyValue(fieldEntry.getKey()); 
        if(o2 != null) 
        { 

         // Only remove the JsonNode if the object already exists 
         // Otherwise it will be instantiated when the parent gets 
         // deserialized 
         i.remove(); 
         applyRecursively(o2, child); 
        } 
       } 
      } 
     } 
     ObjectReader jsonReader = objectMapper.readerForUpdating(objToBindInto); 
     jsonReader.readValue(node); 
    } 
} 

Chúng tôi sử dụng này cùng với một một thực hiện HandlerMethodArgumentResolver Spring.

Chúng tôi không sử dụng nhiều khung MVC của Spring. Chúng tôi chỉ đang xây dựng một chương trình phụ trợ API JSON bằng cách sử dụng rất nhiều phần khác nhau của Spring. Đó là một số lượng khá tốt của hệ thống ống nước để có được tất cả làm việc, nhưng bây giờ bộ điều khiển của chúng tôi rất đơn giản.

Rất tiếc, tôi không thể hiển thị tất cả mã của chúng tôi, dù sao cũng khá dài. Tôi hy vọng điều này giải quyết ít nhất một phần của vấn đề.

Các vấn đề liên quan