偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

別錯(cuò)過(guò)!Spring Boot 實(shí)現(xiàn)統(tǒng)一響應(yīng)結(jié)果的五種方案

開發(fā) 前端
在 Spring Boot 項(xiàng)目開發(fā)中,隨著接口數(shù)量增多,不同接口的響應(yīng)結(jié)果格式各異,這給前端開發(fā)和接口維護(hù)帶來(lái)諸多不便。

環(huán)境:SpringBoot3.4.2

1. 簡(jiǎn)介

在 Spring Boot 項(xiàng)目開發(fā)中,隨著接口數(shù)量增多,不同接口的響應(yīng)結(jié)果格式各異,這給前端開發(fā)和接口維護(hù)帶來(lái)諸多不便。前端需要針對(duì)不同格式做適配,增加開發(fā)成本;后端維護(hù)時(shí),也易因格式混亂導(dǎo)致錯(cuò)誤。

統(tǒng)一響應(yīng)結(jié)果能解決這些問(wèn)題。它規(guī)定所有接口返回相同格式的數(shù)據(jù),如包含狀態(tài)碼、消息、數(shù)據(jù)等字段。例如,成功時(shí)返回狀態(tài)碼 200、消息“操作成功”和數(shù)據(jù);失敗時(shí)返回對(duì)應(yīng)錯(cuò)誤碼和消息。這樣前端只需按統(tǒng)一格式解析,降低開發(fā)復(fù)雜度;后端維護(hù)也更便捷,只需關(guān)注業(yè)務(wù)邏輯。統(tǒng)一響應(yīng)結(jié)果提升了代碼可讀性、可維護(hù)性,增強(qiáng)了前后端協(xié)作效率。

在本篇文章里,我們將針對(duì) Spring Boot 中實(shí)現(xiàn)統(tǒng)一響應(yīng)結(jié)果,詳細(xì)闡述 6 種切實(shí)可行的方案。

2.實(shí)戰(zhàn)案例

2.1 自定義響應(yīng)實(shí)體類

定義一個(gè)通用的響應(yīng)類,包含狀態(tài)碼、消息和數(shù)據(jù)。然后在Controller中返回這個(gè)類的實(shí)例。

自定義狀態(tài)碼

public enum ResultCode {
  SUCCESS(200, "操作成功"), FAILURE(400, "業(yè)務(wù)異常"), 
  UNAUTHORIZED(401, "未授權(quán)"), FORBIDDEN(403, "禁止訪問(wèn)"), 
  NOT_FOUND(404, "資源不存在"), INTERNAL_ERROR(500, "系統(tǒng)錯(cuò)誤") ;
  private final int code ;
  private final String msg ;
  // getters
}

自定義結(jié)果對(duì)象

public class ApiResponse<T> {
  private int code ;
  private String message ;
  private T data;
  public ApiResponse(int code, String message, T data) {
    this.code = code;
    this.message = message;
    this.data = data;
  }
  // 成功響應(yīng)(帶數(shù)據(jù))
  public static <T> ApiResponse<T> success(T data) {
    return new ApiResponse<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMsg(), data);
  }
  // 失敗響應(yīng)
  public static <T> ApiResponse<T> fail(ResultCode resultCode) {
    return new ApiResponse<>(resultCode.getCode(), resultCode.getMsg(), null);
  }
  // ...
  // getters, setters
}

Controller接口

@RestController
@RequestMapping("/way1")
public class Way1Controller {
  @GetMapping("/{id}")
  public ApiResponse<User> getUser(@PathVariable Long id) {
    return ApiResponse.success(new User(id, "Pack")) ;
  }
  // 錯(cuò)誤處理
  @ExceptionHandler(Exception.class)
  public ApiResponse<Void> handleException(Exception e) {
    return ApiResponse.fail(ResultCode.NOT_FOUND);
  }
}

2.2 自定義ResponseBodyAdvice

通過(guò)實(shí)現(xiàn) ResponseBodyAdvice 接口,可以對(duì)Controller返回的結(jié)果進(jìn)行統(tǒng)一封裝。這種方式不需要修改每個(gè)Controller方法。

自定義注解(標(biāo)注那些不需要處理的接口)

@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface NoWrap {
}

自定義ResponseBodyAdvice

@RestControllerAdvice
public class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {
  private final ObjectMapper objectMapper ;
  public GlobalResponseAdvice(ObjectMapper objectMapper) {
    this.objectMapper = objectMapper;
  }
  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return !returnType.hasMethodAnnotation(NoWrap.class);
  }
  @Override
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
      Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
      ServerHttpResponse response) {
    // 處理String類型特殊轉(zhuǎn)換
    if (body instanceof String) {
      try {
        return this.objectMapper.writeValueAsString(ApiResponse.success(body)) ;
      } catch (JsonProcessingException e) {
        System.err.printf("JSON序列化錯(cuò)誤: %s%n", e.getMessage()) ;
        return body ;
      }
    }
    // 已封裝過(guò)的響應(yīng)直接返回
    if (body instanceof ApiResponse) {
      return body ;
    }
    // 空響應(yīng)
    if (body == null && returnType.getParameterType().equals(void.class)) {
      return ApiResponse.success();
    }
    return ApiResponse.success(body) ;
  }
}

Controller接口

@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
  return new User(id, "Pack") ;
}
@GetMapping("/query")
public String query() {
  return "查詢完成" ;
}

圖片圖片

圖片圖片

2.3 使用AOP技術(shù)

我們也可以使用AOP來(lái)攔截Controller方法的返回值,然后進(jìn)行統(tǒng)一封裝。但是AOP技術(shù)的局限性非常大,我們首先要統(tǒng)一Controller接口的響應(yīng)類型比如:使用ResponseEntity 作為統(tǒng)一方法返回類型。

