如何向"/users?<some-query-here>"发出GET请求,则所有满足查询条件的用户都将在JSON数组中返回



长期读者,第一次海报。

我需要帮助。我无法弄清楚 URL 参数↔数据库。

情况:我把.../用户/?角色=管理员&标题=经理放到邮递员

预期:作为管理员和管理员的所有用户的 json。

实际:我的电脑炸了。

@RestController
@RequestMapping(path = USERS_PATH)
@Log4j2
public class UserController
// other code...
@GetMapping
public ResponseEntity<List<User>>  getUserQuery(
@RequestParam( required = false, name = "name") String name,
@RequestParam( required = false, name = "title") String title,
@RequestParam( required = false, name = "roles") String roles,
@RequestParam( required = false, name = "email") String email,
@RequestParam( required = false, name = "password") String password
) {
log.info("Request received for getUserQuery");
return new ResponseEntity<>(userService.doSomething???(), HttpStatus.OK); // stuff I don't understand yet)
}

我的问题:在控制器之后,用户服务和用户存储库中的内容是什么?

额外信息:我正在使用Spring Boot和H2,但以后可能需要切换到PostgreSQL DB。

我有下面的代码作为在服务层上放置和发布期间对唯一电子邮件的检查,但我无法获得类似的东西来解决这个问题。

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.email = ?1")
Optional<User> findUserByEmail(String email);
}

咆哮:这似乎是一件非常普遍的事情,我应该已经知道如何做到这一点了。 我没有。 我已经在互联网上阅读了大约 5 个小时。 仍然没有答案。我学到了有关Specification,Querydsl,@ModelAtribute,DAO和映射RequestParams的知识。 但是,我找不到如何连接这些点。 所以,我完全变成了穴居人,并尝试使用StringBuilder和一堆逻辑制作一个@Query参数......我开始螺旋式上升。

无论如何,我想避免规范和Querydsl。只需使用 @Query 和 JPA,但更重要的是,我想要一个干净的解决方案/最佳实践。

这是一个工作截图。我认为您的存储库有问题。您正在使用@Query和现成的查询支持。

服务和存储库中的内容:存储库层(存储库)类用于抽象与数据库的交互。

服务层与存储库层交互,并对存储库层返回的数据进行处理。

UserEntity

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Getter
@Setter
@Entity
@Table(name = "users")
@NoArgsConstructor
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "designation")
private String designation;
@Column(name = "email")
private String email;

}

UserRepository

import com.example.code.entity.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<UserEntity, Long> {
Optional<UserEntity> findByName(String name);
List<UserEntity> findByDesignation(String designation);
Optional<UserEntity> findByEmail(String email);
}

UserService

import java.util.Collection;
public interface UserService {
void createUser(UserDTO userDTO);
Collection<UserDTO> getUsers(
String username,
String designation,
String email
);
}

UserServiceImpl

import com.example.code.dto.UserDTO;
import com.example.code.entity.UserEntity;
import com.example.code.mapper.UserMapper;
import com.example.code.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.apache.catalina.User;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
@Override
public void createUser(UserDTO userDTO) {
UserEntity userEntity = new UserEntity();
userEntity.setName(userDTO.getName());
userEntity.setDesignation(userDTO.getDesignation());
userEntity.setEmail(userDTO.getEmail());
userRepository.save(userEntity);
}
@Override
public Collection<UserDTO> getUsers(String username, String designation, String email) {
Set<UserDTO> userDTOS = new HashSet<>();
if( !username.isBlank() && !username.isEmpty() && userRepository.findByName(username).isPresent() ) {
userDTOS.add(UserMapper.toDto(
userRepository.findByName(username).get()
));
}
if(!designation.isBlank() && !designation.isEmpty()) {
userDTOS.addAll(
userRepository.findByDesignation(designation)
.stream()
.map(UserMapper::toDto)
.collect(Collectors.toSet())
);
}
if( !email.isBlank() &&
!email.isEmpty() &&
userRepository.findByEmail(email).isPresent() ) {
userDTOS.add(UserMapper.toDto(
userRepository.findByEmail(email).get()
));
}
return userDTOS;
}
}

UserMapper

import com.example.code.dto.UserDTO;
import com.example.code.entity.UserEntity;
public class UserMapper {
public static UserDTO toDto(UserEntity entity) {
UserDTO userDTO = new UserDTO();
userDTO.setName(entity.getName());
userDTO.setDesignation(entity.getDesignation());
userDTO.setEmail(entity.getEmail());
return userDTO;
}
}

TestController

@RestController
@RequestMapping("/test")
@RequiredArgsConstructor
public class TestController {
private final UserService userService;
@PostMapping
public ResponseEntity<String> createUser(@RequestBody final UserDTO userDTO) {
try {
userService.createUser(userDTO);
}catch (Exception e) {
return ResponseEntity.internalServerError().body("Failure");
}
return ResponseEntity.ok("Success");
}
@GetMapping
public ResponseEntity<Collection<UserDTO>> getUsers(
@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "designation", required = false) String designation,
@RequestParam(value = "email", required = false) String email
) {
return ResponseEntity.ok(userService.getUsers(name, designation, email));
}
}

