No hay muchos chismes, continúe optimizando el marco de respuesta global unificado de la API Restful para hacer que la interfaz general del proyecto sea escalable.
Si no ha leído los artículos anteriores, lea los artículos anteriores.
SpringBoot define un elegante marco de respuesta de API Restful unificado global
SpringBoot define un elegante marco de respuesta de API Restful unificado global 2
SpringBoot define un marco de respuesta de API Restful unificado global elegante tres
SpringBoot define un elegante marco de respuesta de API Restful unificado global cuatro
SpringBoot define un marco de respuesta de API Restful unificado global elegante cinco
Aquí hay una charla sobre la última versión y algunos problemas que deben solucionarse.
@PostMapping("/add/UserApiCombo")
public R addApiCombo(@RequestBody @Validated UserApplyApiComboDto userApplyApiComboDto) {
userApiComboService.addApiCombo(userApplyApiComboDto);
return R.success();
}
Veamos este código, qué está mal. Devolvimos un conjunto de resultados encapsulados unificados R
, pero controller
no es fácil escribir todo lo siguiente.
- El contenido devuelto no es lo suficientemente claro.
- Toda
controller
escritura de esta manera aumenta la carga de trabajo de la duplicación.
Podemos optimizar así:
Spirng proporciona ResponseBodyAdvice
una interfaz que admite el procesamiento del resultado de retorno de la interfaz antes de que el convertidor de mensajes realice la conversión y, en combinación con @ControllerAdvice
las anotaciones, las funciones anteriores se pueden admitir fácilmente.
package cn.soboys.springbootrestfulapi.common.handler;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.soboys.springbootrestfulapi.common.error.ErrorDetail;
import cn.soboys.springbootrestfulapi.common.resp.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
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.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/12 12:17 下午
* @webSite https://github.com/coder-amiao
* @Slf4j
* @ControllerAdvice
*/
@Slf4j
@ControllerAdvice
public class ResponseResultHandler implements ResponseBodyAdvice<Object> {
/**
* supports方法: 判断是否要执行beforeBodyWrite方法,
* true为执行,false不执行.
* 通过该方法可以选择哪些类或那些方法的response要进行处理, 其他的不进行处理.
*
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
/**
* beforeBodyWrite方法: 对response方法进行具体操作处理
* 实际返回结果业务包装处理
*
* @param body
* @param returnType
* @param selectedContentType
* @param selectedConverterType
* @param request
* @param response
* @return
*/
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof R) {
return body;
} else if (body == null) {
return R.success();
} else if (body instanceof ErrorDetail) {
return body;
} else if (body instanceof String) {
return body;
} else {
return R.success().data(body);
}
}
}
En la controller
devolución real, podemos devolver directamente el contenido de los datos
@GetMapping("/home")
public Student home() {
Student s = new Student();
s.setUserName("Tom");
s.setAge(22);
List hobby = new ArrayList();
hobby.add("抽烟");
hobby.add("喝酒");
hobby.add("烫头");
s.setHobby(hobby);
s.setBalance(2229891.0892);
s.setIdCard("420222199811207237");
return s;
}
La lógica de juicio de errores comerciales en nuestra versión actual no es muy amigable y necesita ser optimizada. Aquí podemos encapsular nuestras propias excepciones comerciales y
usar Assert (afirmación) para encapsular excepciones y hacer que el código sea más elegante.
De acuerdo con el principio de retorno de prioridad de error
Normalmente, nuestro código de excepción comercial se escribe así
// 另一种写法
Order order = orderDao.selectById(orderId);
if (order == null) {
throw new IllegalArgumentException("订单不存在。");
}
Después de usar la optimización de aserciones
Order order = orderDao.selectById(orderId);
Assert.notNull(order, "订单不存在。");
Comparando los dos métodos, es obvio que el primer método es más elegante, mientras que el segundo método es un bloque de código if {…} relativamente feo. Entonces , ¿qué hay detrás del mágico Assert.notNull() ?
Aquí está el código que necesitamos para optimizar
De hecho, muchos marcos tienen herramientas Assert , incluido JAVA JDK. SpringBoot, Spring también tiene su propio Assert
pero no se ajusta a nuestra propia lógica comercial de generación de excepciones, aquí podemos personalizar nuestra propia herramienta Assert .
Echemos un vistazo a un código fuente
public abstract class Assert {
public Assert() {
}
public static void notNull(@Nullable Object object, String message) {
if (object == null) {
throw new IllegalArgumentException(message);
}
}
}
Como puede ver, Assert en realidad nos ayuda a encapsular si {...} , ¿no es asombroso? Aunque simple, es innegable que la experiencia de codificación se ha mejorado al menos un nivel.
Entonces, podemos imitar Assert y escribir una clase de aserción personalizada, pero las excepciones lanzadas después de que falla la aserción no son excepciones integradas como IllegalArgumentException , sino excepciones definidas por nosotros mismos.
- definir excepción pública
package cn.soboys.springbootrestfulapi.common.exception;
import cn.soboys.springbootrestfulapi.common.resp.ResultCode;
import lombok.Data;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/6/12 10:32 下午
* @webSite https://github.com/coder-amiao
*/
@Data
public class BaseException extends RuntimeException {
/**
* 返回码
*/
protected ResultCode resultCode;
/**
* 异常消息参数
*/
protected Object[] args;
public BaseException(ResultCode resultCode) {
super(resultCode.getMessage());
this.resultCode = resultCode;
}
public BaseException(String code, String msg) {
super(msg);
this.resultCode = new ResultCode() {
@Override
public String getCode() {
return code;
}
@Override
public String getMessage() {
return msg;
}
@Override
public boolean getSuccess() {
return false;
}
;
};
}
public BaseException(ResultCode resultCode, Object[] args, String message) {
super(message);
this.resultCode = resultCode;
this.args = args;
}
public BaseException(ResultCode resultCode, Object[] args, String message, Throwable cause) {
super(message, cause);
this.resultCode = resultCode;
this.args = args;
}
}
- Todas las demás excepciones heredan la excepción común
package cn.soboys.springbootrestfulapi.common.exception;
import cn.soboys.springbootrestfulapi.common.resp.ResultCode;
/**
* @author 公众号 程序员三时
* @version 1.0
* @date 2023/4/29 00:15
* @webSite https://github.com/coder-amiao
* 通用业务异常封装
*/
public class BusinessException extends BaseException {
public BusinessException(ResultCode resultCode, Object[] args, String message) {
super(resultCode, args, message);
}
public BusinessException(ResultCode resultCode, Object[] args, String message, Throwable cause) {
super(resultCode, args, message, cause);
}
}
- Encapsulación de clase de excepción empresarial de aserción
public interface Assert {
/**
* 创建异常
* @param args
* @return
*/
BaseException newException(Object... args);
/**
* 创建异常
* @param t
* @param args
* @return
*/
BaseException newException(Throwable t, Object... args);
/**
* <p>断言对象<code>obj</code>非空。如果对象<code>obj</code>为空,则抛出异常
*
* @param obj 待判断对象
*/
default void assertNotNull(Object obj) {
if (obj == null) {
throw newException(obj);
}
}
/**
* <p>断言对象<code>obj</code>非空。如果对象<code>obj</code>为空,则抛出异常
* <p>异常信息<code>message</code>支持传递参数方式,避免在判断之前进行字符串拼接操作
*
* @param obj 待判断对象
* @param args message占位符对应的参数列表
*/
default void assertNotNull(Object obj, Object... args) {
if (obj == null) {
throw newException(args);
}
}
}
Uso específico
/**
* 异常返回模拟
*
* @return
*/
@GetMapping("/exception")
public Student exception() {
Student s = null;
BusinessErrorCode.Sign_Error.assertNotNull(s,"secret秘钥不正确");
return s;
}
En los negocios, podemos lanzar excepciones de enumeración directamente de esta manera. Esto hace que el código sea mucho más simple y limpio.
El proxy se ha actualizado al proyecto de andamiaje del repositorio de github
Preste atención a la cuenta oficial, el programador continuará generando contenido de alta calidad a las tres en punto , con la esperanza de brindarle algo de inspiración y ayuda.