如何使用 MongoTemplate 的 class 属性过滤数据?
How to filter data using class attributes with MongoTemplate?
我是第一次使用 MongoTemplate。
使用 Postman,我正在点击 API 并将 JSON 作为 @RequestBody 传递以获取经过过滤的学生列表。
型号Class
Student.java
package bd.ac.seu.erp.criteriademo.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import javax.validation.constraints.NotNull;
@Data
@NoArgsConstructor
@EqualsAndHashCode
public class Student {
@Id
String studentId;
@NotNull
Name name;
String nationality;
}
Name.java
package bd.ac.seu.erp.criteriademo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Name {
private String firstName;
private String lastName;
}
控制器
StudentController.java
package bd.ac.seu.erp.criteriademo.Controller;
import bd.ac.seu.erp.criteriademo.Service.StudentService;
import bd.ac.seu.erp.criteriademo.model.Student;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
@CrossOrigin()
@RestController
public class StudentController {
StudentService studentService;
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
@PostMapping("student/filter")
public ResponseEntity<?> getFilteredList(@RequestBody HashMap<String, String> fieldValueMap) {
System.out.println("Something");
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("requestedBy", "Shamin Asfaq");
List<Student> studentList = studentService.applyFilter(fieldValueMap);
return new ResponseEntity<>(studentList, multiValueMap, HttpStatus.OK);
}
}
服务
StudentService.java
package bd.ac.seu.erp.criteriademo.Service;
import bd.ac.seu.erp.criteriademo.model.Student;
import com.mongodb.MongoClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class StudentService {
@Value("${spring.data.mongodb.database}")
String databaseName;
public List<Student> applyFilter(HashMap<String,String> fieldValueMap) {
MongoTemplate mongoTemplate = new MongoTemplate(new MongoClient("127.0.0.1"), databaseName);
Query query = new Query();
for(Map.Entry<String,String> keyValuePair: fieldValueMap.entrySet()) {
query.addCriteria(Criteria.where(keyValuePair.getKey()).is(keyValuePair.getValue()));
}
return mongoTemplate.find(query, Student.class);
}
}
当我通过邮递员点击 API 时,通常这是我作为@RequestBody 发送的内容:
{
"nationality":"Bangladeshi"
}
..它工作得很好。
当我尝试使用 "firstName" 或 "lastName" 属性过滤数据时,问题就开始了。
这是我尝试发送的内容:
{
"name": {
"firstName": "Shamin"
}
}
我从 Postman 那里得到的 return 是:
{
"timestamp": "2018-08-09T12:01:58.620+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 2, column: 10] (through reference chain: java.util.HashMap[\"name\"])",
"path": "/student/filter"
}
显然,我了解到后端正在将 "name" 视为 key,其余部分视为 value .
如何在此处使用 "firstName" 或 "lastName" 属性过滤数据?更通用的是,我如何使用 class 属性或另一个 Class 中的 Class 的属性来过滤数据?
您的地图未在其余控制器中正确反序列化。
而不是使用 HashMap。
尝试使用 Student class 作为请求正文或使用 com.fasterxml.jackson.databind.node.ObjectNode 之类的内容并读取值。
public ResponseEntity<?> getFilteredList(@RequestBody ObjectNode req)
或将 Json 更改为:
{
"name.firstname":"aaa"
}
根据您的需要,我认为您应该看看 QueryDsl,它非常好,您可以使用 GET 请求进行查询 student/filter?name.firstname=xxx,您有很好的示例 link
你只需要在StudentRepository中扩展QuerydslPredicateExecutor:
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends PagingAndSortingRepository<Student, String>, QuerydslPredicateExecutor<Student> {
}
然后使用谓词进行查询:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.function.Predicate;
@CrossOrigin()
@RestController
public class StudentController {
StudentRepository studentService;
public StudentController(StudentRepository studentService) {
this.studentService = studentService;
}
@GetMapping("student/filter")
public ResponseEntity<Page<Student>> getFilteredList(@QuerydslPredicate(root = Student.class) Predicate predicate, Pageable pageable) {
System.out.println("Something");
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("requestedBy", "Shamin Asfaq");
Page<Student> studentList = studentService.findAll(predicate, pageable);
return new ResponseEntity<>(studentList, multiValueMap, HttpStatus.OK);
}
}
您还需要将此构建插件添加到您的 pom.xml:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>${apt.version}</version>
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
<processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
<logOnlyOnError>true</logOnlyOnError>
</configuration>
</execution>
</executions>
</plugin>
我是第一次使用 MongoTemplate。 使用 Postman,我正在点击 API 并将 JSON 作为 @RequestBody 传递以获取经过过滤的学生列表。
型号Class
Student.java
package bd.ac.seu.erp.criteriademo.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import javax.validation.constraints.NotNull;
@Data
@NoArgsConstructor
@EqualsAndHashCode
public class Student {
@Id
String studentId;
@NotNull
Name name;
String nationality;
}
Name.java
package bd.ac.seu.erp.criteriademo.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Name {
private String firstName;
private String lastName;
}
控制器
StudentController.java
package bd.ac.seu.erp.criteriademo.Controller;
import bd.ac.seu.erp.criteriademo.Service.StudentService;
import bd.ac.seu.erp.criteriademo.model.Student;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
@CrossOrigin()
@RestController
public class StudentController {
StudentService studentService;
public StudentController(StudentService studentService) {
this.studentService = studentService;
}
@PostMapping("student/filter")
public ResponseEntity<?> getFilteredList(@RequestBody HashMap<String, String> fieldValueMap) {
System.out.println("Something");
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("requestedBy", "Shamin Asfaq");
List<Student> studentList = studentService.applyFilter(fieldValueMap);
return new ResponseEntity<>(studentList, multiValueMap, HttpStatus.OK);
}
}
服务
StudentService.java
package bd.ac.seu.erp.criteriademo.Service;
import bd.ac.seu.erp.criteriademo.model.Student;
import com.mongodb.MongoClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class StudentService {
@Value("${spring.data.mongodb.database}")
String databaseName;
public List<Student> applyFilter(HashMap<String,String> fieldValueMap) {
MongoTemplate mongoTemplate = new MongoTemplate(new MongoClient("127.0.0.1"), databaseName);
Query query = new Query();
for(Map.Entry<String,String> keyValuePair: fieldValueMap.entrySet()) {
query.addCriteria(Criteria.where(keyValuePair.getKey()).is(keyValuePair.getValue()));
}
return mongoTemplate.find(query, Student.class);
}
}
当我通过邮递员点击 API 时,通常这是我作为@RequestBody 发送的内容:
{
"nationality":"Bangladeshi"
}
..它工作得很好。 当我尝试使用 "firstName" 或 "lastName" 属性过滤数据时,问题就开始了。
这是我尝试发送的内容:
{
"name": {
"firstName": "Shamin"
}
}
我从 Postman 那里得到的 return 是:
{
"timestamp": "2018-08-09T12:01:58.620+0000",
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 2, column: 10] (through reference chain: java.util.HashMap[\"name\"])",
"path": "/student/filter"
}
显然,我了解到后端正在将 "name" 视为 key,其余部分视为 value .
如何在此处使用 "firstName" 或 "lastName" 属性过滤数据?更通用的是,我如何使用 class 属性或另一个 Class 中的 Class 的属性来过滤数据?
您的地图未在其余控制器中正确反序列化。 而不是使用 HashMap。
尝试使用 Student class 作为请求正文或使用 com.fasterxml.jackson.databind.node.ObjectNode 之类的内容并读取值。
public ResponseEntity<?> getFilteredList(@RequestBody ObjectNode req)
或将 Json 更改为:
{
"name.firstname":"aaa"
}
根据您的需要,我认为您应该看看 QueryDsl,它非常好,您可以使用 GET 请求进行查询 student/filter?name.firstname=xxx,您有很好的示例 link
你只需要在StudentRepository中扩展QuerydslPredicateExecutor:
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface StudentRepository extends PagingAndSortingRepository<Student, String>, QuerydslPredicateExecutor<Student> {
}
然后使用谓词进行查询:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.querydsl.binding.QuerydslPredicate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.function.Predicate;
@CrossOrigin()
@RestController
public class StudentController {
StudentRepository studentService;
public StudentController(StudentRepository studentService) {
this.studentService = studentService;
}
@GetMapping("student/filter")
public ResponseEntity<Page<Student>> getFilteredList(@QuerydslPredicate(root = Student.class) Predicate predicate, Pageable pageable) {
System.out.println("Something");
MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();
multiValueMap.add("requestedBy", "Shamin Asfaq");
Page<Student> studentList = studentService.findAll(predicate, pageable);
return new ResponseEntity<>(studentList, multiValueMap, HttpStatus.OK);
}
}
您还需要将此构建插件添加到您的 pom.xml:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>${apt.version}</version>
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/annotations</outputDirectory>
<processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
<logOnlyOnError>true</logOnlyOnError>
</configuration>
</execution>
</executions>
</plugin>