前后端交互时将返回值中的null置为空字符串的8种方式(亲测有效)

返回给前端的Json对象中有很多字段没有值,就会有很多的null值(如下图)

 前端判断处理会比较麻烦,所以打算在后端回传数据时做一下处理:

1、字符串null值置为空字符串

2、空List转为[]

3、封装数字类型null转为0

4、Boolean类型null转为false

先看想要达到的效果:

 一、通过继承WebMvcConfigurationSupport,重写configureMessageConverters方法实现

@Configuration
public class MyJsonConfig extends WebMvcConfigurationSupport {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(
                //json格式输出
                SerializerFeature.PrettyFormat,
                // 保留map为空的字段
                SerializerFeature.WriteMapNullValue,
                // 将String类型的null转成""形式
                SerializerFeature.WriteNullStringAsEmpty,
                // 将Number类型的null转成0
                SerializerFeature.WriteNullNumberAsZero,
                // 将List类型的null转成[],而不是""
                SerializerFeature.WriteNullListAsEmpty,
                // Boolean类型的null转成false
                SerializerFeature.WriteNullBooleanAsFalse,
                // 处理可能循环引用的问题
                SerializerFeature.DisableCircularReferenceDetect);
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        List<MediaType> mediaTypeList = new ArrayList<>();
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        converter.setSupportedMediaTypes(mediaTypeList);
        converters.add(converter);
    }
}

二、通过实现WebMvcConfigurer,重写configureMessageConverters方法实现

@Configuration
public class BaseMvcConfig implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        /**
         * 序列换成Json时,将所有的Long变成String
         * 因为js中得数字类型不能包括所有的java Long值
         */
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        // 所有的double类型返回保留三位小数
        simpleModule.addSerializer(Double.class, CustomerDoubleSerialize.instance);
        simpleModule.addSerializer(Double.TYPE, CustomerDoubleSerialize.instance);

        objectMapper.registerModule(simpleModule);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(jackson2HttpMessageConverter);
    }
}

三、在Springboot启动类中注入Bean---FastJson

@Bean
public HttpMessageConverters fastJsonConverters() {
	FastJsonHttpMessageConverter4 fastConverter = new FastJsonHttpMessageConverter4();
	FastJsonConfig fastJsonConfig = new FastJsonConfig();
	fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.IgnoreNonFieldGetter,
			SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty);
	fastConverter.setFastJsonConfig(fastJsonConfig);
	List supportedMediaTypes = new ArrayList();
	supportedMediaTypes.add(new MediaType("text", "json", Charset.forName("utf8")));
	supportedMediaTypes.add(new MediaType("application", "json", Charset.forName("utf8")));
	fastConverter.setSupportedMediaTypes(supportedMediaTypes);
	HttpMessageConverter<?> converter = fastConverter;
	return new HttpMessageConverters(converter);
}

四、在Springboot启动类中注入Bean---Jackson

@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
	MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
	List<MediaType> supported = new ArrayList<>();
	supported.add(MediaType.APPLICATION_JSON_UTF8);
	mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supported);

	// JsonMapper
	ObjectMapper objectMapper = new ObjectMapper();

	// null值的处理,必须要放在第一步,否则会将下面的日期格式化覆盖掉  null ==> ""
	objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
		@Override
		public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
			gen.writeString("");
		}
	});

	// 处理默认日期格式化:yyyy-MM-dd HH:mm:ss
	objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
	objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
	objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

	mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
	return mappingJackson2HttpMessageConverter;
}

五、使用fastjson的toJSONString方式

/**
 * @Description: 将java对象的null值置空,转成JSON对象
 * @Parameters: Object 任意java对象
 * @Return: JSONObject 返回fastjson的JSON对象
 * @Auther: WZH
 * @Date: 2021/1/15 9:54
 */
public static JSONObject nullToEmptyJson(Object object){
	String returnString = JSONObject.toJSONString(object,
			//json格式输出
			SerializerFeature.PrettyFormat,
			// 保留map为空的字段
			SerializerFeature.WriteMapNullValue,
			// 将String类型的null转成""形式
			SerializerFeature.WriteNullStringAsEmpty,
			// 将Number类型的null转成0
			SerializerFeature.WriteNullNumberAsZero,
			// 将List类型的null转成[],而不是""
			SerializerFeature.WriteNullListAsEmpty,
			// Boolean类型的null转成false
			SerializerFeature.WriteNullBooleanAsFalse,
			// 处理可能循环引用的问题
			SerializerFeature.DisableCircularReferenceDetect);
	return JSONObject.parseObject(returnString);
}

六、通过反射判断修改(可根据需要补全其他类型)

