多个可选的@RequestParam 未在 spring 引导中获取数据

Multiple optional @RequestParam not fetching Data in spring boot

我想对 Spring 引导项目中的响应数据进行分页。根据业务逻辑,我添加了多个RequestParam。一切正常,如果我为所有请求参数传递值,即性别和国家/地区。但是,如果我不给一个或两个值,我会得到 500 状态代码,尽管我将性别和国家/地区请求参数设置为可选。这意味着,

如果我命中

http://localhost:8080/api/v1/users?page=1&country=Russia&gender=M,

我收到分页响应。

但是如果我命中

http://localhost:8080/api/v1/users?page=1&gender=M

http://localhost:8080/api/v1/users?page=1&country=俄罗斯

http://localhost:8080/api/v1/users?page=1.

我遇到异常

这是我的代码。

UserRepository.kt

@Repository
interface UserRepository: JpaRepository<User, Long> {

    @Query(
        nativeQuery = true,
        value = "SELECT * FROM user_info WHERE gender =:gender AND country =:country"
    )
    fun getUsers(gender: String?, country: String?, pageable: Pageable): Page<User>

}

UserServiceImpl.kt

@Service
class UserServiceImpl(
    @Autowired private val userRepository: UserRepository
): UserService {

    override fun getUsers(gender: String?, country: String?, pageable: Pageable): Page<User> {
        return userRepository.getUsers(gender, country, pageable)
    }

}

UserController.kt

@RestController
@RequestMapping(
    path = [
        "/api/v1/"
    ]
)
class UserController(
    @Autowired private val userService: UserService
) {

    @GetMapping("users")
    fun getUsers(
        @RequestParam(required = true) page: Int,
        @RequestParam(required = false) gender: String?,
        @RequestParam(required = false) country: String?
    ): Page<User> {
        return userService.getUsers(gender, country, PageRequest.of(page, 10))
    }

}

response

{
    "status": "500 INTERNAL_SERVER_ERROR",
    "message": "Internal server error occurs",
    "error": "could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet"
}

这里使用jdbcTemplate比较好:

String query = "SELECT * FROM user_info WHERE gender = :gender AND country = :country";
Map<String, Object> params = new HashMap<>();
params.put("gender", gender);
params.put("country", country);
Map<String, Long> results = new HashMap<>();
// Execute Your Query Here like: users = jdbcTemplate.query(query, params, ...

对于这些参数,您可以检查 gender 是否不为 null 将 gender = :gender 附加到主查询。

是的,您得到的错误是正确的,因为您的查询值不存在我建议您进行以下更改...

@Repository
interface UserRepository: JpaRepository<User, Long> {

@Query(
    nativeQuery = true,
    value = "SELECT * FROM user_info WHERE country =:country"
)
fun getUsersWithoutGender( country: String?, pageable: Pageable): Page<User>

 @Query(
    nativeQuery = true,
    value = "SELECT * FROM user_info WHERE gender =:gender AND country =:country"
)
fun getUsersWithoutCountry(gender: String?, pageable: Pageable): Page<User>

 @Query(
    nativeQuery = true,
    value = "SELECT * FROM user_info WHERE gender =:gender AND country =:country"
)
fun getUsers(gender: String?, country: String?, pageable: Pageable): Page<User>

@Query(
    nativeQuery = true,
    value = "SELECT * FROM user_info"
)
fun getallUsers(): Page<User>

}

并在您的控制器中

RestController
@RequestMapping(
path = [
    "/api/v1/"
]
)
class UserController(
@Autowired private val userService: UserService
) {

@GetMapping("users")
fun getUsers(
    @RequestParam(required = true) page: Int,
    @RequestParam(required = false) gender: String?,
    @RequestParam(required = false) country: String?
): Page<User> {

if(country == null && gender =! null){
    return userService.getUsersWithoutCountry(gender,PageRequest.of(page, 10))
} else if (gender== null && country =! null){
    return userService.getUsersWithoutGender(country,PageRequest.of(page, 10))
}else if (gender && country == null){
    return userService.getAllUsers()
}else {
    return userService.getUsers(gender, country, PageRequest.of(page, 10))    
}
}

}

这样您的所有查询都会 运行 因为它们没有空值。

最后,我通过帮助创建动态查询的JpaSpecificationExecutor解决了这个问题。代码如下。

UserSpecification.kt

import com.example.demo.entity.User
import org.springframework.data.jpa.domain.Specification
import javax.persistence.criteria.CriteriaBuilder
import javax.persistence.criteria.CriteriaQuery
import javax.persistence.criteria.Root
import java.text.MessageFormat.format

object UserSpecification {

    fun countryContains(country: String?): Specification<User>? {
        return country?.let {
            Specification { root: Root<User>, _: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
                criteriaBuilder.like(root.get("country"), format("%{0}%", country))
            }
        }
    }

    fun genderContains(gender: String?): Specification<User>? {
        return gender?.let {
            Specification { root: Root<User>, _: CriteriaQuery<*>, criteriaBuilder: CriteriaBuilder ->
                criteriaBuilder.equal(root.get<String>("gender"), gender)
            }
        }
    }

}

UserRepository.kt

@Repository
interface UserRepository: JpaRepository<User, Long>, JpaSpecificationExecutor<User> {

}

UserServiceImpl.kt

@Service
class UserServiceImpl(
    @Autowired private val userRepository: UserRepository
): UserService {

    override fun getUsers(gender: String?, country: String?, pageable: Pageable): Page<User> {
        return userRepository.findAll(
            where(
                countryContains(country)
            ).and(
                genderContains(gender)
            ), pageable
        )
    }
}