前言 使用SpringBoot查询数据库,数据库中字段是首字母大写,实体类中也是使用了首字母大写,但是返回前端的数据json字符串时,出现了大写字母变为小写字母的情况。比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Autowired private MediumRepo mediumRepo;@Autowired private GroupInfoRepo groupInfoRepo;@RequestMapping(value = "siteList") public JSONObject siteList () { JSONObject result=new JSONObject (); try { List<Medium> mediumList=mediumRepo.findAll(); JSONObject mediumObj=new JSONObject (); JSONObject tempObj=new JSONObject (); mediumList.stream().forEach(medium -> { mediumObj.put(medium.getMediumType().toString(),medium); }); result.put("mediumList" ,mediumObj); List<GroupInfo> groupInfos=groupInfoRepo.findAll(); JSONObject groupObj=new JSONObject (); groupInfos.stream().forEach(groupInfo -> { groupObj.put(groupInfo.getGroupId().toString(),groupInfo.getGroupName()); }); result.put("groupList" ,groupObj); }catch (Exception e){ logger.error("siteList" ,e); } return result; }
最后返回给前台的json字符串清一色的首字母变成了小写。
参考文章: 【1】.SpringBoot统一响应,拦截Response返回 【2】.Spring MVC 切面 ResponseBodyAdvice 对响应/返回值增强、API接口数据统一格式返回
[解决方式]
1.在属性上添加@JsonProperty注解 在属性上添加@JsonProperty注解,在set和get方法上添加@JsonIgnore,@JsonProperty和@JsonIgnore一起使用,只使用一个无效。
1 2 3 4 5 6 7 8 9 10 11 @JsonProperty(value = "MediumStr") private String MediumStr;@JsonIgnore public String getMediumStr () { return MediumStr; } public void setMediumStr (String mediumStr) { MediumStr = mediumStr; }
参考文章: 【1】.Java中JSONField字段大小写失效的问题解决 (这里有一个就是使用了set函数,没发现什么区别) 【2】.Springboot @JSONField返回json首字母大写不生效 (这里只使用了一个@JsonProperty)
2.直接将@JsonProperty注解到get,set方法上 1 2 3 4 @JsonProperty(value = "MediumStr") public String getMediumStr () { return MediumStr; }
3.使用FastJSON替换默认的json转换器 根据参考文章4和5,还可以使用FastJSON替换默认的json转换器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package com.bibichuan.phemsjava.boot;import com.alibaba.fastjson.serializer.SerializerFeature;import com.alibaba.fastjson.support.config.FastJsonConfig;import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import org.springframework.web.servlet.config.annotation.CorsRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.Iterator;import java.util.List;@Configuration public class WebMvcCon implements WebMvcConfigurer { @Override public void addCorsMappings (CorsRegistry registry) { registry.addMapping("/**" ) .allowedOrigins("*" ) .allowCredentials(true ) .allowedMethods("GET" , "POST" , "DELETE" , "PUT" ,"PATCH" ) .maxAge(3600 ); } @Override public void configureMessageConverters (List<HttpMessageConverter<?>> converters) { Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); while (iterator.hasNext()){ HttpMessageConverter<?> converter = iterator.next(); if (converter instanceof MappingJackson2HttpMessageConverter){ iterator.remove(); } } FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter (); FastJsonConfig fastJsonConfig=new FastJsonConfig (); fastJsonConfig.setSerializerFeatures( SerializerFeature.PrettyFormat ); fastConverter.setFastJsonConfig(fastJsonConfig); converters.add(fastConverter); } @Override public void extendMessageConverters (List<HttpMessageConverter<?>> converters) { for (HttpMessageConverter<?> messageConverter : converters) { System.out.println(messageConverter); } } }
参考文章: 【1】.springboot中jackJson返回的json大写变小写 【2】.SpringBoot | 返回Json实体类属性大小写问题 【3】.spring boot json 首字母大小写问题解决方案 【4】.springboot2.0配置WebMvcConfigurer的configureMessageConverters方法不启用 【5】.记一次踩坑:springboot2.0.2配置fastjson不生效 【6】.Spring Boot项目中如何定制HTTP消息转换器
问题: (1) Spring Boot配置FastJson报错’Content-Type’ cannot contain wildcard type ‘*’
在WebMvcCon类中增加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 @Override public void configureMessageConverters (List<HttpMessageConverter<?>> converters) { Iterator<HttpMessageConverter<?>> iterator = converters.iterator(); while (iterator.hasNext()){ HttpMessageConverter<?> converter = iterator.next(); if (converter instanceof MappingJackson2HttpMessageConverter){ iterator.remove(); } } FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter (); FastJsonConfig config = new FastJsonConfig (); config.setSerializerFeatures(SerializerFeature.QuoteFieldNames, SerializerFeature.PrettyFormat, SerializerFeature.WriteEnumUsingToString, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.DisableCircularReferenceDetect); List<MediaType> supportedMediaTypes = new ArrayList <>(); supportedMediaTypes.add(MediaType.APPLICATION_JSON); supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); supportedMediaTypes.add(MediaType.APPLICATION_ATOM_XML); supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM); supportedMediaTypes.add(MediaType.APPLICATION_PDF); supportedMediaTypes.add(MediaType.APPLICATION_RSS_XML); supportedMediaTypes.add(MediaType.APPLICATION_XHTML_XML); supportedMediaTypes.add(MediaType.APPLICATION_XML); supportedMediaTypes.add(MediaType.IMAGE_GIF); supportedMediaTypes.add(MediaType.IMAGE_JPEG); supportedMediaTypes.add(MediaType.IMAGE_PNG); supportedMediaTypes.add(MediaType.TEXT_EVENT_STREAM); supportedMediaTypes.add(MediaType.TEXT_HTML); supportedMediaTypes.add(MediaType.TEXT_MARKDOWN); supportedMediaTypes.add(MediaType.TEXT_PLAIN); supportedMediaTypes.add(MediaType.TEXT_XML); fastConverter.setSupportedMediaTypes(supportedMediaTypes); fastConverter.setFastJsonConfig(config); converters.add(fastConverter); }
(2) 不知道为什么,还是返回的是小写字母。就算单独写一个Bean也是不行的。不知道什么原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.bibichuan.phemsjava.boot;import com.alibaba.fastjson.serializer.SerializerFeature;import com.alibaba.fastjson.support.config.FastJsonConfig;import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import org.springframework.boot.autoconfigure.http.HttpMessageConverters;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.MediaType;import java.util.ArrayList;import java.util.List;@Configuration public class MessageConverConf { @Bean public HttpMessageConverters fastJsonHttpMessageConverters () { FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter (); FastJsonConfig fastJsonConfig = new FastJsonConfig (); fastJsonConfig.setSerializerFeatures( SerializerFeature.PrettyFormat, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty ); List<MediaType> fastMediaTypes = new ArrayList <MediaType>(); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); fastConverter.setSupportedMediaTypes(fastMediaTypes); fastConverter.setFastJsonConfig(fastJsonConfig); return new HttpMessageConverters (fastConverter); } }
(3) 原来是要在@Entity注解的实体类的属性上使用 @JSONField(name=”SiteNo”) ,就可以实现了首字母大写。
进一步的问题,如果我不使用每一个属性都多加一个@JSONField注解的方式,实现直接的进行首字母大写转换。
参考文章: 【1】.Spring Boot配置FastJson报错’Content-Type’ cannot contain wildcard type ‘*’ 【2】.解决fastjson出现java.lang.IllegalArgumentException:’Content-Type’ cannot contain wildcardt * 【3】.fastjson SerializerFeature详解 【4】.使用自定义HttpMessageConverter对返回内容进行加密 【5】.spring boot json 首字母大小写问题解决方案 【6】.Springboot2配置FastJsonHttpMessageConverter不生效,FastJsonHttpMessageConverter返回类型字符串String中文乱码问题 【7】.SpringBoot | 返回Json实体类属性大小写问题
(4) 使用@JsonProperty注解之后,虽然将返回的字段首字母进行了大小,但是出现新的问题,就是小写的字段还是存在,也就是返回了两个数据,一个大写,一个小写
【解决方法】 如果放到属性上不起作用,或者同时返回了大小写,那么就尝试放在get方法上
参考文章: 【1】.解决@JsonProperty不生效的问题 【2】.@JsonProperty 失效问题的排查 (这里提到了在引入fastjson时,如何使JsonProperty生效,一个就是使用启动类上添加@EnableWebMvc,一个就是禁用fastjson) 【3】.SpringBoot 返回Json实体类属性大小写问题 (如果注解放到属性上,则返回的时候既有大写也有小写。解决方法就是注解放到getter上) 【4】.SpringBoot解决驼峰命名 —返回Json实体类属性大小写问题 (这里也提到了返回大小写的问题,一个就是放到get上,一个就是使用fastjson进行序列化) 【5】.用jackson的@JsonProperty注解属性名,会多出一个字段 【6】.如何解决SpringBoot 返回Json类属性大小写 这里也是返回的大小写都存在,如果没有使用fastjson(阿里巴巴出品),使用@JsonProperty(“XXXX”)的注解方式可以解决问题,XXXX就是转换成Json的属性名,但注意,只有放在getter上才是有效的,直接在属性上加没效果.(这说明spring 默认的jackson类库处理是基于访问器。
4.Spring的PropertyNamingStrategy配置 随着进一步资料查询,可以配置命名策略,我发现了一个在application.yml中通过配置PropertyNamingStrategy方法。答案是有的。只需要配置application.yml内容:
1 2 3 spring: jackson: property-naming-strategy: UPPER_CAMEL_CASE
还有其他的一些命名策略:
(1) LOWER_CASE
Naming convention in which all words of the logical name are in lower case, and no separator is used between words.
(2) KEBAB_CASE
Naming convention used in languages like Lisp, where words are in lower-case letters, separated by hyphens.
(3) LOWER_CAMEL_CASE
Naming convention used in Java, where words other than first are capitalized and no separator is used between words.
(4) LOWER_CASE
Naming convention in which all words of the logical name are in lower case, and no separator is used between words.
(5) SNAKE_CASE
Naming convention used in languages like C, where words are in lower-case letters, separated by underscores.
有下面几种方式: (1)属性名称:@JsonProperty (2)预定义命名策略,只需要作用于某个类:@JsonNaming (3)自定义命名策略:PropertyNamingStrategy
参考文章: 【1】.Jackson使用PropertyNamingStrategy处理属性首字母为大写的情况 【2】.Class PropertyNamingStrategy 【3】.spring.jackson.property-naming-strategy 【4】.springboot 针对jackson配置 【5】.Spring Boot Jackson命名策略
5.使用Bean注入的方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.bibichuan.phemsjava.boot;import com.fasterxml.jackson.annotation.JsonInclude;import com.fasterxml.jackson.core.JsonGenerator;import com.fasterxml.jackson.core.JsonParser;import com.fasterxml.jackson.databind.DeserializationFeature;import com.fasterxml.jackson.databind.JsonSerializer;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.SerializerProvider;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;import java.io.IOException;@Configuration public class BeanConf { @Bean @Primary @ConditionalOnMissingBean(ObjectMapper.class) public ObjectMapper jacksonObjectMapper (Jackson2ObjectMapperBuilder builder) { ObjectMapper objectMapper = builder.createXmlMapper(false ).build(); objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true ); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true ); objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer <Object>() { @Override public void serialize (Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString("" ); } }); return objectMapper; } }
参考文章: 1.springboot 针对jackson配置 2.Jackson修改字段名和自定义命名策略 3.jackson根据属性名动态序列化对象字段 4.Jackson序列化方式实现数据字段脱敏(工厂模式 + 策略模式) 1.基于Jaskson 序列化:针对需要展示在前端的数据 通常我们都是对应一个VO对象,这里可以在将VO对象返回给前端序列化时进行数据的脱敏;2.基于Mybatis 的拦截器:对select 语句进行拦截数据脱敏,但是存在问题 在某些业务中对数据脱敏字段是需要进行逻辑业务处理的。
总结 基础知识还是不牢啊,总是出现问题再去找答案,非常的浪费时间,需要系统性,综合性的对SpringBoot进行学习,才能进行更好的开发。
6.@RequestBody属性名大写注入为空 参考文章: 【1】.spring中使用@RequestBody,对应的bean中属性名大写注入为空的解决方法 (也是通过在属性上使用@JsonProperty注解完成)
7.使用@JSONFiled 使用这个注解主要就是在使用FastJSON序列化的时候,出现首字母大写变小写的问题。在fastjson1.x的时候,在属性上注解@JSONField就可以指定序列化的时候的内容,但是在FastJSON2.x的时候,这个注解注解到属性上不再起作用了,必须要注解到getter方法上,这个暂时还没有解决
参考文章: 【1】.fastjson转换json时,碰到的那些首字母大小写转换的坑!
8.自定义命名策略 编写自定义命名策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class CustomPropertyNamingStrategy extends PropertyNamingStrategies .NamingBase { @Override public String nameForField (MapperConfig<?> config, AnnotatedField field, String defaultName) { return translate(defaultName); } @Override public String nameForGetterMethod (MapperConfig<?> config, AnnotatedMethod method, String defaultName) { return translate(defaultName); } @Override public String translate (String input) { return input; } }
ObjectMapper 注入自定义命名策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 @Configuration public class SpringBeanConfiguration { @Bean public ObjectMapper objectMapper () { ObjectMapper objectMapper = new ObjectMapper (); objectMapper.setPropertyNamingStrategy(new CustomPropertyNamingStrategy ()); objectMapper.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN); objectMapper.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); objectMapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false ); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false ); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES, false ); objectMapper.setDateFormat(new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss" )); JavaTimeModule javaTimeModule = new JavaTimeModule (); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer (DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" ))); javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer (DateTimeFormatter.ofPattern("yyyy-MM-dd" ))); javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer (DateTimeFormatter.ofPattern("HH:mm:ss" ))); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer (DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss" ))); javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer (DateTimeFormatter.ofPattern("yyyy-MM-dd" ))); javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer (DateTimeFormatter.ofPattern("HH:mm:ss" ))); objectMapper.registerModule(javaTimeModule); return objectMapper; } }
参考文章: 【1】.jackson自定义策略 一.属性名称@JsonProperty;二 .预定义命名策略PropertyNamingStrategy;三.自定义PropertyNamingStrategy 【2】.Jackson修改字段名和自定义命名策略 通过实现 PropertyNamingStrategyBase 进行自定义命名策略的实现
9.StdSerializer 使用 StdSerializer 注入自定义的序列化和反序列化的类,实现单独对某一个类进行特殊的序列化。
参考文章: 【1】.spring/jackson:实现对保存JSON字符串的字段自动序列化和反序列化 【2】.springboot只对某个特定的类或属性进行自定义的序列化和反序列化操作