使用 Spring 解码 body 个参数
Decoding body parameters with Spring
我正在为 Slack 应用程序开发一个 REST API 后端 Spring。我能够从 Slack 接收消息(斜杠命令),但我无法正确接收组件交互(按钮点击)。
Your Action URL will receive a HTTP POST request, including a payload body parameter, itself containing an application/x-www-form-urlencoded JSON string.
所以我写了下面的@RestController
:
@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") ActionController.Action action) {
return ResponseEntity.status(HttpStatus.OK).build();
}
@JsonIgnoreProperties(ignoreUnknown = true)
class Action {
@JsonProperty("type")
private String type;
public Action() {}
public String getType() {
return type;
}
}
但是我收到以下错误:
Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action': no matching editors or conversion strategy found
什么意思,如何解决?
您收到一个包含 JSON 内容的字符串。您没有收到 JSON 输入,因为 application/x-www-form-urlencoded
用作内容类型,而不是 application/json
,如所述:
Your Action URL will receive a HTTP POST request, including a payload
body parameter, itself containing an application/x-www-form-urlencoded
JSON string.
因此将参数类型更改为 String
并使用 Jackson 或任何 JSON 库将 String
映射到您的 Action
class :
@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") String actionJSON) {
Action action = objectMapper.readValue(actionJSON, Action.class);
return ResponseEntity.status(HttpStatus.OK).build();
}
正如 pvpkiran 所建议的,如果您可以直接在 POST 请求的正文中传递 JSON 字符串,则可以将 @RequestParam
替换为 @RequestBody
,而不是作为参数的值,但似乎并非如此。
实际上,通过使用 @RequestBody
,请求的主体通过 HttpMessageConverter
传递以解析方法参数。
为了回答您的评论,Spring MVC 没有提供一种非常简单的方法来实现您的要求:将字符串 JSON 映射到您的 Action
class .
但是如果你真的需要自动化这个转换,你有一个冗长的选择,如 the Spring MVC documentation 中所述,例如格式化程序(重点是我的):
Some annotated controller method arguments that represent String-based
request input — e.g. @RequestParam
, @RequestHeader
, @PathVariable
,
@MatrixVariable,
and @CookieValue
, may require type conversion if the
argument is declared as something other than String.
For such cases type conversion is automatically applied based on the
configured converters. By default simple types such as int, long,
Date, etc. are supported. Type conversion can be customized through a
WebDataBinder, see DataBinder, or by registering Formatters with the
FormattingConversionService, see Spring Field Formatting.
通过为您的 Action
class 创建格式化程序 (FormatterRegistry
subclass),您可以将其添加到 Spring 网络配置 as documented:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ... add action formatter here
}
}
并在您的参数声明中使用它:
public ResponseEntity action(@RequestParam("payload") @Action Action actionJ)
{...}
为简单起见,您可以使用下面的代码块。 @Request 正文将负载映射到 Action class。它还会验证以确保类型不为空。 @Valid 和 @NotBlank 来自 javax.validation 包。
@PostMapping("actions")
public ResponseEntity<?> startApplication(@RequestBody @Valid Action payload) {
// use your payload here
return ResponseEntity.ok('done');
}
class Action {
@NotBlank
private String type;
public Action() {
}
public String getType() {
return type;
}
}
我正在为 Slack 应用程序开发一个 REST API 后端 Spring。我能够从 Slack 接收消息(斜杠命令),但我无法正确接收组件交互(按钮点击)。
Your Action URL will receive a HTTP POST request, including a payload body parameter, itself containing an application/x-www-form-urlencoded JSON string.
所以我写了下面的@RestController
:
@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") ActionController.Action action) {
return ResponseEntity.status(HttpStatus.OK).build();
}
@JsonIgnoreProperties(ignoreUnknown = true)
class Action {
@JsonProperty("type")
private String type;
public Action() {}
public String getType() {
return type;
}
}
但是我收到以下错误:
Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'controllers.ActionController$Action': no matching editors or conversion strategy found
什么意思,如何解决?
您收到一个包含 JSON 内容的字符串。您没有收到 JSON 输入,因为 application/x-www-form-urlencoded
用作内容类型,而不是 application/json
,如所述:
Your Action URL will receive a HTTP POST request, including a payload body parameter, itself containing an application/x-www-form-urlencoded JSON string.
因此将参数类型更改为 String
并使用 Jackson 或任何 JSON 库将 String
映射到您的 Action
class :
@RequestMapping(method = RequestMethod.POST, value = "/actions", headers = {"content-type=application/x-www-form-urlencoded"})
public ResponseEntity action(@RequestParam("payload") String actionJSON) {
Action action = objectMapper.readValue(actionJSON, Action.class);
return ResponseEntity.status(HttpStatus.OK).build();
}
正如 pvpkiran 所建议的,如果您可以直接在 POST 请求的正文中传递 JSON 字符串,则可以将 @RequestParam
替换为 @RequestBody
,而不是作为参数的值,但似乎并非如此。
实际上,通过使用 @RequestBody
,请求的主体通过 HttpMessageConverter
传递以解析方法参数。
为了回答您的评论,Spring MVC 没有提供一种非常简单的方法来实现您的要求:将字符串 JSON 映射到您的 Action
class .
但是如果你真的需要自动化这个转换,你有一个冗长的选择,如 the Spring MVC documentation 中所述,例如格式化程序(重点是我的):
Some annotated controller method arguments that represent String-based request input — e.g.
@RequestParam
,@RequestHeader
,@PathVariable
,@MatrixVariable,
and@CookieValue
, may require type conversion if the argument is declared as something other than String.For such cases type conversion is automatically applied based on the configured converters. By default simple types such as int, long, Date, etc. are supported. Type conversion can be customized through a WebDataBinder, see DataBinder, or by registering Formatters with the FormattingConversionService, see Spring Field Formatting.
通过为您的 Action
class 创建格式化程序 (FormatterRegistry
subclass),您可以将其添加到 Spring 网络配置 as documented:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ... add action formatter here
}
}
并在您的参数声明中使用它:
public ResponseEntity action(@RequestParam("payload") @Action Action actionJ)
{...}
为简单起见,您可以使用下面的代码块。 @Request 正文将负载映射到 Action class。它还会验证以确保类型不为空。 @Valid 和 @NotBlank 来自 javax.validation 包。
@PostMapping("actions")
public ResponseEntity<?> startApplication(@RequestBody @Valid Action payload) {
// use your payload here
return ResponseEntity.ok('done');
}
class Action {
@NotBlank
private String type;
public Action() {
}
public String getType() {
return type;
}
}