将snake_case请求参数绑定到Spring表单

pgvzfuti  于 2023-04-10  发布在  Spring
关注(0)|答案(2)|浏览(223)

我正在使用Sping Boot 实现一个简单的RESTful服务,其接口由.NET(我认为)客户端定义。它们的参数名称是snake_case,而不是camelCase,这显然意味着我需要自定义它们的Map方式。
在JSON输入/输出的情况下,这很好,我刚刚定制了ObjectMapper,如下所示:

  1. @Bean
  2. public ObjectMapper objectMapper() {
  3. ObjectMapper objectMapper = new ObjectMapper();
  4. objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
  5. return objectMapper;
  6. }

这很好。现在我的问题是表单数据。我有一个Spring表单,如下所示:

  1. public class MyForm {
  2. private String myValue;
  3. public String getMyValue() {return myValue;}
  4. public void setMyValue(String myValue) {this.myValue = myValue;}
  5. }

但是我需要接受的请求看起来像:

  1. POST /foo/bar HTTP/1.1
  2. Host: localhost:8080
  3. Content-Type: application/x-www-form-urlencoded
  4. my_value=5

我觉得Spring的binding中一定有一些简单的hook,就像Jackon的ObjectMapper中的等效设置一样,但我很难找到一个。我在这里能找到的唯一一些相关的帖子是this one, about completely changing the parameter names,其中有一些建议,对于我的用例来说似乎有些矫枉过正。
简单的解决方案是对MyForm中的字段使用snake case,它工作得很好,但有点难看。
我在其他地方看到的最后一个建议是使用拦截器来修改请求参数,这看起来很简单,但感觉肯定会有异常,使其变得不平凡,我担心将代码隐藏在拦截器中,当你遇到一个模糊的情况时,它真的很难找到。
是否有一些“适当的”Spring Y方式来处理我所错过的问题,或者我只需要选择上述不太完美的解决方案之一?

w1e3prcc

w1e3prcc1#

可能你已经解决了这个问题,我今天在StackOverflow PT上回答了一个问题。
所以我们做个交易
在请求到达控制器之前创建一个要执行的过滤器,并相应地设置参数的格式(在我的场景中,从snake case到camel case)。

光说不练,给我看代码!

  1. import java.io.IOException;
  2. import java.util.Collections;
  3. import java.util.Enumeration;
  4. import java.util.Map;
  5. import java.util.concurrent.ConcurrentHashMap;
  6. import javax.servlet.Filter;
  7. import javax.servlet.FilterChain;
  8. import javax.servlet.ServletException;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletRequestWrapper;
  11. import javax.servlet.http.HttpServletResponse;
  12. import org.springframework.context.annotation.Bean;
  13. import org.springframework.context.annotation.Configuration;
  14. import org.springframework.web.filter.OncePerRequestFilter;
  15. import com.google.common.base.CaseFormat;
  16. @Configuration
  17. public class AppConfig {
  18. @Bean
  19. public Filter snakeConverter() {
  20. return new OncePerRequestFilter() {
  21. @Override
  22. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
  23. throws ServletException, IOException {
  24. final Map<String, String[]> formattedParams = new ConcurrentHashMap<>();
  25. for (String param : request.getParameterMap().keySet()) {
  26. String formattedParam = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, param);
  27. formattedParams.put(formattedParam, request.getParameterValues(param));
  28. }
  29. filterChain.doFilter(new HttpServletRequestWrapper(request) {
  30. @Override
  31. public String getParameter(String name) {
  32. return formattedParams.containsKey(name) ? formattedParams.get(name)[0] : null;
  33. }
  34. @Override
  35. public Enumeration<String> getParameterNames() {
  36. return Collections.enumeration(formattedParams.keySet());
  37. }
  38. @Override
  39. public String[] getParameterValues(String name) {
  40. return formattedParams.get(name);
  41. }
  42. @Override
  43. public Map<String, String[]> getParameterMap() {
  44. return formattedParams;
  45. }
  46. }, response);
  47. }
  48. };
  49. }
  50. }

snakeConverter做魔术。
在那里,doFilterInternal总是在请求到达控制器之前执行,参数以其格式化形式存储在新的Map中,并通过filterChain.doFilter转发到控制器。
HttpServletRequestWrapper负责为控制器提供新参数。
此代码完全基于azhawkes过滤器。
使用以下URL中的简单控制器测试它:http://localhost:8080/snakecase?foo_bar=123

展开查看全部
eivnm1vs

eivnm1vs2#

只需将其添加到Sping Boot 项目中的application.properties即可

  1. spring.jackson.property-naming-strategy=SNAKE_CASE

如果你在寻找一个指南,我从这个Article on BeyondCode得到了这个答案

相关问题