Spring REST Controller在具有空格或逗号等特殊字符时理解字符串数组

时间:2014-07-03 16:47:01

标签: java arrays spring rest spring-mvc

我正在尝试编写一个Spring REST Controller,将一个字符串数组作为HTTP GET请求的输入参数。

在GET请求中出现问题时,在数组的某些字符串中,我使用逗号,,空格或正斜杠/等特殊字符,< strong>无论我是否对URL HTTP GET请求的查询部分进行URL编码。

这意味着字符串&#34; 1/4 cup ricotta, yogurt&#34; (编辑,需要将其视为包含在输入数组的字符串元素中的唯一成分),格式如下:

http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1/4 cup ricotta, yogurt

此格式(请注意空格编码为+加上,而不是十六进制代码):

http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1%2F4+cup+ricotta%2C+yogurt

或此格式(请注意编码为十六进制代码%20的空格):

http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1%2F4%20cup%20ricotta%2C%20yogurt

未正确呈现。

  • 系统无法将输入字符串识别为数组的单个元素。
  • 在第二和第三种情况下,系统将输入字符串拆分为逗号,并返回一个包含2个元素而不是1个元素的数组。我期待这里有1个元素。

控制器的相关代码是:

@RequestMapping(
        value = "/parseThis",
        params = {
                "language",
                "ingredients"

        }, method = RequestMethod.GET, headers = HttpHeaders.ACCEPT + "=" + MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public HttpEntity<CustomOutputObject> parseThis(
        @RequestParam String language,
        @RequestParam String[] ingredients){

    try {

        CustomOutputObject responseFullData = parsingService.parseThis(ingredients, language);

        return new ResponseEntity<>(responseFullData, HttpStatus.OK);

    } catch (Exception e) {
        // TODO
    }

}

我需要针对这个Spring控制器执行HTTP GET请求,这是一个要求(因此这里不能使用HTTP POST)。

修改1:

如果我将HttpServletRequest request添加到控制器中方法的签名中,那么我添加一个日志语句,如log.debug("The query string is: '" + request.getQueryString() + "'");,然后我在日志中看到像The query string is: '&language=en&ingredients=1%2F4+cup+ricotta%2C+yogurt'这样的行(所以仍然是URL编码)。

编辑2:

另一方面,如果我将WebRequest request添加到方法的签名中,则日志为log.debug("The query string is: '" + request.getParameter("ingredients") + "'");,然后我在日志中获得一个字符串The query string is: '1/4 cup ricotta, yogurt'(因此URL解码)。

我正在使用Apache Tomcat作为服务器。

我是否需要在Spring / webapp配置文件中添加/查看任何过滤器或其他内容?

编辑3:

主要问题在于逗号的解释:

@ResponseBody
@RequestMapping(value="test", method=RequestMethod.GET)
public String renderTest(@RequestParam("test") String[] test) {
    return test.length + ": " + Arrays.toString(test);
    // /app/test?test=foo,bar => 2: [foo, bar]
    // /app/test?test=foo,bar&test=baz => 2: [foo,bar, baz]
}

可以防止这种行为吗?

4 个答案:

答案 0 :(得分:3)

请求参数方法参数的路径经过参数值提取然后参数值转换。现在发生的事情是:

<强>提取

参数为extracted as a single String value。这可能是为了允许简单的属性作为简单的字符串值传递,以便以后进行值转换。

<强>转换

Spring使用ConversionService进行值转换。在其默认设置StringToArrayConverter is used中,遗憾的是将字符串作为逗号分隔列表处理。

怎么做

你对Spring处理单值请求参数的方式非常不满。所以我会手动进行绑定:

// Method annotations
public HttpEntity<CustomOutputObject> handlerMethod(WebRequest request) {
    String[] ingredients = request.getParameterValues("ingredients");
    // Do other stuff 
}

您还可以查看Spring guys have to say about this ..和related SO question

答案 1 :(得分:2)

好吧,你可以注册一个custom conversion service(来自this SO answer),但这似乎很多工作。 :)如果是我,我会忽略方法签名中的@RequestParam声明,并使用传入的request对象解析值。

答案 2 :(得分:1)

我建议您尝试以下格式:

ingredients=egg&ingredients=milk&ingredients=butter

&ingredients附加到末尾将处理数组只有一个值的情况。

ingredients=egg&ingredients=milk&ingredients=butter&ingredients
ingredients=milk,skimmed&ingredients   

需要从数组中删除额外的条目,使用List<String>会使这更容易。

或者,如果您尝试将REST控制器直接导入到spring-data-jpa的数据库中,则应该查看spring-data-rest。这是一个example

您基本上使用@RepositoryRestResource注释您的存储库,而其余的则使用spring:)

答案 3 :(得分:0)

来自here

的解决方案
public String get(WebRequest req) {
    String[] ingredients = req.getParameterValues("ingredients");
    for(String ingredient:ingredients ) {
        System.out.println(ingredient);
    }
    ...
}

这适用于包含逗号

的单一成分的情况