[英]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.