diff --git a/cloud-demo/ReadMe.md b/cloud-demo/ReadMe.md index b520737..bb42088 100644 --- a/cloud-demo/ReadMe.md +++ b/cloud-demo/ReadMe.md @@ -240,7 +240,7 @@ spring: active: dev cloud: nacos: - server-addr: ${NACOS_HOST:192.168.95.135}:8848 + server-addr: ${NACOS_HOST:192.168.3.150}:8848 config: namespace: ${spring.profiles.active:dev} # 动态匹配当前profile group: DEFAULT_GROUP @@ -425,15 +425,15 @@ public interface BunnyFeignClient { ### 负载均衡对比 -| 特性 | 客户端负载均衡 (OpenFeign) | 服务端负载均衡 (Nginx等) | -| ------------ | ----------------------------------- | ------------------------ | -| **实现位置** | 客户端实现 | 服务端实现 | -| **依赖关系** | 需要服务注册中心 | 不依赖注册中心 | -| **性能** | 直接调用,减少网络跳转 | 需要经过代理服务器 | -| **灵活性** | 可定制负载均衡策略 | 配置相对固定 | -| **服务发现** | 集成服务发现机制 | 需要手动维护服务列表 | -| **适用场景** | 微服务内部调用 | 对外暴露API或跨系统调用 | -| **容错能力** | 集成熔断机制(如Sentinel、Hystrix) | 依赖代理服务器容错配置 | +| 特性 | 客户端负载均衡 (OpenFeign) | 服务端负载均衡 (Nginx等) | +|----------|---------------------------|------------------| +| **实现位置** | 客户端实现 | 服务端实现 | +| **依赖关系** | 需要服务注册中心 | 不依赖注册中心 | +| **性能** | 直接调用,减少网络跳转 | 需要经过代理服务器 | +| **灵活性** | 可定制负载均衡策略 | 配置相对固定 | +| **服务发现** | 集成服务发现机制 | 需要手动维护服务列表 | +| **适用场景** | 微服务内部调用 | 对外暴露API或跨系统调用 | +| **容错能力** | 集成熔断机制(如Sentinel、Hystrix) | 依赖代理服务器容错配置 | ### 高级配置 @@ -578,3 +578,209 @@ public interface ProductFeignClient { // 方法定义 } ``` + +## Sentinel 使用指南 + +> [!NOTE] +> 如果安装完Sentinel打开控制面板可以看到服务,但簇点链路为空,可能原因: +> +> 1. 微服务与Sentinel不在同一IP段 +> 2. 服务未发送心跳到Sentinel Dashboard +> 3. 未正确配置`spring.cloud.sentinel.transport.dashboard` + +### 依赖引入 + +```xml + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + 2022.0.0.0 + +``` + +### 基础配置 + +```yaml +spring: + cloud: + sentinel: + enabled: true + eager: true # 提前初始化 + transport: + dashboard: 192.168.3.150:8858 # Sentinel控制台地址 + port: 8719 # 本地启动的HTTP Server端口 + client-ip: ${spring.cloud.client.ip-address} # 客户端IP + filter: + enabled: true + web-context-unify: false # 关闭统一上下文(链路模式需要) +``` + +### 自定义异常处理 + +#### MVC接口自定义返回 + +```java +@Component +public class MyBlockExceptionHandler implements BlockExceptionHandler { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, + String s, BlockException e) throws Exception { + response.setContentType("application/json;charset=utf-8"); + response.setStatus(429); // 建议使用429 Too Many Requests + + Map result = Map.of( + "code", 429, + "message", "请求被限流", + "timestamp", System.currentTimeMillis(), + "rule", e.getRule() + ); + + objectMapper.writeValue(response.getWriter(), result); + } +} +``` + +#### REST接口全局异常处理 + +```java +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(BlockException.class) + public ResponseEntity handleBlockException(BlockException e) { + return ResponseEntity.status(429) + .body(Map.of( + "error", "Too Many Requests", + "rule", e.getRule().toString() + )); + } +} +``` + +### @SentinelResource详解 + +#### 作用 + +- 定义资源名称(用于流量控制) +- 指定限流/降级处理逻辑 +- 配置异常降级策略 + +#### blockHandler vs fallback区别 + +| 特性 | blockHandler | fallback | +| -------- | ------------------------ | ------------------- | +| 触发条件 | 流量控制/熔断时触发 | 业务异常时触发 | +| 参数要求 | 需包含BlockException参数 | 需包含Throwable参数 | +| 优先级 | 更高 | 更低 | +| 典型场景 | 限流/熔断处理 | 业务降级处理 | + +#### blockHandler使用示例 + +```java +@Operation(summary = "创建订单") +@SentinelResource( + value = "orderService", + blockHandler = "createBlockHandler", + fallback = "createFallback" +) +@GetMapping("create") +public Order createOrder(Long userId, Long productId) { + return orderService.createOrder(productId, userId); +} + +// 限流处理(参数需匹配原方法且最后加BlockException) +public Order createBlockHandler(Long userId, Long productId, BlockException ex) { + log.warn("触发限流,rule={}", ex.getRule()); + return Order.fallbackOrder(userId, "限流:" + ex.getClass().getSimpleName()); +} + +// 降级处理(参数需匹配原方法且最后加Throwable) +public Order createFallback(Long userId, Long productId, Throwable t) { + log.error("业务异常", t); + return Order.fallbackOrder(userId, "降级:" + t.getMessage()); +} +``` + +### 流控规则详解 + +#### 阈值类型 + +| 类型 | 说明 | 适用场景 | +| ------ | -------------------------------- | -------------------- | +| QPS | 每秒请求数 | 绝大多数场景推荐使用 | +| 线程数 | 并发线程数(统计服务内部线程数量) | 同步服务/耗时操作 | + +> [!WARNING] +> 线程数模式需要统计服务内部线程数量,性能开销较大,非必要不推荐使用 + +#### 集群模式 + +| 模式 | 说明 | 示意图 | +| -------- | ---------------------------------- | ------------------------------------------------- | +| 单机均摊 | 总阈值=单机阈值×节点数(均匀分配) | ![单机均摊](./images/image-20250527112921793.png) | +| 总体阈值 | 所有节点共享总阈值(按实际请求分配) | - | + +### 流控模式 + +#### 1. 直接模式 + +```mermaid +graph LR + 流量 --直接--> 资源A +``` + +- 最简单的模式,直接对资源生效 + +#### 2. 关联模式 + +```mermaid +graph LR + 流量 --入口A--> 资源A[[不限流]] + 流量 --入口B--> 资源B[[限流]] +``` + +配置要求: + +```yaml +spring.cloud.sentinel.web-context-unify: false +``` + +典型场景:写操作触发时限制读操作 + +#### 3. 链路模式 + +```mermaid +graph TD + 入口A --> 服务1 --> 资源X + 入口B --> 服务2 --> 资源X +``` + +- 只针对特定入口的调用链路限流 +- 需要配合`@SentinelResource`标注资源点 + +### 流控效果 + +#### 1. 快速失败 + +- 直接抛出FlowException +- 支持所有流控模式 +- 配置简单,性能最好 + +#### 2. Warm Up(预热) + +![预热模式](./images/image-20250527112649302.png) + +- 冷启动阶段逐步提高阈值 +- 防止冷系统被突发流量击垮 +- 需配置预热时长(秒) + +#### 3. 匀速排队 + +![排队模式](./images/image-20250527120421676.png) + +- 以恒定间隔处理请求 +- 需配置超时时间(毫秒) +- 不支持QPS>1000的场景 + diff --git a/cloud-demo/images/f69073a0-a94a-437a-b555-1abe9914556f.png b/cloud-demo/images/f69073a0-a94a-437a-b555-1abe9914556f.png deleted file mode 100644 index 453c7f4..0000000 Binary files a/cloud-demo/images/f69073a0-a94a-437a-b555-1abe9914556f.png and /dev/null differ diff --git a/cloud-demo/images/image-20250526152842107.png b/cloud-demo/images/image-20250526152842107.png deleted file mode 100644 index c667a90..0000000 Binary files a/cloud-demo/images/image-20250526152842107.png and /dev/null differ diff --git a/cloud-demo/images/image-20250526152904745.png b/cloud-demo/images/image-20250526152904745.png deleted file mode 100644 index c07dd22..0000000 Binary files a/cloud-demo/images/image-20250526152904745.png and /dev/null differ diff --git a/cloud-demo/images/image-20250526160709930.png b/cloud-demo/images/image-20250526160709930.png deleted file mode 100644 index 20f6469..0000000 Binary files a/cloud-demo/images/image-20250526160709930.png and /dev/null differ diff --git a/cloud-demo/images/image-20250527112649302.png b/cloud-demo/images/image-20250527112649302.png new file mode 100644 index 0000000..9d71c63 Binary files /dev/null and b/cloud-demo/images/image-20250527112649302.png differ diff --git a/cloud-demo/images/image-20250527112921793.png b/cloud-demo/images/image-20250527112921793.png new file mode 100644 index 0000000..9e21d40 Binary files /dev/null and b/cloud-demo/images/image-20250527112921793.png differ diff --git a/cloud-demo/images/image-20250527120421676.png b/cloud-demo/images/image-20250527120421676.png new file mode 100644 index 0000000..fb18cc7 Binary files /dev/null and b/cloud-demo/images/image-20250527120421676.png differ diff --git a/cloud-demo/model/pom.xml b/cloud-demo/model/pom.xml index cc35c36..9f0e430 100644 --- a/cloud-demo/model/pom.xml +++ b/cloud-demo/model/pom.xml @@ -22,5 +22,20 @@ org.projectlombok lombok + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + + + + + + + + + diff --git a/cloud-demo/model/src/main/java/cn/bunny/model/common/enums/ResultCodeEnum.java b/cloud-demo/model/src/main/java/cn/bunny/model/common/enums/ResultCodeEnum.java new file mode 100644 index 0000000..9de6337 --- /dev/null +++ b/cloud-demo/model/src/main/java/cn/bunny/model/common/enums/ResultCodeEnum.java @@ -0,0 +1,90 @@ +package cn.bunny.model.common.enums; + +import lombok.Getter; + +/** + * 统一返回结果状态信息类 + */ +@Getter +public enum ResultCodeEnum { + // 成功操作 200 + SUCCESS(200, "操作成功"), + CREATE_SUCCESS(200, "添加成功"), + UPDATE_SUCCESS(200, "修改成功"), + DELETE_SUCCESS(200, "删除成功"), + SORT_SUCCESS(200, "排序成功"), + SUCCESS_UPLOAD(200, "上传成功"), + SUCCESS_LOGOUT(200, "退出成功"), + LOGOUT_SUCCESS(200, "退出成功"), + EMAIL_CODE_REFRESH(200, "邮箱验证码已刷新"), + EMAIL_CODE_SEND_SUCCESS(200, "邮箱验证码已发送"), + + // 验证错误 201 + USERNAME_OR_PASSWORD_NOT_EMPTY(201, "用户名或密码不能为空"), + EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"), + SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"), + EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"), + LOGIN_ERROR(500, "账号或密码错误"), + LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"), + GET_BUCKET_EXCEPTION(201, "获取文件信息失败"), + SEND_MAIL_CODE_ERROR(201, "邮件发送失败"), + EMAIL_CODE_EMPTY(201, "邮箱验证码过期或不存在"), + EMAIL_EXIST(201, "邮箱已存在"), + REQUEST_IS_EMPTY(201, "请求数据为空"), + DATA_TOO_LARGE(201, "请求数据为空"), + UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD(201, "新密码与密码相同"), + + // 数据相关 206 + ILLEGAL_REQUEST(206, "非法请求"), + REPEAT_SUBMIT(206, "重复提交"), + DATA_ERROR(206, "数据异常"), + EMAIL_USER_TEMPLATE_IS_EMPTY(206, "邮件模板为空"), + EMAIL_TEMPLATE_IS_EMPTY(206, "邮件模板为空"), + EMAIL_USER_IS_EMPTY(206, "关联邮件用户配置为空"), + DATA_EXIST(206, "数据已存在"), + DATA_NOT_EXIST(206, "数据不存在"), + ALREADY_USER_EXCEPTION(206, "用户已存在"), + USER_IS_EMPTY(206, "用户不存在"), + FILE_NOT_EXIST(206, "文件不存在"), + NEW_PASSWORD_SAME_OLD_PASSWORD(206, "新密码不能和旧密码相同"), + MISSING_TEMPLATE_FILES(206, "缺少模板文件"), + + // 身份过期 208 + LOGIN_AUTH(208, "请先登陆"), + AUTHENTICATION_EXPIRED(208, "身份验证过期"), + SESSION_EXPIRATION(208, "会话过期"), + FAIL_NO_ACCESS_DENIED_USER_LOCKED(208, "该账户已封禁"), + + // 209 + THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"), + + // 提示错误 + UPDATE_ERROR(216, "修改失败"), + URL_ENCODE_ERROR(216, "URL编码失败"), + ILLEGAL_CALLBACK_REQUEST_ERROR(217, "非法回调请求"), + FETCH_USERINFO_ERROR(219, "获取用户信息失败"), + ILLEGAL_DATA_REQUEST(219, "非法数据请求"), + CLASS_NOT_FOUND(219, "类名不存在"), + ADMIN_ROLE_CAN_NOT_DELETED(219, "无法删除admin角色"), + ROUTER_RANK_NEED_LARGER_THAN_THE_PARENT(219, "设置路由等级需要大于或等于父级的路由等级"), + + // 无权访问 403 + FAIL_NO_ACCESS_DENIED(403, "无权访问"), + FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"), + TOKEN_PARSING_FAILED(403, "token解析失败"), + + // 系统错误 500 + UNKNOWN_EXCEPTION(500, "服务异常"), + SERVICE_ERROR(500, "服务异常"), + UPLOAD_ERROR(500, "上传失败"), + FAIL(500, "失败"), + ; + + private final Integer code; + private final String message; + + ResultCodeEnum(Integer code, String message) { + this.code = code; + this.message = message; + } +} \ No newline at end of file diff --git a/cloud-demo/model/src/main/java/cn/bunny/model/common/result/PageResult.java b/cloud-demo/model/src/main/java/cn/bunny/model/common/result/PageResult.java new file mode 100644 index 0000000..fc45853 --- /dev/null +++ b/cloud-demo/model/src/main/java/cn/bunny/model/common/result/PageResult.java @@ -0,0 +1,34 @@ +package cn.bunny.model.common.result; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 封装分页查询结果 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Schema(name = "PageResult 对象", title = "分页返回结果", description = "分页返回结果") +public class PageResult implements Serializable { + + @Schema(name = "pageNo", title = "当前页") + private Long pageNo; + + @Schema(name = "pageSize", title = "每页记录数") + private Long pageSize; + + @Schema(name = "total", title = "总记录数") + private Long total; + + @Schema(name = "list", title = "当前页数据集合") + private List list; + +} \ No newline at end of file diff --git a/cloud-demo/model/src/main/java/cn/bunny/model/common/result/Result.java b/cloud-demo/model/src/main/java/cn/bunny/model/common/result/Result.java new file mode 100644 index 0000000..689b268 --- /dev/null +++ b/cloud-demo/model/src/main/java/cn/bunny/model/common/result/Result.java @@ -0,0 +1,174 @@ +package cn.bunny.model.common.result; + +import cn.bunny.model.common.enums.ResultCodeEnum; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Result { + // 状态码 + private Integer code; + // 返回消息 + private String message; + // 返回数据 + private T data; + + /** + * * 自定义返回体 + * + * @param data 返回体 + * @return Result + */ + protected static Result build(T data) { + Result result = new Result<>(); + result.setData(data); + return result; + } + + /** + * * 自定义返回体,使用ResultCodeEnum构建 + * + * @param body 返回体 + * @param codeEnum 返回状态码 + * @return Result + */ + public static Result build(T body, ResultCodeEnum codeEnum) { + Result result = build(body); + result.setCode(codeEnum.getCode()); + result.setMessage(codeEnum.getMessage()); + return result; + } + + /** + * * 自定义返回体 + * + * @param body 返回体 + * @param code 返回状态码 + * @param message 返回消息 + * @return Result + */ + public static Result build(T body, Integer code, String message) { + Result result = build(body); + result.setCode(code); + result.setMessage(message); + result.setData(null); + return result; + } + + /** + * * 操作成功 + * + * @return Result + */ + public static Result success() { + return success(null, ResultCodeEnum.SUCCESS); + } + + /** + * * 操作成功 + * + * @param data baseCategory1List + */ + public static Result success(T data) { + return build(data, ResultCodeEnum.SUCCESS); + } + + /** + * * 操作成功-状态码 + * + * @param codeEnum 状态码 + */ + public static Result success(ResultCodeEnum codeEnum) { + return success(null, codeEnum); + } + + /** + * * 操作成功-自定义返回数据和状态码 + * + * @param data 返回体 + * @param codeEnum 状态码 + */ + public static Result success(T data, ResultCodeEnum codeEnum) { + return build(data, codeEnum); + } + + /** + * * 操作失败-自定义返回数据和状态码 + * + * @param data 返回体 + * @param message 错误信息 + */ + public static Result success(T data, String message) { + return build(data, 200, message); + } + + /** + * * 操作失败-自定义返回数据和状态码 + * + * @param data 返回体 + * @param code 状态码 + * @param message 错误信息 + */ + public static Result success(T data, Integer code, String message) { + return build(data, code, message); + } + + /** + * * 操作失败 + */ + public static Result error() { + return Result.build(null); + } + + /** + * * 操作失败-自定义返回数据 + * + * @param data 返回体 + */ + public static Result error(T data) { + return build(data, ResultCodeEnum.FAIL); + } + + /** + * * 操作失败-状态码 + * + * @param codeEnum 状态码 + */ + public static Result error(ResultCodeEnum codeEnum) { + return build(null, codeEnum); + } + + /** + * * 操作失败-自定义返回数据和状态码 + * + * @param data 返回体 + * @param codeEnum 状态码 + */ + public static Result error(T data, ResultCodeEnum codeEnum) { + return build(data, codeEnum); + } + + /** + * * 操作失败-自定义返回数据和状态码 + * + * @param data 返回体 + * @param code 状态码 + * @param message 错误信息 + */ + public static Result error(T data, Integer code, String message) { + return build(data, code, message); + } + + /** + * * 操作失败-自定义返回数据和状态码 + * + * @param data 返回体 + * @param message 错误信息 + */ + public static Result error(T data, String message) { + return build(null, 500, message); + } +} diff --git a/cloud-demo/samples/namespace-config/dev.zip b/cloud-demo/samples/namespace-config/dev.zip new file mode 100644 index 0000000..7129142 Binary files /dev/null and b/cloud-demo/samples/namespace-config/dev.zip differ diff --git a/cloud-demo/samples/namespace-config/prod.zip b/cloud-demo/samples/namespace-config/prod.zip new file mode 100644 index 0000000..7f788c2 Binary files /dev/null and b/cloud-demo/samples/namespace-config/prod.zip differ diff --git a/cloud-demo/samples/namespace-config/public.zip b/cloud-demo/samples/namespace-config/public.zip new file mode 100644 index 0000000..440e4c3 Binary files /dev/null and b/cloud-demo/samples/namespace-config/public.zip differ diff --git a/cloud-demo/samples/namespace-config/test.zip b/cloud-demo/samples/namespace-config/test.zip new file mode 100644 index 0000000..bcf063c Binary files /dev/null and b/cloud-demo/samples/namespace-config/test.zip differ diff --git a/cloud-demo/samples/namespace-config/创建命名空间_nacos_config_export_dev.zip b/cloud-demo/samples/namespace-config/创建命名空间_nacos_config_export_dev.zip deleted file mode 100644 index 9555171..0000000 Binary files a/cloud-demo/samples/namespace-config/创建命名空间_nacos_config_export_dev.zip and /dev/null differ diff --git a/cloud-demo/services/pom.xml b/cloud-demo/services/pom.xml index 9940483..55e24f4 100644 --- a/cloud-demo/services/pom.xml +++ b/cloud-demo/services/pom.xml @@ -68,6 +68,10 @@ com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + org.springframework.cloud spring-cloud-starter-loadbalancer diff --git a/cloud-demo/services/service-order/pom.xml b/cloud-demo/services/service-order/pom.xml index a2ca031..4f87b13 100644 --- a/cloud-demo/services/service-order/pom.xml +++ b/cloud-demo/services/service-order/pom.xml @@ -18,9 +18,15 @@ - - com.alibaba.cloud - spring-cloud-starter-alibaba-sentinel - + + + + + + + + + + diff --git a/cloud-demo/services/service-order/src/main/java/cn/bunny/service/controller/OrderController.java b/cloud-demo/services/service-order/src/main/java/cn/bunny/service/controller/OrderController.java index 8fc71a7..db74c57 100644 --- a/cloud-demo/services/service-order/src/main/java/cn/bunny/service/controller/OrderController.java +++ b/cloud-demo/services/service-order/src/main/java/cn/bunny/service/controller/OrderController.java @@ -3,12 +3,16 @@ package cn.bunny.service.controller; import cn.bunny.model.order.bean.Order; import cn.bunny.service.config.OrderProperties; import cn.bunny.service.service.OrderService; +import com.alibaba.csp.sentinel.annotation.SentinelResource; +import com.alibaba.csp.sentinel.slots.block.BlockException; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController @RequestMapping("/api/order") @RequiredArgsConstructor @@ -25,18 +29,28 @@ public class OrderController { private final OrderProperties orderProperties; @Operation(summary = "创建订单") + @SentinelResource(value = "order", blockHandler = "createBlockHandler") @GetMapping("create") public Order createOrder(Long userId, Long productId) { return orderService.createOrder(productId, userId); } + public Order createBlockHandler(Long userId, Long productId, BlockException exception) { + Order order = new Order(); + order.setUserId(userId); + order.setAddress("xxx"); + order.setNickName(exception.getMessage()); + order.setProductList(List.of()); + return order; + } + @Operation(summary = "读取配置") @GetMapping("config") public String config() { String timeout = orderProperties.getTimeout(); String autoConfirm = orderProperties.getAutoConfirm(); String dbUrl = orderProperties.getDbUrl(); - + return "timeout:" + timeout + "\nautoConfirm:" + autoConfirm + "\norder.db-url" + dbUrl; } } diff --git a/cloud-demo/services/service-order/src/main/java/cn/bunny/service/exception/MyBlockExceptionHandler.java b/cloud-demo/services/service-order/src/main/java/cn/bunny/service/exception/MyBlockExceptionHandler.java new file mode 100644 index 0000000..7b5cd38 --- /dev/null +++ b/cloud-demo/services/service-order/src/main/java/cn/bunny/service/exception/MyBlockExceptionHandler.java @@ -0,0 +1,26 @@ +package cn.bunny.service.exception; + +import cn.bunny.model.common.result.Result; +import com.alibaba.csp.sentinel.adapter.spring.webmvc_v6x.callback.BlockExceptionHandler; +import com.alibaba.csp.sentinel.slots.block.BlockException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; + +import java.io.PrintWriter; + +@Component +public class MyBlockExceptionHandler implements BlockExceptionHandler { + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s, BlockException e) throws Exception { + PrintWriter writer = httpServletResponse.getWriter(); + httpServletResponse.setContentType("application/json;charset=utf-8"); + + Result result = new Result<>(500, "限制访问", null); + String json = objectMapper.writeValueAsString(result); + writer.write(json); + } +} diff --git a/cloud-demo/services/service-order/src/main/resources/application-feign.yaml b/cloud-demo/services/service-order/src/main/resources/application-feign.yaml index ce0bc6e..f778e63 100644 --- a/cloud-demo/services/service-order/src/main/resources/application-feign.yaml +++ b/cloud-demo/services/service-order/src/main/resources/application-feign.yaml @@ -16,6 +16,14 @@ spring: read-timeout: 5000 # 最多等待对方 5s request-interceptors: - cn.bunny.service.interceptor.XTokenRequestInterceptor + sentinel: + enabled: true + eager: true # 提前加载 + transport: + dashboard: 192.168.3.150:8858 + filter: + enabled: true + # web-context-unify: false # 关闭统一上下文 feign: sentinel: - enabled: true \ No newline at end of file + enabled: true diff --git a/cloud-demo/services/service-order/src/main/resources/application.yaml b/cloud-demo/services/service-order/src/main/resources/application.yaml index cce3540..347ff19 100644 --- a/cloud-demo/services/service-order/src/main/resources/application.yaml +++ b/cloud-demo/services/service-order/src/main/resources/application.yaml @@ -10,7 +10,7 @@ spring: - feign cloud: nacos: - server-addr: 192.168.95.135:8848 + server-addr: 192.168.3.150:8848 config: import-check: enabled: false diff --git a/cloud-demo/services/service-product/src/main/resources/application-dev.yaml b/cloud-demo/services/service-product/src/main/resources/application-dev.yaml index 7cd2945..67acf78 100644 --- a/cloud-demo/services/service-product/src/main/resources/application-dev.yaml +++ b/cloud-demo/services/service-product/src/main/resources/application-dev.yaml @@ -2,4 +2,4 @@ server: port: 8001 nacos: - server-addr: 192.168.95.135:8848 + server-addr: 192.168.3.150:8848 diff --git a/cloud-demo/services/service-product/src/main/resources/application.yaml b/cloud-demo/services/service-product/src/main/resources/application.yaml index 478cea8..1407dd5 100644 --- a/cloud-demo/services/service-product/src/main/resources/application.yaml +++ b/cloud-demo/services/service-product/src/main/resources/application.yaml @@ -12,3 +12,11 @@ spring: config: import-check: enabled: false + + sentinel: + enabled: true + eager: true # 提前加载 + transport: + dashboard: 192.168.3.150:8858 + filter: + enabled: true \ No newline at end of file diff --git a/cloud-demo/环境搭建.md b/cloud-demo/环境搭建.md index 12454eb..f79295e 100644 --- a/cloud-demo/环境搭建.md +++ b/cloud-demo/环境搭建.md @@ -26,7 +26,7 @@ sudo systemctl daemon-reload && sudo systemctl restart docker #### MySQL配置问题 -| **特性** | `**my.cnf**` | `**conf.d**` **目录** | +| **特性** | my.cnf | conf.d **目录** | | ------------ | :--------------------------- | :------------------------: | | **文件类型** | 单个文件 | 目录,包含多个 `.cnf` 文件 | | **配置方式** | 集中式配置 | 分布式配置 |