繁体   English   中英

如何在 SpringBoot 中为 RestTemplate 设置 PropertyNamingStrategy?

[英]How to set PropertyNamingStrategy for RestTemplate in SpringBoot?

我写了一个 SpringBoot 应用程序,它消耗了一个 rest api 并呈现了一个 rest api。 我的模型 pojo 具有驼峰命名的属性。 应用程序使用的 json 具有 under_score 属性名称。 应用程序生成的 json 具有 under_score 属性名称。 我想使用一个 PropertyNamingStrategy,它将在编组/解组期间自动在 Java 和 json 名称之间进行转换。

我有 Java 配置,尝试设置可以处理此问题的命名策略;

/**
 * Configuration for Rest api.
 * <p>
 * Created by emurphy on 2/25/16.
 */
@Configuration
    public class RestConfig
    {
        /**
         * Bean to make jackson automatically convert from
         * camelCase (java) to under_scores (json) in property names
         *
         * @return ObjectMapper that maps from Java camelCase to json under_score names
         */
        @Bean
        public ObjectMapper jacksonObjectMapper()
        {
            return new ObjectMapper().setPropertyNamingStrategy(new UpperCaseUnderscoreStrategy());
        }

        /**
         * Property naming strategy that converts both ways between camelCase and under_score
         * property names.
         */
        public static class UpperCaseUnderscoreStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase
        {
            /**
             * Converts camelCase to under_score and
             * visa versa.  The idea is that this
             * name strategy can be used for both
             * marshalling and unmarshaling.
             *
             * For example, "userName" would be converted to
             * "user_name" and conversely "user_name" would
             * be converted to "userName".
             *
             * @param input formatted as camelCase or under_score string
             * @return input converted to opposite format
             */
            @Override
            public String translate(String input)
            {
                if (input == null || input.length() == 0)
                {
                    return input; // garbage in, garbage out
                }

                //
                // we always take the first character;
                // this preserves initial underscore
                //
                StringBuilder sb = new StringBuilder();

                final int length = input.length();
                int i = 0;  

                //
                // skip initial underscores
                //
                while ((i < length) && ('_' == input.charAt(i)))
                {
                    sb.append(input.charAt(i));
                    i += 1;
                }

                while (i < length)
                {
                    //
                    // find underscores, remove and capitalize next letter
                    //
                    while ((i < length) && ('_' != input.charAt(i)) && !Character.isUpperCase(input.charAt(i)))
                    {
                        sb.append(input.charAt(i));
                        i += 1;
                    }

                    if(i < length)
                    {
                        if('_' == input.charAt(i))
                        {
                            // underscore to uppercase

                            //
                            // skip underscores
                            //
                            while ((i < length) && ('_' == input.charAt(i)))
                            {
                                // skip underscores
                                i += 1;
                            }

                            //
                            // capitalize
                            //
                            if (i < length)
                            {
                                sb.append(Character.toUpperCase(input.charAt(i)));
                                i += 1;
                            }
                        }
                        else // uppercase to unscore + lowercase
                        {
                            sb.append('_');
                            sb.append(Character.toLowerCase(input.charAt(i)));
                            i += 1;
                        }
                    }
                }
                return sb.toString();
            }
        }

当我的休息服务将 Java pojos 转换为 json 以进行响应时,我可以看到命名策略的 translate 方法被调用。 但是,当我通过 RestTemplate 使用 rest api 时,我没有看到它被调用,并且我生成的 pojo 没有从传入的 json 正确初始化; 名称需要翻译的所有属性都为空。 这迫使我在大多数属性上使用 @JsonProperty。 我有很多属性和很多 pojos - 这是 SpringBoot 应该提供帮助的一种非常不优雅的样板解决方案。 有没有办法设置一个 PropertyNamingStrategy,RestTemplate 将使用它来将传入的 json 名称从 under_score 转换为 camelCase?

感谢您的帮助。

创建RestTemplate您需要将objectMapper设置为您的。 此外,您应该将自定义 ObjectMapper 声明为@Bean以便 Spring 将其构造为单例并为您管理。 PropertyNamingStrategy做同样的事情,而不是“更新”它并将类声明为静态。

public class RestConfig
{
    /**
     * Bean to make jackson automatically convert from
     * camelCase (java) to under_scores (json) in property names
     *
     * @return ObjectMapper that maps from Java camelCase to json under_score names
     */
    @Bean
    public ObjectMapper jacksonObjectMapper()
    {
        return new ObjectMapper().setPropertyNamingStrategy(propertyNamingStrategy());
    }

    @Bean
    public PropertyNamingStrategy propertyNamingStrategy()
    {
        return new UpperCaseUnderscoreStrategy();
    }

    @Bean
    public RestTemplate restTemplate() {
       RestTemplate restTemplate = new RestTemplate();
       List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
       MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
       jsonMessageConverter.setObjectMapper(jacksonObjectMapper());
       messageConverters.add(jsonMessageConverter);
       restTemplate.setMessageConverters(messageConverters); 

       return restTemplate;
    }
}

你的班级在一个单独的文件中? 它不需要是静态的。

    /**
     * Property naming strategy that converts both ways between camelCase and under_score
     * property names.
     */
    public static class UpperCaseUnderscoreStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase
    {
        /**
         * Converts camelCase to under_score and
         * visa versa.  The idea is that this
         * name strategy can be used for both
         * marshalling and unmarshaling.
         *
         * For example, "userName" would be converted to
         * "user_name" and conversely "user_name" would
         * be converted to "userName".
         *
         * @param input formatted as camelCase or under_score string
         * @return input converted to opposite format
         */
        @Override
        public String translate(String input)
        {
            if (input == null || input.length() == 0)
            {
                return input; // garbage in, garbage out
            }

            //
            // we always take the first character;
            // this preserves initial underscore
            //
            StringBuilder sb = new StringBuilder();

            final int length = input.length();
            int i = 0;  

            //
            // skip initial underscores
            //
            while ((i < length) && ('_' == input.charAt(i)))
            {
                sb.append(input.charAt(i));
                i += 1;
            }

            while (i < length)
            {
                //
                // find underscores, remove and capitalize next letter
                //
                while ((i < length) && ('_' != input.charAt(i)) && !Character.isUpperCase(input.charAt(i)))
                {
                    sb.append(input.charAt(i));
                    i += 1;
                }

                if(i < length)
                {
                    if('_' == input.charAt(i))
                    {
                        // underscore to uppercase

                        //
                        // skip underscores
                        //
                        while ((i < length) && ('_' == input.charAt(i)))
                        {
                            // skip underscores
                            i += 1;
                        }

                        //
                        // capitalize
                        //
                        if (i < length)
                        {
                            sb.append(Character.toUpperCase(input.charAt(i)));
                            i += 1;
                        }
                    }
                    else // uppercase to unscore + lowercase
                    {
                        sb.append('_');
                        sb.append(Character.toLowerCase(input.charAt(i)));
                        i += 1;
                    }
                }
            }
            return sb.toString();
        }
    }

只需在您将在请求响应中发送或接收的 POJO 上方添加此注释。

@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)

PS,策略可以根据要求而有所不同。

一个简短的答案是使用 Spring 的 objectMapper。 好处是它在application.properties共享相同的配置。 因此,您可以设置spring.jackson.property-naming-strategy=SNAKE_CASE或其他任何内容,并且在包括 RestTemplate 在内的整个应用程序中都是一致的。 代码如下。

@Configuration
@RequiredArgsConstructor
public class HTTPConfig {
    public final ObjectMapper objectMapper;  // provided by spring

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplateBuilder()
            .messageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
            .build();
    }
}

我建议你使用这个方法。 您也可以将其添加为弹簧豆。

private RestTemplate getRestTemplate() {

    final RestTemplate restTemplate = new RestTemplate();
    final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    final MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
    jsonMessageConverter.setObjectMapper(new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE));
    messageConverters.add(jsonMessageConverter);
    restTemplate.setMessageConverters(messageConverters);

    return restTemplate;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM