2012-06-27 37 views
6

Trong một ứng dụng web sử dụng JPA Spring Data với Hibernate, chúng tôi sử dụng chức năng web pagination để cung cấp khả năng phân trang và sắp xếp trong các danh sách các thực thể khác nhau.Dữ liệu Spring JPA Các tham số page.sort không hợp lệ

@Controller 
public class MyEntityController { 
    @RequestMapping(method = RequestMethod.GET) 
    public ModelAndView list(Pageable pageable) { ... } 
} 

@Configuration 
public class MyWebMvcConfig extends WebMvcConfigurationSupport { 
    @Override 
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { 
     super.addArgumentResolvers(argumentResolvers); 
     argumentResolvers.add(new PageableArgumentResolver()); 
    } 
} 

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, String> { 
    Page<MyEntity> findByPropertyX(String propertyX, Pageable pagable); 
} 

Điều này cho phép tính thực thể được xác định trong html rendered như loại đặc biệt request parameters, trong đó giá trị page.sort thực sự phù hợp với một tài sản trong thực thể mà trên đó để sắp xếp.

<table> 
    <thead> 
     <tr> 
      <th><a href="?page.sort=propertyX&amp;page.sort.dir=asc">Property X</a></th> 
      <th><a href="?page.sort=propertyY&amp;page.sort.dir=asc">Property Y</a></th> 
     </tr> 
    </thead> 
    <tbody>...</tbody> 
</table> 

này tạo ra một URL kết quả như:

http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc 

Vấn đề là người dùng có thể thay đổi URL để sử dụng không hợp lệ page.sort tài sản mà một trong hai tài liệu tham khảo không tồn tại tên cột/tài sản, hoặc tệ hơn, sử dụng các ký tự truy vấn JPA không hợp lệ dẫn đến cú pháp không hợp lệ.

Ví dụ, nếu URL được sửa đổi để sắp xếp vào "noSuchProperty":

http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc 

Nhưng tài sản này không tồn tại, ngoại trừ sau đây sẽ được ném:

