我正在努力扩展这个baeldung教程https://www.baeldung.com/rest-api-search-language-spring-data-specifications
但是我希望规范是通用的,并且我希望允许客户端通过嵌入对象的值进行搜索。一切都适用于字符串和一些数字,但不适用于ID和其他更复杂的对象,如 Date
.
我的模型:(假设一个人只能养一只宠物)
@Entity
public Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
private String name;
private Date dateOfBirth
private Integer age;
private Pet pet;
// Getter & Setters etc
}
@Entity
public Pet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private ID id;
private String type;
private String name;
private Integer numOfLegs;
// Getter & Setters etc
}
人员存储库:
@Repository
public interface PersonRepository extends JpaRepository<Person, Integer>, JpaSpecificationExecutor<Person>{}
搜索条件,将保存键,运算符和值,我们可以搜索。
public class EntitySearchCriteria {
private String key;
private String operation;
private Object value;
public EntitySearchCriteria(final String key, final String operation, final Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
// Getters and Setters etc
我的泛型规范类(这里的操作实际上是构建要使用的 predicate )。这还允许客户机对联接表的值设置搜索条件。e、 g.“pet.name=松饼”
public abstract class AbstractEntitySpecification<T, ID extends Serializable> implements Specification<T> {
protected EntitySearchCriteria criteria;
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
if (criteria.getOperation().equalsIgnoreCase(">")) {
return criteriaBuilder.greaterThanOrEqualTo(root.<String>get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase("<")) {
return criteriaBuilder.lessThanOrEqualTo(root.<String>get(criteria.getKey()), criteria.getValue().toString());
} else if (criteria.getOperation().equalsIgnoreCase(":")) {
if (criteria.getKey().contains(".")) {
String[] joinCriteriaArray = criteria.getKey().split("\\.");
Class<?> joinedClass = root.get(joinCriteriaArray[0]).getClass();
Join<T, ?> joinedRelationship = root.join(joinCriteriaArray[0]);
return criteriaBuilder.equal(joinedRelationship.get(joinCriteriaArray[1]), criteria.getValue());
}
if (root.get(criteria.getKey()).getJavaType() == String.class) {
return criteriaBuilder.like(root.<String>get(criteria.getKey()), "%" + criteria.getValue() + "%");
} else {
return criteriaBuilder.equal(root.get(criteria.getKey()), criteria.getValue());
}
}
return null;
}
}
我希望允许这种查询的任何实体只需要有 AbstractEntitySpecification
```
public class PersonSpecification extends AbstractEntitySpecification<Person, Integer> {
public PersonSpecification (final EntitySearchCriteria entitySearchCriteria) {
this.criteria = entitySearchCriteria;
}
}
这些是我做的测试。对person的字符串或int属性(即person.name、person.age)的任何搜索都将起作用,但对dateofbirth的搜索将不起作用。任何对pet的属性(字符串)的搜索都可以使用join,但是对id(整数)的搜索都不行,不管我是将id作为int还是字符串传递。每次考试我都会把这种行为写进评语里。
public class PersonSpecificationMediumTest extends AbstractMediumTest {
@Autowired
private PersonRepository personRepository;
@Autowired
private PetRepository petRepository;
Person person1;
Person person2;
@Before
public void setUp() {
Pet muffins = new Pet(1, "cat", "muffins", 4);
Pet rex= new Pet(2, "dog", "rex", 4);
petRepository.saveAll(Arrays.asList(muffins , rex));
person1 = new Person();
person1.setName("David");
person1.setDateOfBirth(Date.parse("1979-03-01");
person1.setPet(muffins);
person1 = personRepository.saveAndFlush(person1);
person2 = new Person();
person2.setName("Mary");
person2.setDateOfBirth(Date.parse("1982-03-01");
person2.setPet(rex);
person2 = personRepository.saveAndFlush(person2);
}
@Test //Works
public void toPredicate_findByNameEquals_assertCorrectResult() {
PersonSpecification spec
= new PersonSpecification(new EntitySearchCriteria("name", ":", "David"));
List<Person> results = personRepository.findAll(spec);
Assert.assertEquals(person1, results.get(0));
}
@Test // Works
public void toPredicate_findByPetNameEquals_assertCorrectResult() {
PersonSpecification spec
= new PersonSpecification(new EntitySearchCriteria("client.name", ":", "Rex"));
List<Person> results = personRepository.findAll(spec);
Assert.assertEquals(person2, results.get(0));
}
@Test // Return empty list. Cannot find the pet by Id.
public void toPredicate_findByPetIdEquals_assertCorrectResult() {
PersonSpecification spec
= new PersonSpecification(new EntitySearchCriteria("pet.id", ":", 2));
List<Person> results = personRepository.findAll(spec);
Assert.assertEquals(person2, results.get(0));
}
@Test // org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2] did not match expected type [java.lang.Integer (n/a)];
public void toPredicate_findByPetIdAsStringEquals_assertCorrectResult() {
PersonSpecification spec
= new PersonSpecification(new EntitySearchCriteria("pet.id", ":", "2"));
List<Person> results = personRepository.findAll(spec);
Assert.assertEquals(person2, results.get(0));
}
@Test // Fails on org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2020-01-01] did not match expected type [java.util.Date (n/a)]
public void toPredicate_findByDateOfBirthBetween_assertCorrectResult() {
PersonSpecification spec1
= new PersonSpecification(new EntitySearchCriteria("dateOfBirth", "<", "1990-01-01"));
PersonSpecification spec2
= new PersonSpecification(new EntitySearchCriteria("dateOfBirth", ">", "1970-01-01"));
List<Person> results = personRepository.findAll(spec1.and(spec2));
Assert.assertTrue(results.size() == 2);
}
}
你知道为什么约会这么麻烦吗?我想用照片上的日期 `greaterThanOrEqualTo` 以及 `lessThanOrEqualTo` ,但传入criteria.getvalue(object)会产生编译错误,因此它会强制我使用对象的字符串表示形式。但显示的错误是 `org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2020-01-01] did not match expected type [java.util.Date (n/a)]` 这向我表明它不能将字符串与日期进行比较,这是有意义的,但是为什么要阻止我传递date对象呢?
另外,为什么在联接表中id是这样一个问题?为什么找不到 `id = 2` ,我会认为这是直截了当的,特别是因为我可以成功地通过宠物的腿数来搜索。它一定与id是可序列化的有关。
1条答案
按热度按时间6rqinv9w1#
查看javadoc
Date.parse
. 基本的部分已经与宣言一起:@已弃用
公共静态长解析(字符串s)
正如它明确指出的,它返回一个
long
价值观。得到一个Date
可以使用的对象SimpleDateFormat
继承的DateFormat.parse(String s)
,例如: