鍵.png)
使用NestJS和Prisma構(gòu)建REST API:身份驗證
如果還有接口test2、test3、test4…..,即每個接口都必須返回Result對象,這也是目前大多數(shù)項目正在使用的方式
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@ResponseBody
public @interface ResponseResultBody {
}
ResponseBodyAdvice 接口允許在執(zhí)行 @ResponseBody 或 ResponseEntity 控制器方法之后,但在使用 HttpMessageConverter 寫入響應(yīng)體之前自定義響應(yīng),進(jìn)行功能增強。通常用于加密,簽名,統(tǒng)一數(shù)據(jù)格式等
相應(yīng)的也有RequestBodyAdvice接口,針對所有以@RequestBody的參數(shù),在讀取請求body之前或者在body轉(zhuǎn)換成對象之前可以做相應(yīng)的增強
@Slf4j
@RestControllerAdvice
public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
/**
* 1、選擇是否執(zhí)行 beforeBodyWrite 方法,返回 true 執(zhí)行,false 不執(zhí)行.
* 2、通過supports方法,可以選擇對哪些類或方法的 Response 進(jìn)行處理,其余的則不處理。
* @param returnType:返回類型
* @param converterType:轉(zhuǎn)換器
* @return :返回 true 則下面的 beforeBodyWrite 執(zhí)行,否則不執(zhí)行
* /
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE);
}
/**
* 對 Response 處理的具體執(zhí)行方法
* @param body:響應(yīng)對象(response)中的響應(yīng)體
* @param returnType:控制器方法的返回類型
* @param selectedContentType:通過內(nèi)容協(xié)商選擇的內(nèi)容類型
* @param selectedConverterType:選擇寫入響應(yīng)的轉(zhuǎn)換器類型
* @param request:當(dāng)前請求
* @param response:當(dāng)前響應(yīng)
* @return :返回傳入的主體或修改過的(可能是新的)主體
* /
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return convert(convert(body), selectedConverterType);
}
private Result<?> convert(Object body) {
//兼容返回是Result類型
if (body instanceof Result) {
return (Result<?>) body;
}
return Result.success(body);
}
private Object convert(Result<?> result, Class<? extends HttpMessageConverter<?>> selectedConverterType) {
//兼容返回是String類型
if (selectedConverterType == StringHttpMessageConverter.class && result.getData() instanceof String) {
return "{\"code\":\"" + result.getCode() + "\",\"message\":\"" + result.getMessage() + "\",\"data\":\"" + result.getData() + "\"}";
}
return result;
}
}
@RestController
@ResponseResultBody
public class HelloController {
@GetMapping("/test")
public Result hello() {
HashMap<String, Object> info = new HashMap<>();
info.put("name","一安未來");
info.put("addr","北京");
return Result.success(ResultCode.SUCCESS,info);
}
@GetMapping("/test2")
public Object hello2() {
HashMap<String, Object> info = new HashMap<>();
info.put("name","一安未來");
info.put("addr","北京");
return info;
}
}
至此,即使返回Object也可以統(tǒng)一JSON格式了, 不用每個返回都返回Result對象
使用@ExceptionHandler可以用來統(tǒng)一處理方法拋出的異常返回JSON格式
自定義異常處理類
@Data
public class ResultException extends Exception{
ResultCode resultCode;
public ResultException() {
this(ResultCode.FAIL);
}
public ResultException(ResultCode resultCode) {
super(resultCode.getMessage());
this.resultCode = resultCode;
}
}
改造ResponseResultBodyAdvice
類
ResponseBodyAdvice 接口允許在執(zhí)行 @ResponseBody 或 ResponseEntity 控制器方法之后,但在使用 HttpMessageConverter 寫入響應(yīng)體之前自定義響應(yīng),進(jìn)行功能增強。通常用于加密,簽名,統(tǒng)一數(shù)據(jù)格式等
相應(yīng)的也有RequestBodyAdvice接口,針對所有以@RequestBody的參數(shù),在讀取請求body之前或者在body轉(zhuǎn)換成對象之前可以做相應(yīng)的增強
@Slf4j
@RestControllerAdvice
public class ResponseResultBodyAdvice implements ResponseBodyAdvice<Object> {
private static final Class<? extends Annotation> ANNOTATION_TYPE = ResponseResultBody.class;
/**
* 1、選擇是否執(zhí)行 beforeBodyWrite 方法,返回 true 執(zhí)行,false 不執(zhí)行.
* 2、通過supports方法,可以選擇對哪些類或方法的 Response 進(jìn)行處理,其余的則不處理。
* @param returnType:返回類型
* @param converterType:轉(zhuǎn)換器
* @return :返回 true 則下面的 beforeBodyWrite執(zhí)行,否則不執(zhí)行
* /
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ANNOTATION_TYPE) || returnType.hasMethodAnnotation(ANNOTATION_TYPE);
}
/**
* 對 Response 處理的具體執(zhí)行方法
* @param body:響應(yīng)對象(response)中的響應(yīng)體
* @param returnType:控制器方法的返回類型
* @param selectedContentType:通過內(nèi)容協(xié)商選擇的內(nèi)容類型
* @param selectedConverterType:選擇寫入響應(yīng)的轉(zhuǎn)換器類型
* @param request:當(dāng)前請求
* @param response:當(dāng)前響應(yīng)
* @return :返回傳入的主體或修改過的(可能是新的)主體
* /
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
return convert(convert(body), selectedConverterType);
}
private Result<?> convert(Object body) {
if (body instanceof Result) {
return (Result<?>) body;
}
return Result.success(body);
}
private Object convert(Result<?> result, Class<? extends HttpMessageConverter<?>> selectedConverterType) {
if (selectedConverterType == StringHttpMessageConverter.class && result.getData() instanceof String) {
return "{\"code\":\"" + result.getCode() + "\",\"message\":\"" + result.getMessage() + "\",\"data\":\"" + result.getData() + "\"}";
}
return result;
}
/**
* 提供對標(biāo)準(zhǔn)Spring MVC異常的處理
*/
@ExceptionHandler(Exception.class)
public final ResponseEntity<Result<?>> exceptionHandler(Exception ex, WebRequest request) {
log.error("ExceptionHandler: {}", ex.getMessage());
HttpHeaders headers = new HttpHeaders();
if (ex instanceof ResultException) {
return this.handleResultException((ResultException) ex, headers, request);
}
// TODO: 這里可以自定義其他的異常攔截
return this.handleException(ex, headers, request);
}
/**
* 對ResultException類返回返回結(jié)果的處理
*/
protected ResponseEntity<Result<?>> handleResultException(ResultException ex, HttpHeaders headers, WebRequest request) {
Result<?> body = Result.failure(ex.getResultCode());
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return this.handleExceptionInternal(ex, body, headers, status, request);
}
/**
* 異常類的統(tǒng)一處理
*/
protected ResponseEntity<Result<?>> handleException(Exception ex, HttpHeaders headers, WebRequest request) {
Result<?> body = Result.failure();
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
return this.handleExceptionInternal(ex, body, headers, status, request);
}
protected ResponseEntity<Result<?>> handleExceptionInternal(
Exception ex, Result<?> body, HttpHeaders headers, HttpStatus status, WebRequest request) {
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
}
return new ResponseEntity<>(body, headers, status);
}
}
文章轉(zhuǎn)自微信公眾號@一安未來