Java Spring集成Adyen Webhook报错:不支持application/x-www-form-urlencoded类型
Spring接收Adyen Webhook的application/x-www-form-urlencoded请求并映射到对象
问题分析
你遇到的核心问题有两个:
- Spring 默认不支持直接将
application/x-www-form-urlencoded请求体自动转换为POJO,直接用DTO作为接口参数会触发Content type not supported错误; - 用
Map接收后无法通过ObjectMapper转换为DTO,是因为Adyen Webhook的notificationItems参数是JSON字符串格式,而非直接的表单字段,ObjectMapper无法直接将字符串映射为List类型字段。
解决方案
下面提供两种可行的处理方式,推荐优先使用第一种结合Adyen官方SDK的方案,更稳定可靠。
方式一:使用Adyen官方SDK处理(推荐)
Adyen官方Java SDK已经封装了Webhook相关的DTO类,无需自行定义,避免字段匹配错误:
- 引入SDK依赖(Maven示例):
<dependency> <groupId>com.adyen</groupId> <artifactId>adyen-java-api-library</artifactId> <version>21.0.0</version> <!-- 替换为最新版本 --> </dependency>
- 修改控制器方法,手动解析表单参数:
import com.adyen.model.notification.NotificationRequest; import com.adyen.model.notification.NotificationRequestItem; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import jakarta.ws.rs.core.Response; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/webhooks") public class AdyenWebhookController { private static final Logger log = LoggerFactory.getLogger(AdyenWebhookController.class); private final AdyenService adyenService; public AdyenWebhookController(AdyenService adyenService) { this.adyenService = adyenService; } @PostMapping(value = "/notifications", consumes = "application/x-www-form-urlencoded") public Response handleWebhook(HttpServletRequest request) { try { // 从表单参数中获取核心的JSON字符串参数 String notificationItemsJson = request.getParameter("notificationItems"); String merchantAccount = request.getParameter("merchantAccount"); // 将JSON字符串解析为SDK定义的对象列表 ObjectMapper mapper = new ObjectMapper(); java.util.List<NotificationRequestItem> itemList = mapper.readValue( notificationItemsJson, new TypeReference<java.util.List<NotificationRequestItem>>() {} ); // 组装成官方的NotificationRequest对象 NotificationRequest notificationRequest = new NotificationRequest(); notificationRequest.setNotificationItems(itemList); notificationRequest.setMerchantAccount(merchantAccount); // 处理Webhook逻辑 adyenService.webhooks(notificationRequest); return Response.ok("accepted").build(); } catch (Exception ex) { log.error("Adyen Webhook处理失败", ex); return Response.serverError(ex.getMessage()).build(); } } }
方式二:自定义DTO并处理JSON字符串字段
如果不想依赖官方SDK,可自行定义DTO,并通过自定义setter解析JSON字符串:
- 定义DTO类,为
notificationItems字段添加自定义setter:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.List; public class NotificationRequestDTO { private List<NotificationItemDTO> notificationItems; private String merchantAccount; // 其他字段的getter/setter... public List<NotificationItemDTO> getNotificationItems() { return notificationItems; } // 自定义setter,将JSON字符串转换为List public void setNotificationItems(String notificationItemsJson) throws IOException { ObjectMapper mapper = new ObjectMapper(); this.notificationItems = mapper.readValue( notificationItemsJson, new TypeReference<List<NotificationItemDTO>>() {} ); } public String getMerchantAccount() { return merchantAccount; } public void setMerchantAccount(String merchantAccount) { this.merchantAccount = merchantAccount; } } // 对应的NotificationItemDTO public class NotificationItemDTO { private String eventCode; private boolean success; private String pspReference; // 其他字段及getter/setter... }
- 控制器方法使用
@ModelAttribute绑定DTO:
@PostMapping(value = "/notifications", consumes = "application/x-www-form-urlencoded") public Response handleWebhook(@ModelAttribute NotificationRequestDTO notificationRequest) { try { adyenService.webhooks(notificationRequest); return Response.ok("accepted").build(); } catch (Exception ex) { log.error("Adyen Webhook处理失败", ex); return Response.serverError(ex.getMessage()).build(); } }
关键注意事项
- 确保DTO字段名与Adyen Webhook的表单参数名完全一致(大小写敏感),比如
notificationItems、merchantAccount; notificationItems是JSON字符串,必须先解析为对象列表再使用,不能直接映射;- 处理Webhook时,务必验证Adyen的签名,避免恶意请求(官方SDK提供了签名验证工具类)。
内容的提问来源于stack exchange,提问作者Matteo Sperti
相关产品推荐
相关产品推荐