SQLAND的组合,OR子句应该可以满足您的目的。下面给出了一个使用服务和存储库类的示例。

用户服务

public List<User> doingSomething(String name, String title, String roles, String email,String password) {
return userRepository.detailQuery(name, title, roles, email,  password);
}

用户存储库

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE (:name is null or u.name = :name) and (:title is null or u.title = :title) and (:roles is null or u.roles = :roles) and (:email is null or u.email = :email) and (:password is null or u.password = :password)")
List<User> detailQuery(@Param("name") String name,
@Param("title") String title,
@Param("roles") String roles,
@Param("email") String email,
@Param("password") String password);
}

将查询作为单个参数的简单答案是使用 JPA 的按示例查询方法

所以你的代码看起来像这样:

服务

public List<User> getByExample(User user) {
return userRepository.findAll(Example.of(user,
ExampleMatcher.matchingAny().withIgnoreCase()));
}

在控制器类上,您甚至不必再提供单个参数。您只需将 User 作为方法的参数提供即可。JPA 足够聪明,可以从您给出的参数中暗示用户的属性。因此,您的控制器类可能只是看起来像这样:

控制器:

@GetMapping
public ResponseEntity<List<User>>  getUserQuery(User user) {
log.info("Request received for getUserQuery");
return new ResponseEntity<>(userService.getByExample(user), HttpStatus.OK);
}

5.1.6 按示例查询,我们开始:

我们的存储库中不需要任何东西,因为JpaRepository"已经板上了"!

我们的服务如下所示:

package com.example;
import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.exact;
import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.ignoreCase;
import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.startsWith;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
@Autowired
JpaRepository<Person, Long> personRepository;
public List<Person> find(String name, String title, String roles, String email, String password) {
Person person = Person.of(name, title, roles, email, password);
ExampleMatcher matcher = ExampleMatcher
.matchingAny()
.withIgnoreNullValues()
.withMatcher("name", ignoreCase())
.withMatcher("title", ignoreCase())
.withMatcher("roles", ignoreCase())
.withMatcher("email", ignoreCase())
.withMatcher("password", exact());
return personRepository.findAll(Example.of(person, matcher));
}
} // UN-TESTED, but compilable ;)

。但我们看到:仅使用这五个参数就可以进行多少"调整"。

用法:

按示例查询非常适合多种用例:

  • 使用一组静态或动态约束查询数据存储。

  • 频繁重构域对象,无需担心中断现有查询。

  • 独立于基础数据存储 API 工作。

按示例查询也有几个限制:

  • 不支持嵌套或分组属性约束,例如firstname = ?0 or (firstname = ?1 and lastname = ?2)

  • 仅支持字符串的开始/包含/结束/正则表达式匹配和其他属性类型的精确匹配。

我得到了这个工作,但我不知道这是否是最佳实践。

控制器:

@GetMapping
public ResponseEntity<List<User>>  getUserQuery(
@RequestParam( required = false, name = "name") String name,
@RequestParam( required = false, name = "title") String title,
@RequestParam( required = false, name = "roles") String roles,
@RequestParam( required = false, name = "email") String email,
@RequestParam( required = false, name = "password") String password
) {
log.info("Request received for getUserQuery");
return new ResponseEntity<>(userService.QueryUsers(name, title, roles, email, password), HttpStatus.OK); // stuff I don't understand yet)
}

服务:

public List<User> QueryUsers(String name, String title, String roles,String email,String password) {
if (name == null && title == null && roles == null && email == null && password == null) {
return userRepository.findAll(Sort.by(Direction.ASC, "id"));
}
//TODO: make to lower case
List<User> users = new ArrayList<>();
users.addAll(userRepository.findAllUsersByName(name));
users.addAll(userRepository.findAllUsersByTitle(title));
users.addAll(userRepository.findAllUsersByRoles(roles));
users.addAll(userRepository.findAllUsersByEmail(email));
users.addAll(userRepository.findAllUsersByPassword(password));
return users;
}

存储 库:

@Query("SELECT u FROM User u WHERE u.name = ?1")
Collection<? extends User> findAllUsersByName(String name);
@Query("SELECT u FROM User u WHERE u.title = ?1")
Collection<? extends User> findAllUsersByTitle(String title);
@Query("SELECT u FROM User u WHERE u.roles = ?1")
Collection<? extends User> findAllUsersByRoles(String roles);
@Query("SELECT u FROM User u WHERE u.email = ?1")
Collection<? extends User> findAllUsersByEmail(String email);
@Query("SELECT u FROM User u WHERE u.password = ?1")
Collection<? extends User> findAllUsersByPassword(String password);

似乎正在工作,但我需要对其进行更多测试。

最新更新