[英]Custom parameter names with a bean for request parameters in Spring 5
我正在尝试使用 Spring 5 为我的请求参数设置自定义 bean。 理论上这很容易,但我想让字段名称与参数名称不同。
我可以使用普通的@RequestParam
参数轻松地做到这一点,但我似乎无法让它与 bean 一起工作。
我发现这个问题之前被问过,答案似乎是“手动执行”,有各种不同的自动化选项,例如使用参数解析器。 但是Spring 5真的还是这样吗?
我的代码(顺便说一句,它是 Kotlin,但这不重要)是这样的:
data class AuthorizationCodeParams(
@RequestParam("client_id") val clientIdValue: String?,
@RequestParam("redirect_uri") val redirectUriValue: String?,
@RequestParam("scope") val scopes: String?,
@RequestParam("state") val state: String?
)
fun startAuthorizationCode(params: AuthorizationCodeParams): ModelAndView {
似乎没有 Spring 提供的方法可以做到这一点。
Spring GitHub 页面上有一个未解决的问题: https://github.com/spring-projects/spring-framework/issues/25815
我在 StackOverflow 上找到了一些解决方案,例如https://stackoverflow.com/a/16520399/4161471 ,但它们看起来相当复杂,或者不可重复使用。 所以我开发了一个解决方法。
我通过创建自定义注释和HandlerMethodArgumentResolver
解决了这个问题。 参数解析器将使用 Jackson 转换请求参数。(不需要使用 Jackson,但它很好、通用且安全。)
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.core.MethodParameter
import org.springframework.stereotype.Component
import org.springframework.web.bind.support.WebDataBinderFactory
import org.springframework.web.context.request.NativeWebRequest
import org.springframework.web.method.support.HandlerMethodArgumentResolver
import org.springframework.web.method.support.ModelAndViewContainer
/**
* Parses all request parameters and maps them to a JSON-serializable class.
*
* This is useful, because it allows multiple `@RequestParam`s to be
* encapsulated in a single object, the values will be type-safe, and
* the parameter names can be set using (for example, with `@JsonProperty`).
*/
@Target(AnnotationTarget.VALUE_PARAMETER)
@MustBeDocumented
annotation class JsonRequestParam {
@Component
class ArgumentResolver(
private val objectMapper: ObjectMapper
) : HandlerMethodArgumentResolver {
// only resolve parameters that are annotated with JsonRequestParam
override fun supportsParameter(parameter: MethodParameter): Boolean {
return parameter.hasParameterAnnotation(JsonRequestParam::class.java)
}
override fun resolveArgument(
parameter: MethodParameter,
mavContainer: ModelAndViewContainer?,
webRequest: NativeWebRequest,
binderFactory: WebDataBinderFactory?
): Any? {
// `webRequest.parameterMap` is a `Map<String, String[]>`, so join
// the values to a string
val params: Map<String, String> = webRequest.parameterMap.mapValues { (_, v) -> v.joinToString() }
return objectMapper.convertValue(params, parameter.parameterType)
}
}
}
请注意,将参数 map 值与webRequest.parameterMap.mapValues { (_, v) -> v.joinToString() }
一起加入是一个快速修复。 它可能不正确,只适用于具有原始参数的类 - 请提出改进建议!
所以如果我有一个 DTO...
data class MyDataObject(
@JsonProperty("n")
val name: String,
val age: Int,
)
我已经使用@JsonProperty
来覆盖属性名称,这意味着“名称”的请求参数将为n
。
现在在我的@Controller
中,我可以在@GetMapping
方法中使用 DTO,并使用我创建的@JsonRequestParam
对其进行注释。
import my.project.JsonRequestParam
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api")
class MyDataController {
@GetMapping(value = ["/data"])
fun getData(
@JsonRequestParam
request: MyDataObject
): ResponseEntity<String> {
return "get data $request"
}
}
所以如果我 GET /api/data?n=MyName&age=22
,那么我会得到一个回应:
get data MyDataObject(name = "MyName", age = 22)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.