【问题标题】:How to disable spring boot parameter split如何禁用spring boot参数拆分
【发布时间】:2019-09-11 10:09:44
【问题描述】:

我们有许多@RestController 接收用户用通用语言编写的短语。短语可能很长,并且包含标点符号,例如句号,当然还有逗号。

简化控制器示例:

@RequestMapping(value = "/countphrases", method = RequestMethod.PUT)
public String countPhrases(
    @RequestParam(value = "phrase", required = false) String[] phrase) {

  return "" + phrase.length;
}

Spring boot 默认行为是以逗号分隔参数值,因此之前的控制器使用此 url 调用:

[...]/countphrases?phrase=john%20and%20me,%20you%and%her

将返回“2”而不是我们想要的“1”。事实上,使用逗号拆分之前的调用相当于:

[...]/countphrases?phrase=john%20and%20me&phrase=you%and%her

我们使用自然语言,我们需要准确分析用户如何写的短语,并确切知道他们写了多少。

我们尝试了这个解决方案:https://stackoverflow.com/a/42134833/1085716 在适应我们的 Spring Boot 版本(2.0.5)之后:

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // we hoped this code could remove the "split strings at comma"
        registry.removeConvertible(String.class, Collection.class);
    }
}

但它不起作用。

有人知道如何在spring boot 2.0.5中全局删除“spring boot 2.0.5中的“spring boot split string parameters at comma”行为吗?

【问题讨论】:

  • 你为什么不去 POST 并检索正文中的值?
  • POST、PUT、PATCH 用于将数据发布到服务中,在这里您通常使用正文,因为这样您可以利用 SSL 并且发送的数据是加密的。 GET 通常会返回一个正文,但返回的数据会根据您发送的查询参数进行过滤。例如,您在搜索引擎中进行搜索。您想获取根据您搜索“香蕉”的内容过滤的结果。查询字符串包含香蕉,它会在正文中返回我的结果。
  • 一些解决方案在这里stackoverflow.com/questions/4998748/…

标签: spring-boot


【解决方案1】:

我找到了解决办法。 要覆盖默认转换,我们必须添加一个新转换。如果我们只删除旧的,它就不起作用了。

正确的(示例)代码应该是:

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.removeConvertible(String.class, String[].class);
        registry.addConverter(String.class, String[].class, noCommaSplitStringToArrayConverter());
    }

    @Bean
    public Converter<String, String[]> noCommaSplitStringToArrayConverter() {
        return new Converter<String, String[]>() {
            @Override
            public String[] convert(String source) {
                String[] arrayWithOneElement = {source};
                return arrayWithOneElement;
            }
        };
    }
}

这样,任何像主要问题中的控制器都不会拆分参数值:

  • [...]/countphrases?phrase=a,b 将返回 1(和 fq=["a,b"])
  • [...]/countphrases?phrase=a,b&phrase=c,d 将返回 2(和 fq=["a,b", "c,d"])

【讨论】:

  • 有没有办法只对选定的端点执行此操作?
  • 我不这么认为,因为格式化程序是顶级定义的。应该调查一下。
  • @dobry,可以使用活页夹完成 - stackoverflow.com/a/20375369/363867
【解决方案2】:

用一个全新的列表替换您的格式化程序注册表可能会使您失去框架附带的一些所需的默认格式化程序。这还将在每个端点上禁用整个应用程序的所有 String-To-Collections 解析,这样如果您想在另一个端点上请求如下过滤器,它将不起作用:

identifiers = 12,34,45,56,67

解决方案: 只需将分隔符更改为其他内容... # 或 ;或 $

identifiers = 12;23;34;45;56

这就是我一直在做的事情,所以我不会乱用格式化程序注册表中的所有好东西。

【讨论】:

  • 在我们的用例中,您的解决方案是不可能的,因为参数值是人工编写的文本并且没有可用的预处理,例如“在调用 api 之前用管道替换所有逗号”。我们没有这种级别的控制,所以我们不得不改变弹簧靴的行为。
猜你喜欢
  • 2016-09-27
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-07
  • 1970-01-01
  • 2023-01-14
  • 1970-01-01
相关资源
最近更新 更多