یکی دیگر از روش های کوئری Search / Filter در REST Api استفاده از Spring Data QueryDSL Web Support است که در این بخش به آن میپردازیم
ابتدا کتابخانه های مورد نیاز را به پروژه اضافه میکنیم :
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-commons</artifactId> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-apt</artifactId> <version>${querydsl.version}</version> </dependency> <dependency> <groupId>com.mysema.querydsl</groupId> <artifactId>querydsl-jpa</artifactId> <version>${querydsl.version}</version> </dependency> ...
* اگر از کتابخانه Spring-Data-Commons ورژن 1.11 به بالا استفاده میکنیم نیاز نیست که کتابخانه QueryDSL web support را جداگانه اضافه کنیم
مرحله بعد Repository را میسازیم :
public interface UserRepository extends JpaRepository<User, Long>, QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> { @Override default public void customize(QuerydslBindings bindings, QUser root) { bindings.bind(String.class).first( (StringPath path, String value) -> path.containsIgnoreCase(value)); bindings.excluding(root.email); } }
دقت کنید که در کد بالا متد customize از کلای QuerydslBinderCustomizer را Override کردیم تا bind کنند پیش فرض را ایجاد کنیم و مقادیر از نوع String در Binder سفارشی بصورت IgnoreCase تعریف کردیم که بزرگ و کوچک بودن رشته ها در عملیات بی تاثیر باشند
سپس email کاربر را از bind خارج کردیم
ساخت User Controller :
@RequestMapping(method = RequestMethod.GET, value = "/users") @ResponseBody public Iterable<User> findAllByWebQuerydsl( @QuerydslPredicate(root = User.class) Predicate predicate) { return userRepository.findAll(predicate); }
قسمت جالب کد بالا ساخته شدن اتوماتیک Predicate توسط QuerydslPredicate@ است
ارسال درخواست توسط کلاینت :
http://localhost:8080/users?firstName=john
ساختار پاسخ دریافتی کلاینت :
[ { "id":1, "firstName":"john", "lastName":"doe", "email":"john@test.com", "age":11 } ]
تست :
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) @WebAppConfiguration public class UserLiveTest { private ObjectMapper mapper = new ObjectMapper(); private User userJohn = new User("john", "doe", "john@test.com"); private User userTom = new User("tom", "doe", "tom@test.com"); private static boolean setupDataCreated = false; @Before public void setupData() throws JsonProcessingException { if (!setupDataCreated) { givenAuth().contentType(MediaType.APPLICATION_JSON_VALUE) .body(mapper.writeValueAsString(userJohn)) .post("http://localhost:8080/users"); givenAuth().contentType(MediaType.APPLICATION_JSON_VALUE) .body(mapper.writeValueAsString(userTom)) .post("http://localhost:8080/users"); setupDataCreated = true; } } private RequestSpecification givenAuth() { return RestAssured.given().auth().preemptive().basic("user1", "user1Pass"); } }
تست کوئری دریافت کلیه User ها :
@Test public void whenGettingListOfUsers_thenCorrect() { Response response = givenAuth().get("http://localhost:8080/users"); User[] result = response.as(User[].class); assertEquals(result.length, 2); }
تست کوئری پیدا کردن User بر اساس firstName :
@Test public void givenFirstName_whenGettingListOfUsers_thenCorrect() { Response response = givenAuth().get("http://localhost:8080/users?firstName=john"); User[] result = response.as(User[].class); assertEquals(result.length, 1); assertEquals(result[0].getEmail(), userJohn.getEmail()); }
تست کوئری پیدا کردن User بر اساس قسمتی از lastName :
@Test public void givenPartialLastName_whenGettingListOfUsers_thenCorrect() { Response response = givenAuth().get("http://localhost:8080/users?lastName=do"); User[] result = response.as(User[].class); assertEquals(result.length, 2); }
تست کوئری بر اساس ایمیل User :
@Test public void givenEmail_whenGettingListOfUsers_thenIgnored() { Response response = givenAuth().get("http://localhost:8080/users?email=john"); User[] result = response.as(User[].class); assertEquals(result.length, 2); }
دقت کنید که ما قبلا ایمیل را از Predicate خارج کرده بودیم پس این کوئری نادیده گرفته میشود و جوابی در بر نخواهد داشت