Java 用弹簧解码车身参数
我正在为Slack应用程序开发一个带有Spring的RESTAPI后端。我能够从Slack(斜杠命令)接收消息,但无法正确接收组件交互(按钮单击) 报告说: 您的操作URL将接收一个HTTP POST请求,包括一个有效负载主体参数,该参数本身包含一个application/x-www-form-urlencoded JSON字符串 因此,我编写了以下Java 用弹簧解码车身参数,java,spring,slack,slack-api,spring-rest,Java,Spring,Slack,Slack Api,Spring Rest,我正在为Slack应用程序开发一个带有Spring的RESTAPI后端。我能够从Slack(斜杠命令)接收消息,但无法正确接收组件交互(按钮单击) 报告说: 您的操作URL将接收一个HTTP POST请求,包括一个有效负载主体参数,该参数本身包含一个application/x-www-form-urlencoded JSON字符串 因此,我编写了以下@RestController: @RequestMapping(method = RequestMethod.POST, value = "/ac
@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
,如上所述:
您的操作URL将接收HTTP POST请求,包括有效负载
body参数,本身包含一个应用程序/x-www-form-urlencoded
JSON字符串
因此,将参数类型更改为String
,并使用Jackson或任何JSON库将String
映射到您的Action
类:
@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
来解析方法参数
为了回答您的评论,SpringMVC没有提供一种非常简单的方法来实现您的需求:将字符串JSON映射到您的Action
类。但是,如果您确实需要自动化此转换,您有一个冗长的替代方案,如Formatters(重点是我的): 一些带注释的控制器方法参数表示基于字符串的 请求输入 — e、 g.
@RequestParam
,@RequestHeader
,@PathVariable
,
@MatrixVariable、
和@CookieValue
可能需要进行类型转换,如果
参数声明为字符串以外的内容
对于这种情况,类型转换将根据
配置转换器。默认情况下,简单类型,如int、long、,
支持日期等类型转换可以通过
WebDataBinder,请参阅DataBinder,或通过向
格式化转换服务,请参阅Spring字段格式化。
通过为Action
类创建格式化程序(FormatterRegistry
子类),您可以在SpringWeb配置中添加:
并在参数声明中使用它:
public ResponseEntity action(@RequestParam("payload") @Action Action actionJ)
{...}
为了简单起见,您可以使用下面的代码块@Request主体将有效负载映射到操作类。它还进行验证以确保类型不是空的。@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;
}
}
@PostMapping(“操作”)
公共响应启动应用程序(@RequestBody@Valid Action-payload){
//在这里使用有效载荷
返回ResponseEntity.ok('done');
}
集体诉讼{
@不空白
私有字符串类型;
公共行动(){
}
公共字符串getType(){
返回类型;
}
}
两件事。1.使Action成为一个单独的类,而不是内部类。Jackson在反序列化到内部类方面有一些问题。2发送到此终结点的正文是什么。发送到此终结点的正文是payload=%7B%22type%22%3A%22interactive_message%22%2C%22trigger_id%22%3A%22425937372067.385758389520。上面的字符串是url的一部分吗?或者它是邮件正文的一部分?如果它是url的一部分,那么解决方案就是按照@davidxxx的建议去做。如果它是Post消息负载的一部分,则使用@RequestBody
而不是@RequestParam
,spring将自动将其转换为您的操作class@pvpkiran这是一个有趣的想法。实际上,直接在主体中发布{…}的不是JSON,而是请求主体中添加的有效负载参数的值。你认为Spring能够同样地转换成自定义类吗?@davidxxx如果不是json,没有Spring可以这样做。因为spring依赖Jackson来完成转换,这实际上是可行的,但在我看来,这是一个解决方案,而不是一个解决方案。斯普林/杰克逊真的没有办法自动做到这一点吗?@Andrea不幸的是没有。自动功能取决于另一方是否遵守标准的操作方式,例如,没有合理的理由不双重编码有效负载。真的不知道。也许chrylis是对的。@Andrea不是一个简单的解决方案,但您可以自动化JSON->Action转换。
@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;
}
}