本来想加一个Jackson的配置类修改ObjectMapper实现把null转空字符串或空数组,但是加上之后发现没效果,找不到问题在哪里,不知道是不是我使用@RestControllerAdvice全局返回处理类的问题,所以就自己写了一个工具类方法处理,就在全局返回处理类里面调用
找到配置不生效的问题在哪里了,见springboot中添加Jackson配置类不生效
全局返回处理类是用kotlin写的,用来封装统一响应实体和处理全局异常的,用java也是一样的,语法换成java就行。当然,这不是这篇的博文重点,重点是处理null的方法
package com.gt.gxjhpt.configuration
import cn.dev33.satoken.exception.NotLoginException
import cn.dev33.satoken.exception.NotPermissionException
import cn.dev33.satoken.exception.NotRoleException
import cn.hutool.json.JSONUtil
import com.gt.gxjhpt.entity.RestfulResp
import com.gt.gxjhpt.enumeration.RespCodeEnum
import com.gt.gxjhpt.exception.MyException
import com.gt.gxjhpt.utils.MyUtils
import org.springframework.core.MethodParameter
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.converter.HttpMessageConverter
import org.springframework.http.server.ServerHttpRequest
import org.springframework.http.server.ServerHttpResponse
import org.springframework.http.server.ServletServerHttpResponse
import org.springframework.validation.BindException
import org.springframework.web.bind.MethodArgumentNotValidException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseStatus
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice
import javax.validation.ConstraintViolationException
@RestControllerAdvice
class GlobalResponseBodyAdvice : ResponseBodyAdvice {
override fun supports(returnType: MethodParameter, converterType: Class>): Boolean {
return true
}
override fun beforeBodyWrite(
body: Any?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Any? {
return when (body) {
is RestfulResp<*> -> body
is String -> JSONUtil.toJsonStr(RestfulResp().success(body))
null -> RestfulResp().success()
else -> {
val httpResponse = response as ServletServerHttpResponse
if (httpResponse.servletResponse.status.equals(200)) {
// 设置null值为空字符串或空数组
MyUtils.setNullValue(body)
return RestfulResp().success(body)
} else {
return body
}
}
}
}
//其他参数异常
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = [BindException::class])
fun handleBindException(): RestfulResp<*>? {
return RestfulResp().enumResp(RespCodeEnum.PARAM_ERR)
}
//parameter异常
//为了安全,就不将报错信息返回到前端,只返回粗略信息
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = [ConstraintViolationException::class])
fun handleValidationException(): RestfulResp<*>? {
return RestfulResp().enumResp(RespCodeEnum.PARAM_ERR)
}
//bean异常
//为了安全,就不将报错信息返回到前端,只返回粗略信息
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(value = [MethodArgumentNotValidException::class])
fun handleMethodArgumentNotValidException(ex: MethodArgumentNotValidException?): RestfulResp<*>? {
return RestfulResp().enumResp(RespCodeEnum.PARAM_ERR)
}
//我的自定义异常
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(
MyException::class
)
fun myException(e: MyException): RestfulResp<*>? {
e.printStackTrace()
return if (e.msg != null) {
RestfulResp().error(e.msg, e.code)
} else if (e.respCodeEnum != null) {
RestfulResp().enumResp(e.respCodeEnum)
} else {
RestfulResp().unknown()
}
}
//运行时异常
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(
RuntimeException::class
)
fun runtimeException(e: RuntimeException): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown(e.message)
}
//空指针异常
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(
NullPointerException::class
)
fun nullPointerException(e: NullPointerException): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown("空指针-->>" + e.stackTrace[0].toString())
}
//未知异常
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(
Exception::class
)
fun exception(e: Exception): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown(e.message)
}
// 未提供token
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(value = [NotLoginException::class])
fun exception(e: NotLoginException): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown(e.message)
}
// 无角色
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(
NotRoleException::class
)
fun exception(e: NotRoleException): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown(e.message)
}
// 无权限
@ResponseStatus(HttpStatus.FORBIDDEN)
@ExceptionHandler(
NotPermissionException::class
)
fun exception(e: NotPermissionException): RestfulResp<*>? {
e.printStackTrace()
return RestfulResp().unknown(e.message)
}
}
处理null的方法,不需要继续递归的类型,要写在第一个else if条件里面,工具类使用hutool
public static void setNullValue(Object body) throws IllegalAccessException, InstantiationException {
Class> aClass = body.getClass();
if (Collection.class.isAssignableFrom(aClass)) {
for (Object it : Convert.toList(body)) {
MyUtils.setNullValue(it);
}
} else if (String.class.isAssignableFrom(aClass) || NumberUtil.isNumber(body.toString())
|| BooleanUtil.isBoolean(aClass) || CharUtil.isChar(body) || Date.class.isAssignableFrom(aClass)) {
} else if (Map.class.isAssignableFrom(aClass)) {
Map objectMap = Convert.toMap(String.class, Object.class, body);
objectMap.forEach((k, v) -> {
try {
if (v == null) {
v = "";
} else {
MyUtils.setNullValue(v);
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
objectMap.put(k, v);
});
} else { // 自定义响应对象
List fields = CollUtil.toList(aClass.getDeclaredFields());
// 父类属性
Class> superclass = aClass.getSuperclass();
while (superclass != null && superclass != Object.class) {
fields.addAll(CollUtil.toList(superclass.getDeclaredFields()));
superclass = superclass.getSuperclass();
}
for (Field field : fields) {
// 取消权限检查
field.setAccessible(true);
Object value = field.get(body);
if (value == null) {
if (Collection.class.isAssignableFrom(field.getType())) {
field.set(body, new ArrayList<>());
} else if (String.class.isAssignableFrom(field.getType())) {
field.set(body, "");
}
} else {
MyUtils.setNullValue(value);
}
}
}
}