@Aspect
@Component
public class ResponseAspect {
  @Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping)")
  public void controllerPointcut() {
  }
  @Around("controllerPointcut()")
  public Object handleResponse(ProceedingJoinPoint pjp) throws Throwable {
    Object result = pjp.proceed();
    if (result instanceof ResponseEntity<?> ret) {
      // 對(duì)ResponseEntity的body進(jìn)行統(tǒng)一處理
      Object body = ApiResponse.success(ret.getBody()) ;
      return ResponseEntity.ok(body) ;
    }
    return result;
  }
}

Controller接口

@GetMapping("/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
  return ResponseEntity.ok(new User(id, "Pack")) ;
}

圖片

此種方式最不推薦的了,Controller接口都已經(jīng)統(tǒng)一了ResponseEntity,那么我還搞個(gè)AOP做什么?

2.4 使用Filter

此種方式可行,但是也不推薦,復(fù)雜且易出錯(cuò),破壞流式響應(yīng)。

@WebFilter("/way4/*")
public class ResponseContentFilter implements Filter {
  @Override
  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
      throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) resp;
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
    try {
      chain.doFilter(req, responseWrapper);
    } finally {
      // ...
    }
    String content = new String(responseWrapper.getContentAsByteArray(), "UTF-8") ;
    ObjectMapper mapper = new ObjectMapper();
    byte[] ret = mapper.writeValueAsBytes(ApiResponse.success(content)) ;
    response.getOutputStream().write(ret) ;
  }
}

Controller接口

@GetMapping("/{id}")
public ResponseEntity<?> getUser(@PathVariable Long id) {
  return ResponseEntity.ok(new User(id, "Pack")) ;
}

圖片圖片

通過(guò)Filter方式可能對(duì)那些 遺留系統(tǒng)改造 有用吧。

2.5 自定義HttpMessageConverter

通過(guò)自定義HttpMessageConverter方法提供了對(duì)響應(yīng)處理過(guò)程的精細(xì)控制,特別適合需要完全定制響應(yīng)格式的場(chǎng)景。

@Component
public class ResponseMessageConverter extends AbstractHttpMessageConverter<Object> {
  private final ObjectMapper objectMapper;
  public ResponseMessageConverter(ObjectMapper objectMapper) {
    super(MediaType.APPLICATION_JSON, MediaType.TEXT_HTML) ;
    this.objectMapper = objectMapper;
  }
  @Override
  protected boolean supports(Class<?> clazz) {
    // 支持所有類型,除了我們自己的ApiResponse和Void
    return !ApiResponse.class.isAssignableFrom(clazz) && !Void.TYPE.equals(clazz);
  }
  @Override
  protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
      throws IOException, HttpMessageNotReadableException {
    // 只處理輸出,不處理輸入
    return null;
  }
  @Override
  protected void writeInternal(Object body, HttpOutputMessage outputMessage)
      throws IOException, HttpMessageNotWritableException {
    // 由于我們上面配置的能夠支持text/html,所以必須在這里配置Content-Type否則統(tǒng)一都會(huì)通過(guò)text/html響應(yīng)這會(huì)出現(xiàn)亂碼問(wèn)題
    outputMessage.getHeaders().add("Content-Type", "application/json;charset=utf-8");
    // 創(chuàng)建統(tǒng)一響應(yīng)體
    ApiResponse<Object> response = ApiResponse.success(body);
    try {
      // 序列化響應(yīng)體
      String json = objectMapper.writeValueAsString(response);
      // 寫入響應(yīng)
      outputMessage.getBody().write(json.getBytes(StandardCharsets.UTF_8));
    } catch (JsonProcessingException e) {
      throw new HttpMessageNotWritableException("Error writing response", e);
    }
  }
}

Controller接口

@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
  return new User(id, "Pack") ;
}
@GetMapping("/query")
public String query() {
  return "查詢完成" ;
}

圖片圖片

圖片圖片

總結(jié)

該方案核心優(yōu)勢(shì)在于細(xì)粒度控制與高性能:

  • 直接操作輸出流,性能最優(yōu)
  • 精準(zhǔn)控制封裝邏輯,通過(guò)supports()方法實(shí)現(xiàn)條件過(guò)濾
  • 完全掌控響應(yīng)結(jié)構(gòu),支持特殊類型(如void/String)
  • 與Spring MVC原生機(jī)制無(wú)縫集成,不破壞現(xiàn)有流程
  • 避免全局包裝的過(guò)度處理,保持框架靈活性

適用于需要極致性能優(yōu)化和深度定制響應(yīng)格式的高要求場(chǎng)景。

責(zé)任編輯:武曉燕 來(lái)源: Springboot全家桶實(shí)戰(zhàn)案例
相關(guān)推薦

2024-08-01 09:10:03

2024-09-25 08:10:00

Spring后端

2025-06-06 08:28:56

2023-11-30 07:00:56

SpringBoot處理器

2025-03-31 08:39:55

2024-09-29 09:31:08

Spring前綴URL

2022-08-18 09:38:02

Spring跨域

2025-06-12 02:00:00

Spring簽到打卡

2025-02-13 00:34:22

Spring對(duì)象系統(tǒng)

2024-08-29 09:01:39

2025-06-17 07:37:53

2025-02-13 07:45:26

APISpringHTTP

2025-02-12 08:47:07

SpringAPI接口

2023-11-28 14:32:04

2025-05-30 08:11:30

2025-01-09 08:36:05

2025-05-14 04:00:00

2025-04-30 08:39:33

SpringMVC接口

2025-06-04 02:10:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)