package com.youlai.boot.common.result; import cn.hutool.extra.servlet.JakartaServletUtil; import cn.hutool.json.JSONUtil; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import java.nio.charset.StandardCharsets; /** * 响应写入器 *

* 用于在过滤器、Security处理器等无法使用 @RestControllerAdvice 的场景中统一写入HTTP响应。 * 支持写入成功响应和错误响应。 * 此类为工具类,所有方法均为静态方法,禁止实例化。 * * @author Ray.Hao * @since 2.0.0 */ @Slf4j public final class ResponseWriter { /** * 私有构造函数,防止实例化 */ private ResponseWriter() { throw new UnsupportedOperationException("工具类不允许实例化"); } /** * 写入成功响应 * * @param response HttpServletResponse * @param data 响应数据(可选) */ public static void writeSuccess(HttpServletResponse response, Object data) { writeResult(response, Result.success(data), HttpStatus.OK.value()); } /** * 写入成功响应(无数据) * * @param response HttpServletResponse */ public static void writeSuccess(HttpServletResponse response) { writeSuccess(response, null); } /** * 写入错误响应 * * @param response HttpServletResponse * @param resultCode 响应结果码 */ public static void writeError(HttpServletResponse response, ResultCode resultCode) { writeError(response, resultCode, null); } /** * 写入错误响应(带自定义消息) * * @param response HttpServletResponse * @param resultCode 响应结果码 * @param message 自定义消息(可选,为 null 时使用 resultCode 的默认消息) */ public static void writeError(HttpServletResponse response, ResultCode resultCode, String message) { Result result = message == null ? Result.failed(resultCode) : Result.failed(resultCode, message); int httpStatus = mapHttpStatus(resultCode); writeResult(response, result, httpStatus); } /** * 写入响应结果(通用方法) * * @param response HttpServletResponse * @param result 响应结果对象 * @param httpStatus HTTP状态码 */ private static void writeResult(HttpServletResponse response, Result result, int httpStatus) { try { // 设置HTTP状态码 response.setStatus(httpStatus); // 设置响应编码和内容类型 response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); response.setContentType(MediaType.APPLICATION_JSON_VALUE); // 写入响应 JakartaServletUtil.write(response, JSONUtil.toJsonStr(result), MediaType.APPLICATION_JSON_VALUE ); } catch (Exception e) { log.error("写入响应时发生未知异常: httpStatus={}, result={}", httpStatus, result, e); } } /** * 根据业务结果码映射HTTP状态码 * 401: 未认证(token无效/过期) * 403: 权限不足 * 400: 其他业务错误 * * @param resultCode 业务结果码 * @return HTTP状态码 */ private static int mapHttpStatus(ResultCode resultCode) { return switch (resultCode) { case ACCESS_UNAUTHORIZED, ACCESS_TOKEN_INVALID, REFRESH_TOKEN_INVALID -> HttpStatus.UNAUTHORIZED.value(); case ACCESS_PERMISSION_EXCEPTION -> HttpStatus.FORBIDDEN.value(); default -> HttpStatus.BAD_REQUEST.value(); }; } }