java.lang.IllegalArgumentException: No property noSuchProperty found for type class com.my.company.MyEntity 
    at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76) 
    . . . 
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:86) 
    . . . 
    at $Proxy68.findByPropertyX(Unknown Source) 
    at com.my.company.MyEntityRepository.findByPropertyX(MyEntityRepository.java:17 

Tương tự như vậy, nếu URL được sửa đổi thành ký tự cú pháp truy vấn không hợp lệ, chẳng hạn như "" ":

http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc 

hoặc sẽ xảy ra:

java.lang.StackOverflowError 
    java.util.regex.Pattern$GroupTail.match(Pattern.java:4227) 
    . . . 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 

(Ngoài ra còn có một hương vị thứ ba trường hợp ngoại lệ mà kết quả trong một org.hibernate.QueryException khi @Query được định nghĩa một cách rõ ràng về phương pháp Repository.)

mùa xuân dữ liệu JPA tóm tắt đi các chi tiết của phân loại, phân trang và xử lý các thông số này; tuy nhiên, nó dường như không xử lý các kịch bản này một cách duyên dáng (tức là khi một tham số sắp xếp không hợp lệ được chỉ định).

Chúng tôi có thể thêm vào một số logic tùy chỉnh bổ sung để xác thực rằng thuộc tính sắp xếp thực sự tồn tại trên thực thể; tuy nhiên, tôi tự hỏi liệu có cách tiếp cận tập trung rõ ràng hơn để làm điều này sao cho chúng ta không bị mất các lợi ích và sự đơn giản của trừu tượng JPA dữ liệu Spring. Chúng tôi sử dụng khả năng sắp xếp này trong ứng dụng của chúng tôi với nhiều thực thể khác nhau, vì vậy, lý tưởng, chúng tôi muốn có thêm một cách tiếp cận chung, thay vì phải xác định rõ ràng hoặc kiểm tra thuộc tính sắp xếp cho mọi trang thực thể được yêu cầu.

Cụ thể, chúng tôi thực sự mở rộng PageableArgumentResolver để chấp nhận giá trị mặc định được sắp xếp chú thích được cung cấp trong bộ điều khiển của chúng tôi (không minh họa trong các ví dụ mã đơn giản), vì vậy chúng tôi muốn dự phòng theo thứ tự sắp xếp mặc định này hoặc chỉ là thứ tự sắp xếp mặc định cho thực thể, thay vì ném một ngoại lệ.

Một số ý tưởng và nỗ lực .. Tôi có thể sử dụng một QueryCreationListener để chặn tạo truy vấn và nhận tham số sắp xếp; tuy nhiên, tôi thực sự không thể sửa đổi truy vấn tại thời điểm đó. Hoặc, tôi có thể mở rộng và sử dụng một tùy chỉnh PageableArgumentResolver (chúng tôi đã làm điều này) để lấy các tham số sắp xếp; tuy nhiên, tôi không có quyền truy cập vào thực thể tại thời điểm đó, cũng như không thể xác định xem thực thể có thuộc tính có tên đó hay không.Chúng tôi có thể khai báo các thuộc tính được hỗ trợ một cách rõ ràng; tuy nhiên, một lần nữa, điều này đánh bại ý tưởng tập trung và tự động xử lý kịch bản này mà không yêu cầu kiến ​​thức cụ thể hoặc được khai báo của các thực thể.

Có loại trình chặn chặn hoặc cấu trúc tương tự nào khác mà tôi có thể sử dụng để xác thực tập trung các thông số sắp xếp trang và sửa đổi nếu cần thiết trước khi gọi truy vấn không? Hoặc là có bất kỳ loại cấu hình hoặc cách mà Spring có thể tự động xử lý kịch bản này sao cho nó xử lý các tham số sắp xếp không hợp lệ một cách duyên dáng hơn?

Trả lời

3

Tôi đã xem mã và tôi nghĩ rằng một số dấu vết ngăn xếp sẽ hữu ích. Nhưng từ những gì tôi có thể thấy, tôi nghĩ có hai nơi bạn có thể muốn giải quyết nếu bạn có tâm trạng viết lại một số mã Spring.

Có hai trường hợp ở đây, trong trường hợp đầu tiên bạn đang chuyển trường sắp xếp không tồn tại trong đối tượng/bảng. Những gì bạn thực sự muốn là thông số xấu đó sẽ bị bỏ qua một cách thầm lặng mọi lúc, không chỉ khi đi qua số 1 PageableArgumentResolver] 1. Tôi nghĩ rằng nó nên là một lựa chọn trên AbstractQueryCreator (và do đó, JpaQueryCreator) để bỏ qua các thông số xấu trên một sắp xếp.

Phần thứ hai cần được giải quyết có thể là PageableArgumentResolver. Nếu bạn truyền chuỗi rỗng hoặc thứ gì đó không có ý nghĩa như %20 thì nó sẽ bỏ qua thông số đó và không gửi thông qua số PageRequest.

Hacking và chúc may mắn. Đọc bài đăng của bạn đã khiến tôi nhận ra rằng trang web của tôi dễ bị tổn thương về cùng một vấn đề và tôi thực sự không có giải pháp tốt.

1

Tôi nghĩ cải thiện PageableArgumentResolver để xử lý các kịch bản đó một cách duyên dáng. Nó có thể cố gắng để tạo ra một ví dụ PropertyPath từ String được giao dưới dạng Sort và do đó hãy đảm bảo nó là hợp lệ. Tôi là một chút rách trên cho dù nó có ý nghĩa để chỉ cần bỏ mặc định String theo mặc định, mà sẽ trả lại kết quả không được sắp xếp ở tất cả. Đây có lẽ là trải nghiệm liền mạch nhất nhưng cũng có thể dẫn đến những nỗ lực tẻ nhạt để tìm hiểu lý do tại sao kết quả không được sắp xếp.

Tuy nhiên, nó. Sẽ được mát mẻ nếu bạn có thể nâng cao một vé JIRA cho rằng chống lại Spring Data Commons và chỉ liên kết vé này ở đây. Vui lòng mở yêu cầu kéo trong trường hợp bạn đã tìm ra một thực thi khả thi. Cảm ơn vì đã mang cái này vào bàn rồi!

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