我正在构建一个小型应用程序,以充当此处工作的某些第三方库的客户端。API指出,Webhook
需要a来响应一些异步事件,但是除了_method
调用之间的字段更改之外,它们的所有方法都具有相同的签名。例如,我有个_method
=
ping
,media
等
我想在控制器上使用单独的方法来对这些方法中的每一个进行响应。如果应用程序允许我为每种方法指定不同的URL,则对每种方法使用Spring
MVC会很容易@RequestMapping
。但是我必须指定一个端点来接收所有呼叫。
有没有一种方法(例如,使用Spring
HttpMessageConverter
或类似方法)根据请求主体是什么来映射不同的控制器方法?我已经尝试过@RequestBody
,@RequestParam
但似乎没有找到任何东西。
我真的 非常 不想case, switch
在前端控制器上使用一堆方法来根据_method
POST数据附带的字段来调度操作,因此我碰巧相信有人以前曾遇到过这个问题并可以智能地解决它。
非常感谢!
@Controller
@RequestMapping("/webhooks")
public class WebhookController {
@RequestMapping(method = RequestMethod.POST, params = {"_method=ping"})
@ResponseBody
public String ping(){
return "pong";
}
@RequestMapping(method = RequestMethod.POST, params = {"_method=media"})
@ResponseBody
public String media(){
return "media";
}
}
这是答案:
{
"timestamp": 1440875190389,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.bind.UnsatisfiedServletRequestParameterException",
"message": "Parameter conditions \"_method=ping\" not met for actual request parameters: ",
"path": "/webhooks"
}
是的,我知道了。答案有些棘手,所以如果有人遇到这种问题,我想在这里注册。
@Neil McGuigan在他的评论中为我指出了正确的方向,但起初我没有注意。罪魁祸首是我们的远程应用程序方面非常 非常 糟糕的API设计。
_method
是用于指定非标准HTTP动词诸如场PUT
,PATCH
,DELETE
,TRACE
等。该字段由过滤,HiddenHttpMethodFilter
并HttpServletRequest
使用此“新”方法进行包装。您可以在文件源中看到其工作方式。
因为我希望该_method
字段通过过滤器而不修改整个请求(并且由于没有诸如RequestMethod
ping
或之类的动词而导致错误message
),所以我首先必须停用过滤器。这可以通过两种方式完成:
我可以阻止Spring Boot自动配置Spring MVC,WebMvcAutoConfiguration
而在加载时跳过ApplicationContext
加载。正如你能想象这是一个很大很大的,BIIIIG NO 因为,事情可能发生。
我可以使用FilterRegistrationBean
来禁用错误的过滤器。非常简单明了,这是我选择使用的方法:
@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
最后但并非最不重要HiddenHttpMethodFilter
的一点是,我决定稍作扩展,以某种方式 改进 请求的处理方式。Java
EE规范在Servlet规范指令中非常清楚地指出:
您 不应该 改变您的要求。您必须尊重发件人(类似的东西)
尽管我同意这一点,但是为了我的心理稳定,我还是决定更改它。为此,我们可以使用simple
HttpServletRequestWrapper
方法,重写所选方法,并使用包装的部分过滤原始请求。我最终做了这样的事情:
public class WhatoolsHiddenHttpMethodFilter extends OrderedHiddenHttpMethodFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String paramValue = request.getParameter(OrderedHiddenHttpMethodFilter.DEFAULT_METHOD_PARAM);
if("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
List<String> whatoolsMethods = Arrays.asList("ping", "message", "carbon", "media", "media_carbon", "ack");
if(whatoolsMethods.contains(paramValue)){
WhatoolsHiddenHttpMethodFilter.HttpMethodRequestWrapper wrapper = new WhatoolsHiddenHttpMethodFilter
.HttpMethodRequestWrapper(request, "POST", paramValue);
filterChain.doFilter(wrapper, response);
} else {
WhatoolsHiddenHttpMethodFilter.HttpMethodRequestWrapper wrapper = new WhatoolsHiddenHttpMethodFilter
.HttpMethodRequestWrapper(request, method, null);
filterChain.doFilter(wrapper, response);
}
} else {
filterChain.doFilter(request, response);
}
}
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
private final String whatoolsMethod;
public HttpMethodRequestWrapper(HttpServletRequest request, String method, String whatoolsMethod) {
super(request);
this.method = method;
this.whatoolsMethod = whatoolsMethod;
}
@Override
public String getMethod() {
return this.method;
}
@Override
public String getHeader(String name) {
if("x-whatools-method".equals(name)){
return this.whatoolsMethod;
}
return super.getHeader(name);
}
@Override
public Enumeration<String> getHeaderNames() {
List<String> names = Collections.list(super.getHeaderNames());
if(this.whatoolsMethod != null){
names.add("x-whatools-method");
}
return Collections.enumeration(names);
}
}
}
因此,这是x-whatools- method
在标头位于我的whatoolsMethods
列表中时用新标头包装请求。这样,我可以轻松使用@RequestMapping
的headers
属性并将请求映射到正确的控制器方法。
回到最初的问题,我几乎可以肯定(99.95%应该完全确定,但不要冒险),该params
属性@RequestMapping
仅对GET
URI上的请求参数有效http://foo.bar/?baz=42
。它不能过滤请求正文上发送的参数。
感谢尼尔的指导,即使很小!我希望这可以帮助别人。
我有3个类:< code>Visitor,< code>Guest,< code>EventGuests 和映射到一个表只有一个id和外部id。没有一切都很好。但当添加时,构建失败: 附言:在MySQL中创建“EventGuest”表。
本文向大家介绍bootstrap 表单验证使用方法,包括了bootstrap 表单验证使用方法的使用技巧和注意事项,需要的朋友参考一下 前言:做Web开发的我们,表单验证是再常见不过的需求了。友好的错误提示能增加用户体验。博主搜索bootstrap表单验证,搜到的结果大部分都是文中的主题:bootstrapvalidator。今天就来看看它如何使用吧。 一、源码及API地址 介绍它之前,还是给出它
在流API中映射对象的更好实践是什么? 1-带有方法引用的后续map(): 为什么呢?
我在RestController类中有以下requestMethod,它运行良好: 我还有一个假客户也工作得很好。我在两种方法中都添加了一个名为forceSupplier的新参数,但添加后,我发现,但我真的不明白为什么我会收到此消息,因为参数是相同的。 这是假装的方法: 我做错了什么?谢谢
我试图用Spring Boot MVC做一个应用程序,但遇到了一个问题。对于Post和Put方法,我收到状态200 ok,但值为“null”。创建了数据库上的新注册,但只填充了Id(自动增量)列,并在Postman响应中接收。谁能帮帮我吗? `@RequestMapping(“/api”)@RestController公共类ExtractedNumbersController{private fi
本文向大家介绍angular.extend方法的具体使用,包括了angular.extend方法的具体使用的使用技巧和注意事项,需要的朋友参考一下 AngularJs的angular.extend()方法可以把一个或多个对象中的方法和属性扩展到一个目的对象中,使得这个对象拥有其他对象相同的方法和属性,如下图所示。 angular.extends()方法的第一个参数是要被扩展的对象,后面可以传入一个
我有两个对象,除了date成员外,其他成员都相同。在obj1中,date是java.sql.date,obj2.date是long(纪元)。 我需要编写一个映射器来将obj1映射到obj2。这就是我试图做的: 但是mapperImpl只有自己的日期转换实现: 我得到了: 这种转换的正确方式是什么?
在MySQL数据库上有一个没有任何主键的表。我想使用hibernate访问Java的数据端。但是,hibernate无法解析映射文档。其他表映射正确。这个问题是不是没有主键的原因?我必须至少创建一个主键来映射此表吗?还是还有别的什么? 表