public static <T> void  nullToEmpty(T bean){
	Field[] field = bean.getClass().getDeclaredFields();
	//遍历所有属性
	for (Field item : field) {
		//获取属性的名字
		String name = item.getName();
		//将属性的首字符大写,方便构造get,set方法
		name = name.substring(0, 1).toUpperCase() + name.substring(1);
		//获取属性的类型
		String type = item.getGenericType().toString();
		//如果type是类类型,则前面包含"class ",后面跟类名
		if ("class java.lang.String".equals(type)) {
			try {
				Method mGet = bean.getClass().getMethod("get" + name);
				//调用getter方法获取属性值
				String value = (String) mGet.invoke(bean);
				if (value == null || "".equals(value)) {
					Method mSet = bean.getClass().getMethod("set" + name, String.class);
					mSet.invoke(bean, new String(""));
				}
			} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
}

七、在entity实体类或者字段上面加JsonInclude注解,过滤掉NULL值的属性

@JsonInclude(JsonInclude.Include.NON_NULL)

八、直接在entity字段上加JSONField注解,转Json时不返回当前字段

@JSONField(serialize = false)

如何选择:

1、全局生效,添加之后该服务下的所有接口都会生效,选择前四种;

2、针对特定接口使用,作为静态方法根据自己需要加在接口返回前,方式五和六;

3、针对特定实体类或者字段不传null值属性,使用方式七;

4、直接在Json序列化时不传某个字段,使用方式八。

 

  • 13
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的示例代码,帮助你实现所需的功能: 1. 引入 Actuator 相关依赖 在 pom.xml 文件添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> ``` 2. 实现 AOP 切面 首先定义一个自定义注解 `@Monitor`,用于标记需要进行监控的接口方法。接着,定义一个切面 `ApiMonitorAspect`,在该切面实现监控逻辑,包括记录调用次数、记录调用来源等。具体代码如下: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Monitor { } @Aspect @Component public class ApiMonitorAspect { // 定义一个 Map,用于记录接口方法的调用次数 private Map<String, Integer> callCountMap = new ConcurrentHashMap<>(); @Around("@annotation(com.example.demo.annotation.Monitor)") public Object monitorApi(ProceedingJoinPoint joinPoint) throws Throwable { // 获取接口方法的参数和返回值 Object[] args = joinPoint.getArgs(); Object result = joinPoint.proceed(); // 记录接口方法的调用次数 String methodName = joinPoint.getSignature().toShortString(); Integer callCount = callCountMap.get(methodName); if (callCount == null) { callCount = 0; } callCountMap.put(methodName, callCount + 1); // 记录接口方法的调用来源(这里假设调用来源是从 HTTP 头获取的) HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String callSource = request.getHeader("callSource"); // 将调用次数和调用来源写入日志(这里使用 log4j2) Logger logger = LogManager.getLogger(joinPoint.getTarget().getClass()); logger.info("method: {}, callCount: {}, callSource: {}", methodName, callCount + 1, callSource); return result; } // 定义一个定任务,定将接口方法的调用次数写入 MQ @Scheduled(cron = "0 0 * * * ?") public void sendCallCountToMQ() { // 将调用次数转换成 JSON 格式的字符串 ObjectMapper objectMapper = new ObjectMapper(); String callCountJson = null; try { callCountJson = objectMapper.writeValueAsString(callCountMap); } catch (JsonProcessingException e) { e.printStackTrace(); } // 将调用次数发送到 MQ // ... } } ``` 3. 标记需要监控的接口方法 在接口方法上添加 `@Monitor` 注解即可,例如: ```java @RestController public class ApiController { @Autowired private ApiService apiService; @GetMapping("/api") @Monitor public String api(@RequestParam("param") String param) { return apiService.process(param); } } ``` 4. 发送消息到 MQ 使用 Spring Boot 集成的 RabbitMQ 或者 Kafka 组件发送消息即可。以 RabbitMQ 为例,需要在 application.yml 文件添加 RabbitMQ 的配信息,然后在代码使用 RabbitTemplate 发送消息。具体代码如下: ```java @Component public class CallCountSender { @Autowired private RabbitTemplate rabbitTemplate; public void send(String message) { rabbitTemplate.convertAndSend("call_count_exchange", "call_count_key", message); } } ``` 5. 消费 MQ 的消息 首先定义一个消息消费者 `CallCountConsumer`,在该消费者实现消息的消费逻辑,将消费到的消息插入到数据库。具体代码如下: ```java @Component public class CallCountConsumer { @Autowired private CallCountRepository callCountRepository; @RabbitListener(queues = "call_count_queue") public void receive(String message) { ObjectMapper objectMapper = new ObjectMapper(); try { // 将 JSON 格式的字符串转换成 Map Map<String, Integer> callCountMap = objectMapper.readValue(message, new TypeReference<Map<String, Integer>>() {}); // 将调用次数插入到数据库 for (Map.Entry<String, Integer> entry : callCountMap.entrySet()) { CallCount callCount = new CallCount(); callCount.setMethodName(entry.getKey()); callCount.setCallCount(entry.getValue()); callCountRepository.save(callCount); } } catch (IOException e) { e.printStackTrace(); } } } ``` 最后,需要在 application.yml 文件添加 RabbitMQ 的配信息和数据库的配信息。例如: ```yaml spring: rabbitmq: host: localhost port: 5672 username: guest password: guest datasource: url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=Asia/Shanghai username: root password: root ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值