【java_wxid项目】【第十六章】【Spring Cloud Alibaba Sentinel集成】

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 主项目链接:https://gitee.com/java_wxid/java_wxid项目架构及博文总结:

主项目链接:https://gitee.com/java_wxid/java_wxid

项目架构及博文总结:


  • 点击:【使用Spring Boot快速构建应用】
  • 点击:【使用Spring Cloud Open Feign基于动态代理动态构造请求实现与其他系统进行交互】
  • 点击:【使用Spring Cloud Hystrix实现服务容错、熔断、降级、监控】
  • 点击:【使用Spring Cloud Ribbon以库的方式集成到服务的消费方实现客户端负载均衡】
  • 点击:【使用Spring Cloud Gateway作为API网关服务进行请求拦截、服务分发、降级、限流】
  • 点击:【使用Spring Cloud Security Oauth2作为微服务统一认证中心实现用户认证和授权访问】
  • 点击:【使用Spring Cloud Stream作为消息驱动用于动态的切换中间件】
  • 点击:【使用Spring Cloud Skywalking基于字节码注入通过探针方式进行链路追踪、分布式追踪、性能指标分析、应用和服务依赖分析】
  • 点击:【使用Spring Cloud Alibaba Nacos实现服务注册/发现/续约/剔除/下线、心跳检测、服务配置管理、基于长轮训机制实现配置动态变更】
  • 点击:【使用Spring Cloud Alibaba Seata作为对项目代码无入侵的分布式事务解决方案】
  • 点击:【使用Spring Cloud Alibaba Sentinel实现高可用流量防护】
  • 点击:【使用Apache ShardingSphere作为关系型数据库中间件实现分库分表、读写分离】
  • 点击:【使用Apache Mybatis作为持久层框架用于定制化SQL、存储过程以及高级映射】
  • 点击:【使用Redis作为高性能分布式缓存数据库】
  • 点击:【使用ElasticSearch全文搜索】
  • 点击:【使用MongoDB非关系型数据库】
  • 点击:【使用xxl-job作为分布式任务调度平台】
  • 点击:【使用Elasticsearch + Logstash + Kibana作为日志收集系统】
  • 点击:【使用Apifox作为API文档、API调试、API Mock、API自动化测试】
  • 点击:【使用Apache Spark作为基于内存计算的大数据分析引擎用于批处理、交互式查询】
  • 点击:【使用ETL工具将数据源抽取到HDFS作为高可靠、高吞吐量的分布式文件系统存储,通过Hive清洗、处理和计算原始数据,Hive清洗处理后的结果,将存入Hbase,海量数据随机查询场景从HBase查询数据】
  • 点击:【使用领域驱动DDD设计和设计模式进行开发】
  • 点击:【使用Netty基于Java NIO封装的高性能的网络通信框架】
  • 点击:【使用k8s、docker、docker-compose、宝塔面板进行环境搭建和部署】
  • 点击:【使用Vue渐进式JavaScript框架作为适用场景丰富的Web前端框架】
  • 点击:【分享人才筛选、工作分配、高效办公、项目推动等团队管理经验】


项目模块:

前期规划,实现部分


java_wxid   
├── demo                                                            // 演示模块
│     └── 模块名称:apache-mybatis-demo模块                            //Apache Mybatis集成(已实现并有博文总结)
│     └── 模块名称:apache-shardingsphere-demo模块                     //Apache ShardingSphere集成(已实现并有博文总结)
│     └── 模块名称:design-demo模块                                    //设计模式实战落地(已实现并有博文总结)
│     └── 模块名称:elasticsearch-demo模块                             //ElasticSearch集成(已实现并有博文总结)
│     └── 模块名称:mongodb-demo模块                                   //MongoDB集成(已实现并有博文总结)
│     └── 模块名称:redis-demo模块                                     //Redis集成(已实现并有博文总结)
│     └── 模块名称:spring-boot-demo模块                               //Spring Boot快速构建应用(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-nacos-demo模块                //Spring Cloud Alibaba Nacos集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-seata-demo模块                //Spring Cloud Alibaba Seata集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-sentinel-demo模块             //Spring Cloud Alibaba Sentinel集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-gateway-demo模块                      //Spring Cloud Gateway集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-hystrix-demo模块                      //Spring Cloud Hystrix集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-open-feign-demo模块                   //Spring Cloud Open Feign集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-ribbon-demo模块                       //Spring Cloud Ribbon集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-demo模块              //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-sso-client-demo模块   //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-skywalking-demo模块                   //Spring Cloud Skywalking集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-stream-demo模块                       //Spring Cloud Stream集成(已实现并有博文总结)
│     └── 模块名称:swagger-demo模块                                   //springfox-swagger2集成(已实现并有博文总结)
│     └── 模块名称:xxl-job模块                                        //xxl-job集成(已实现并有博文总结)
│     └── 模块名称:apache-spark-demo模块                              //Apache Spark集成
│     └── 模块名称:etl-hdfs-hive-hbase-demo模块                       //ETL、HDFS、Hive、Hbase集成
│     └── 模块名称:ddd-mode-demo模块                                  //DDD领域设计
│     └── 模块名称:netty-demo模块                                     //Netty集成
│     └── 模块名称:vue-demo模块                                       //前端vue集成
├── document                                                        // 文档
│     └── JavaKnowledgeDocument                                     //java知识点
│           └── java基础知识点.md                     
│           └── mq知识点.md
│           └── mysql知识点.md
│           └── redis知识点.md
│           └── springcould知识点.md
│           └── spring知识点.md
│     └── FounderDocument                                           //创始人
│           └── 创始人.md


系列文章:快速集成各种微服务相关的技术,帮助大家可以快速集成到自己的项目中,节约开发时间。

提示:系列文章还未全部完成,后续的文章,会慢慢补充进去的。


文章目录

创建spring-cloud-alibaba-sentinel-demo项目

修改pom.xml

修改SpringCloudAlibabaSentinelDemoApplication

创建bootstrap.yml

创建application.yml

创建SentinelConfig

创建HelloController

创建LimitFlowController

创建UserController

创建UserDao

创建AuthorityDemo

创建FlowThreadDemo

创建PaceFlowDemo

创建SystemGuardDemo

创建WarmUpFlowDemo

创建UserEntity

创建RRException

创建OrderFeignService

创建CommonBlockHandler

创建CommonFallback

创建MyBlockExceptionHandler

创建MyRequestOriginParser

创建MyUrlBlockHandler

创建UserServiceImpl

创建UserService

创建Constant

创建PageUtils

创建Query

创建R

创建HTMLFilter

创建SQLFilter

创建XssFilter

创建XssHttpServletRequestWrapper

创建UserDao.xml


创建spring-cloud-alibaba-sentinel-demo项目


项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/spring-cloud-alibaba-sentinel-demo

项目结构如下(示例):


  • 533f5b7d7fce4cb18a3b1742973b4e05.png


修改pom.xml


代码如下(示例):


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-cloud-alibaba-sentinel-demo</name>
    <description>Demo project for Spring Boot</description>
    <!--    属性配置-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
        在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系-->
        <spring.boot.version>2.3.12.RELEASE</spring.boot.version>
        <spring.cloud.version>Hoxton.SR12</spring.cloud.version>
        <spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version>
    </properties>
    <dependencies>
        <!--        代表web模块,在这个模块中含了许多JAR包,有spring相关的jar,内置tomcat服务器,jackson等,这些web项目中常用的的功能都会自动引入-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.4.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.4.1</version>
        </dependency>
        <!--        druid驱动-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>
        <!--        mysql连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.22</version>
        </dependency>
        <!--        mybatis的一个库-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.2</version>
        </dependency>
        <!-- Alibaba Nacos 配置 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--        在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,其实这个jar包里什么都没有,就只有一个标识类Marker,用来标识要开启Bootstrap配置文件的支持,由于父类用了2.5.6版本需要导入如下的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!--openfeign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-openfeign-core</artifactId>
            <version>2.2.6.RELEASE</version>
        </dependency>
        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
        <!-- 引入Feign Slf4j -->
        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-slf4j</artifactId>
            <version>8.14.4</version>
        </dependency>
        <!--        lombok插件-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>
<!--        @SentinelResource 注解用来标识资源是否被限流、降级。
        blockHandler: 定义当资源内部发生了BlockException应该进入的方法(捕获的是Sentinel定义的异常)
        fallback: 定义的是资源内部发生了Throwable应该进入的方法
        exceptionsToIgnore:配置fallback可以忽略的异常
        源码入口:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.0</version>
        </dependency>
<!--        流控规则设置可以通过Sentinel dashboard配置
        客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信。-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>1.8.0</version>
        </dependency>
        <!--- 解决流控链路不生效的问题
        从1.6.3版本开始,Sentinel Web filter默认收敛所有URL的入口context,导致链路限流不生效。
        从1.7.0版本开始,官方在CommonFilter引入了WEB_CONTEXT_UNIFY参数,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流。
        1.8.0 需要引入sentinel-web-servlet依赖
        -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
        </dependency>
        <!-- Spring Cloud Alibaba整合Sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--sentinel持久化 采用 Nacos 作为规则配置数据源-->
<!--        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>-->
    </dependencies>
    <!--
        引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
        在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
     -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

修改SpringCloudAlibabaSentinelDemoApplication


代码如下(示例):

package com.example.springcloudalibabasentineldemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@MapperScan("com.example.springcloudalibabasentineldemo.dao")
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudAlibabaSentinelDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudAlibabaSentinelDemoApplication.class, args);
    }
}

创建bootstrap.yml


代码如下(示例):


#bootstrap.yml优先级比application.yml优先级高
spring:
  #prefix−{spring.profile.active}.${file-extension}
  #nacos会根据当前环境去拼接配置名称查找相应配置文件,
  #示例:{spring.application.name}-{spring.profiles.active}-{spring.cloud.nacos.config.file-extension}
  #获取到值:nacos-autoconfig-service-dev.yml
  profiles:
    #开发环境dev,测试环境test,生产环境prod
    active: dev
  application:
    #配置应用的名称,用于获取配置
    name: spring-cloud-alibaba-sentinel-demo
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 106.14.132.94:8848
      config:
        #nacos配置中心地址
        server-addr: 106.14.132.94:8848
        #配置中心的命名空间id
        namespace: 9e50b6d9-6c3d-4e7a-b701-10f085e4b98d
        #配置分组,默认没有也可以
        group: DEFAULT_GROUP
        #配置文件后缀,用于拼接配置配置文件名称,目前只支持yaml和properties
        file-extension: yaml
        #配置自动刷新
        refresh-enabled: true
        #配置文件的前缀,默认是application.name的值,如果配了prefix,就取prefix的值
        #prefix: nacos-autoconfig-service-${spring.profile.active}
        # 配置编码
        encode: UTF-8
        username: nacos
        password: nacos

创建application.yml


代码如下(示例):


server:
  port: 8095
#暴露actuator端点   http://localhost:8800/actuator/sentinel
management:
  endpoints:
    web:
      exposure:
        include: '*'
spring:
  application:
    name: mall-user-sentinel-demo
  cloud:
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
        # 指定应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
        #port: 8719
  #      datasource:
  #        ds1:
  #          nacos:
  #            server-addr: 127.0.0.1:8848
  #            dataId: ${spring.application.name}
  #            groupId: DEFAULT_GROUP
  #            data-type: json
  #            rule-type: flow
  #数据库配置
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://139.224.137.74:3306/syncdemo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root
    password: ca0a997ee4770063
#mybatis
mybatis-plus:
  mapper-locations: classpath*:/mapper/*.xml
  #实体扫描,多个package用逗号或者分号分隔
  typeAliasesPackage: com.example.springcloudalibabasentineldemo.entity

创建SentinelConfig


代码如下(示例):


package com.example.springcloudalibabasentineldemo.config;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import com.example.springcloudalibabasentineldemo.sentinel.MyUrlBlockHandler;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * @className: SentinelConfig
 * @description: https://github.com/alibaba/Sentinel/issues/1213
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Configuration
public class SentinelConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合  解决流控链路不生效的问题
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        //CommonFilter的BlockException自定义处理逻辑
        WebCallbackManager.setUrlBlockHandler(new MyUrlBlockHandler());
        //解决授权规则不生效的问题
        //com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser
        //WebCallbackManager.setRequestOriginParser(new MyRequestOriginParser());
        return registration;
    }
}


创建HelloController


代码如下(示例):


package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
@Slf4j
public class HelloController {
    private static final String RESOURCE_NAME = "hello";
    @RequestMapping(value = "/hello")
    public String hello() {
        Entry entry = null;
        try {
            // 资源名可使用任意有业务语义的字符串,比如方法名、接口名或其它可唯一标识的字符串。
            entry = SphU.entry(RESOURCE_NAME);
            // 被保护的业务逻辑
            String str = "hello world";
            log.info("====="+str+"=====");
            return str;
        } catch (BlockException e1) {
            // 资源访问阻止,被限流或被降级
            //进行相应的处理操作
            log.info("block!");
            return "被流控了!";
        } catch (Exception ex) {
            // 若需要配置降级规则,需要通过这种方式记录业务异常
            Tracer.traceEntry(ex, entry);
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
        return null;
    }
    /**
     * 定义流控规则
     */
    @PostConstruct
    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //设置受保护的资源
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则 QPS
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置受保护的资源阈值
        // Set limit QPS to 20.
        rule.setCount(1);
        rules.add(rule);
        // 加载配置好的规则
        FlowRuleManager.loadRules(rules);
    }
}


创建LimitFlowController


代码如下(示例):


package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
public class LimitFlowController {
    @RequestMapping("/test")
//    @SentinelResource(value = "test",blockHandlerClass = CommonBlockHandler.class,blockHandler = "handleException3")
    public String test() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "========test()========";
    }
    AtomicInteger atomicInteger = new AtomicInteger();
    @RequestMapping("/test2")
    public String test2() {
        atomicInteger.getAndIncrement();
        if (atomicInteger.get() % 2 == 0){
            //模拟异常和异常比率
            int i = 1/0;
        }
        return "========test2()========";
    }
    @Autowired
    private UserService userService;
    @RequestMapping(value = "/test3")  //CommonFilter
    public UserEntity test3() {
        UserEntity user = userService.getUser(1);
        return user;
    }
    @RequestMapping(value = "/test4")
    public UserEntity test4() {
        UserEntity user = userService.getUser(1);
        return user;
    }
    public String handleException(BlockException exception) {
        return "===被限流降级啦===";
    }
}


创建UserController


代码如下(示例):


package com.example.springcloudalibabasentineldemo.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.feign.OrderFeignService;
import com.example.springcloudalibabasentineldemo.sentinel.CommonBlockHandler;
import com.example.springcloudalibabasentineldemo.sentinel.CommonFallback;
import com.example.springcloudalibabasentineldemo.service.UserService;
import com.example.springcloudalibabasentineldemo.utils.PageUtils;
import com.example.springcloudalibabasentineldemo.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Map;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    OrderFeignService orderFeignService;
    @RequestMapping(value = "/getNacosConfigure")
    @SentinelResource(value = "getNacosConfigure",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "getNacosConfigure",
            fallbackClass = CommonFallback.class,
            fallback = "getNacosConfigure"
    )
    public String getNacosConfigure() {
//        try {
//            // 模拟测试并发线程数限流
//            Thread.sleep(900);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        // findOrderByUserId  限流规则  2    sentinel dashboard 定义规则
        //feign调用
        String result = orderFeignService.getNacosConfigure();
        return result;
    }
    /**
     * 列表
     */
    @RequestMapping("/list")
    @SentinelResource(value = "userlist",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "handleException",fallback = "fallback")
    public R list(@RequestParam Map<String, Object> params){
        PageUtils page = userService.queryPage(params);
       // int i=1/0;
        return R.ok().put("page", page);
    }
    public R handleException(@RequestParam Map<String, Object> params,BlockException exception){
        return R.error(-1,"===被限流降级啦===");
    }
    /**
     * 信息
     */
    @RequestMapping("/info/{id}")
    @SentinelResource(value = "userinfo",
            blockHandlerClass = CommonBlockHandler.class,
            blockHandler = "handleException2",
            fallbackClass = CommonFallback.class,
            fallback = "fallback"
    )
    public R info(@PathVariable("id") Integer id){
    UserEntity user = userService.getById(id);
    if(id==4){
        throw new IllegalArgumentException("异常参数");
        }
        return R.ok().put("mapper", user);
    }
    public R handleException2(@PathVariable("id") Integer id, BlockException exception){
        return R.error(-1,"===被限流降级啦===");
    }
    public R fallback(@PathVariable("id") Integer id,Throwable e){
        return R.error(-1,"===被熔断降级啦==="+e.getMessage());
    }
    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@RequestBody UserEntity user){
    userService.save(user);
        return R.ok();
    }
    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@RequestBody UserEntity user){
    userService.updateById(user);
        return R.ok();
    }
    /**
     * 删除
     */
    @RequestMapping("/delete")
    public R delete(@RequestBody Integer[] ids){
    userService.removeByIds(Arrays.asList(ids));
        return R.ok();
    }
}


创建UserDao


代码如下(示例):

package com.example.springcloudalibabasentineldemo.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Mapper
public interface UserDao extends BaseMapper<UserEntity> {
}


创建AuthorityDemo


代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.context.ContextUtil;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import java.util.Collections;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class AuthorityDemo {
    private static final String RESOURCE_NAME = "testABC";
    public static void main(String[] args) {
        System.out.println("========Testing for black list========");
        initBlackRules();
        testFor(RESOURCE_NAME, "appA");
        testFor(RESOURCE_NAME, "appB");
        testFor(RESOURCE_NAME, "appC");
        testFor(RESOURCE_NAME, "appE");
        System.out.println("========Testing for white list========");
        initWhiteRules();
        testFor(RESOURCE_NAME, "appA");
        testFor(RESOURCE_NAME, "appB");
        testFor(RESOURCE_NAME, "appC");
        testFor(RESOURCE_NAME, "appE");
    }
    private static void testFor(/*@NonNull*/ String resource, /*@NonNull*/ String origin) {
        ContextUtil.enter(resource, origin);
        Entry entry = null;
        try {
            entry = SphU.entry(resource);
            System.out.println(String.format("Passed for resource %s, origin is %s", resource, origin));
        } catch (BlockException ex) {
            System.err.println(String.format("Blocked for resource %s, origin is %s", resource, origin));
        } finally {
            if (entry != null) {
                entry.exit();
            }
            ContextUtil.exit();
        }
    }
    private static void initWhiteRules() {
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(RESOURCE_NAME);
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        rule.setLimitApp("appA,appE");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    }
    private static void initBlackRules() {
        AuthorityRule rule = new AuthorityRule();
        rule.setResource(RESOURCE_NAME);
        rule.setStrategy(RuleConstant.AUTHORITY_BLACK);
        rule.setLimitApp("appA,appB");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    }
}


创建FlowThreadDemo


代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class FlowThreadDemo {
    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();
    private static AtomicInteger activeThread = new AtomicInteger();
    private static volatile boolean stop = false;
    private static final int threadCount = 100;
    private static int seconds = 60 + 40;
    private static volatile int methodBRunningTime = 2000;
    public static void main(String[] args) throws Exception {
        System.out.println(
                "MethodA will call methodB. After running for a while, methodB becomes fast, "
                        + "which make methodA also become fast ");
        tick();
        initFlowRule();
        for (int i = 0; i < threadCount; i++) {
            Thread entryThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        Entry methodA = null;
                        try {
                            TimeUnit.MILLISECONDS.sleep(5);
                            methodA = SphU.entry("methodA");
                            activeThread.incrementAndGet();
                            Entry methodB = SphU.entry("methodB");
                            TimeUnit.MILLISECONDS.sleep(methodBRunningTime);
                            methodB.exit();
                            pass.addAndGet(1);
                        } catch (BlockException e1) {
                            block.incrementAndGet();
                        } catch (Exception e2) {
                            // biz exception
                        } finally {
                            total.incrementAndGet();
                            if (methodA != null) {
                                methodA.exit();
                                activeThread.decrementAndGet();
                            }
                        }
                    }
                }
            });
            entryThread.setName("working thread");
            entryThread.start();
        }
    }
    private static void initFlowRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource("methodA");
        // set limit concurrent thread for 'methodA' to 20
        rule1.setCount(20);
        rule1.setGrade(RuleConstant.FLOW_GRADE_THREAD);
        rule1.setLimitApp("default");
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }
    private static void tick() {
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
    }
    static class TimerTask implements Runnable {
        @Override
        public void run() {
            long start = System.currentTimeMillis();
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;
                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;
                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;
                System.out.println(seconds + " total qps is: " + oneSecondTotal);
                System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
                        + ", pass:" + oneSecondPass
                        + ", block:" + oneSecondBlock
                        + " activeThread:" + activeThread.get());
                if (seconds-- <= 0) {
                    stop = true;
                }
                if (seconds == 40) {
                    System.out.println("method B is running much faster; more requests are allowed to pass");
                    methodBRunningTime = 20;
                }
            }
            long cost = System.currentTimeMillis() - start;
            System.out.println("time cost: " + cost + " ms");
            System.out.println("total:" + total.get() + ", pass:" + pass.get()
                    + ", block:" + block.get());
            System.exit(0);
        }
    }
}


创建PaceFlowDemo


代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class PaceFlowDemo {
    private static final String KEY = "abc";
    private static volatile CountDownLatch countDown;
    private static final Integer requestQps = 100;
    private static final Integer count = 10;
    private static final AtomicInteger done = new AtomicInteger();
    private static final AtomicInteger pass = new AtomicInteger();
    private static final AtomicInteger block = new AtomicInteger();
    public static void main(String[] args) throws InterruptedException {
        System.out.println("pace behavior");
        countDown = new CountDownLatch(1);
        initPaceFlowRule();
        simulatePulseFlow();
        countDown.await();
        System.out.println("done");
        System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
        System.out.println();
        System.out.println("default behavior");
        TimeUnit.SECONDS.sleep(5);
        done.set(0);
        pass.set(0);
        block.set(0);
        countDown = new CountDownLatch(1);
        initDefaultFlowRule();
        simulatePulseFlow();
        countDown.await();
        System.out.println("done");
        System.out.println("total pass:" + pass.get() + ", total block:" + block.get());
        System.exit(0);
    }
    private static void initPaceFlowRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(count);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        /*
         * CONTROL_BEHAVIOR_RATE_LIMITER means requests more than threshold will be queueing in the queue,
         * until the queueing time is more than {@link FlowRule#maxQueueingTimeMs}, the requests will be rejected.
         */
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
        rule1.setMaxQueueingTimeMs(20 * 1000);
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }
    private static void initDefaultFlowRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(count);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        // CONTROL_BEHAVIOR_DEFAULT means requests more than threshold will be rejected immediately.
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }
    private static void simulatePulseFlow() {
        for (int i = 0; i < requestQps; i++) {
            Thread thread = new Thread(new Runnable() {
                @Override
                public void run() {
                    long startTime = TimeUtil.currentTimeMillis();
                    Entry entry = null;
                    try {
                        entry = SphU.entry(KEY);
                    } catch (BlockException e1) {
                        block.incrementAndGet();
                    } catch (Exception e2) {
                        // biz exception
                    } finally {
                        if (entry != null) {
                            entry.exit();
                            pass.incrementAndGet();
                            long cost = TimeUtil.currentTimeMillis() - startTime;
                            System.out.println(
                                    TimeUtil.currentTimeMillis() + " one request pass, cost " + cost + " ms");
                        }
                    }
                    try {
                        TimeUnit.MILLISECONDS.sleep(5);
                    } catch (InterruptedException e1) {
                        // ignore
                    }
                    if (done.incrementAndGet() >= requestQps) {
                        countDown.countDown();
                    }
                }
            }, "Thread " + i);
            thread.start();
        }
    }
}


创建SystemGuardDemo


代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class SystemGuardDemo {
    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();
    private static volatile boolean stop = false;
    private static final int threadCount = 100;
    private static int seconds = 60 + 40;
    public static void main(String[] args) throws Exception {
        tick();
        initSystemRule();
        for (int i = 0; i < threadCount; i++) {
            Thread entryThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        Entry entry = null;
                        try {
                            entry = SphU.entry("methodA", EntryType.IN);
                            pass.incrementAndGet();
                            try {
                                TimeUnit.MILLISECONDS.sleep(20);
                            } catch (InterruptedException e) {
                                // ignore
                            }
                        } catch (BlockException e1) {
                            block.incrementAndGet();
                            try {
                                TimeUnit.MILLISECONDS.sleep(20);
                            } catch (InterruptedException e) {
                                // ignore
                            }
                        } catch (Exception e2) {
                            // biz exception
                        } finally {
                            total.incrementAndGet();
                            if (entry != null) {
                                entry.exit();
                            }
                        }
                    }
                }
            });
            entryThread.setName("working-thread");
            entryThread.start();
        }
    }
    private static void initSystemRule() {
        List<SystemRule> rules = new ArrayList<SystemRule>();
        SystemRule rule = new SystemRule();
        // max load is 3
        rule.setHighestSystemLoad(3.0);
        // max cpu usage is 60%
        rule.setHighestCpuUsage(0.6);
        // max avg rt of all request is 10 ms
        rule.setAvgRt(10);
        // max total qps is 20
        rule.setQps(20);
        // max parallel working thread is 10
        rule.setMaxThread(10);
        rules.add(rule);
        SystemRuleManager.loadRules(Collections.singletonList(rule));
    }
    private static void tick() {
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
    }
    static class TimerTask implements Runnable {
        @Override
        public void run() {
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;
                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;
                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;
                System.out.println(seconds + ", " + TimeUtil.currentTimeMillis() + ", total:"
                    + oneSecondTotal + ", pass:"
                    + oneSecondPass + ", block:" + oneSecondBlock);
                if (seconds-- <= 0) {
                    stop = true;
                }
            }
            System.exit(0);
        }
    }
}


创建WarmUpFlowDemo


代码如下(示例):

package com.example.springcloudalibabasentineldemo.demo;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.util.TimeUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class WarmUpFlowDemo {
    private static final String KEY = "abc";
    private static AtomicInteger pass = new AtomicInteger();
    private static AtomicInteger block = new AtomicInteger();
    private static AtomicInteger total = new AtomicInteger();
    private static volatile boolean stop = false;
    private static final int threadCount = 100;
    private static int seconds = 60 + 40;
    public static void main(String[] args) throws Exception {
        initFlowRule();
        // trigger Sentinel internal init
        Entry entry = null;
        try {
            entry = SphU.entry(KEY);
        } catch (Exception e) {
        } finally {
            if (entry != null) {
                entry.exit();
            }
        }
        Thread timer = new Thread(new TimerTask());
        timer.setName("sentinel-timer-task");
        timer.start();
        //first make the system run on a very low condition
        for (int i = 0; i < 3; i++) {
            Thread t = new Thread(new WarmUpTask());
            t.setName("sentinel-warmup-task");
            t.start();
        }
        Thread.sleep(20000);
        /*
         * Start more thread to simulate more qps. Since we use {@link RuleConstant.CONTROL_BEHAVIOR_WARM_UP} as
         * {@link FlowRule#controlBehavior}, real passed qps will increase to {@link FlowRule#count} in
         * {@link FlowRule#warmUpPeriodSec} seconds.
         */
        for (int i = 0; i < threadCount; i++) {
            Thread t = new Thread(new RunTask());
            t.setName("sentinel-run-task");
            t.start();
        }
    }
    private static void initFlowRule() {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(KEY);
        rule1.setCount(20);
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rule1.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        rule1.setWarmUpPeriodSec(10);
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
    }
    static class WarmUpTask implements Runnable {
        @Override
        public void run() {
            while (!stop) {
                Entry entry = null;
                try {
                    entry = SphU.entry(KEY);
                    // token acquired, means pass
                    pass.addAndGet(1);
                } catch (BlockException e1) {
                    block.incrementAndGet();
                } catch (Exception e2) {
                    // biz exception
                } finally {
                    total.incrementAndGet();
                    if (entry != null) {
                        entry.exit();
                    }
                }
                Random random2 = new Random();
                try {
                    TimeUnit.MILLISECONDS.sleep(random2.nextInt(2000));
                } catch (InterruptedException e) {
                    // ignore
                }
            }
        }
    }
    static class RunTask implements Runnable {
        @Override
        public void run() {
            while (!stop) {
                Entry entry = null;
                try {
                    entry = SphU.entry(KEY);
                    pass.addAndGet(1);
                } catch (BlockException e1) {
                    block.incrementAndGet();
                } catch (Exception e2) {
                    // biz exception
                } finally {
                    total.incrementAndGet();
                    if (entry != null) {
                        entry.exit();
                    }
                }
                Random random2 = new Random();
                try {
                    TimeUnit.MILLISECONDS.sleep(random2.nextInt(50));
                } catch (InterruptedException e) {
                    // ignore
                }
            }
        }
    }
    static class TimerTask implements Runnable {
        @Override
        public void run() {
            long start = System.currentTimeMillis();
            System.out.println("begin to statistic!!!");
            long oldTotal = 0;
            long oldPass = 0;
            long oldBlock = 0;
            while (!stop) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                }
                long globalTotal = total.get();
                long oneSecondTotal = globalTotal - oldTotal;
                oldTotal = globalTotal;
                long globalPass = pass.get();
                long oneSecondPass = globalPass - oldPass;
                oldPass = globalPass;
                long globalBlock = block.get();
                long oneSecondBlock = globalBlock - oldBlock;
                oldBlock = globalBlock;
                System.out.println(TimeUtil.currentTimeMillis() + ", total:" + oneSecondTotal
                        + ", pass:" + oneSecondPass
                        + ", block:" + oneSecondBlock);
                if (seconds-- <= 0) {
                    stop = true;
                }
            }
            long cost = System.currentTimeMillis() - start;
            System.out.println("time cost: " + cost + " ms");
            System.out.println("total:" + total.get() + ", pass:" + pass.get()
                    + ", block:" + block.get());
            System.exit(0);
        }
    }
}


创建UserEntity


代码如下(示例):

package com.example.springcloudalibabasentineldemo.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
 * @className: RedisController
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Data
@TableName("t_user")
public class UserEntity implements Serializable {
  private static final long serialVersionUID = 1L;
  /**
   * 
   */
  @TableId
  private Integer id;
  /**
   * 
   */
  private String username;
  /**
   * 
   */
  private Integer age;
}


创建RRException


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.exception;
/**
 * @description:自定义异常
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class RRException extends RuntimeException {
  private static final long serialVersionUID = 1L;
    private String msg;
    private int code = 500;
    public RRException(String msg) {
    super(msg);
    this.msg = msg;
  }
  public RRException(String msg, Throwable e) {
    super(msg, e);
    this.msg = msg;
  }
  public RRException(String msg, int code) {
    super(msg);
    this.msg = msg;
    this.code = code;
  }
  public RRException(String msg, int code, Throwable e) {
    super(msg, e);
    this.msg = msg;
    this.code = code;
  }
  public String getMsg() {
    return msg;
  }
  public void setMsg(String msg) {
    this.msg = msg;
  }
  public int getCode() {
    return code;
  }
  public void setCode(int code) {
    this.code = code;
  }
}


创建OrderFeignService


代码如下(示例):

package com.example.springcloudalibabasentineldemo.feign;
import com.example.springcloudalibabasentineldemo.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@FeignClient(value = "open-feign",path = "/feign")
public interface OrderFeignService {
    @RequestMapping("/getNacosConfigure")
    public String getNacosConfigure();
}


创建CommonBlockHandler


代码如下(示例):


package com.example.springcloudalibabasentineldemo.sentinel;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.springcloudalibabasentineldemo.utils.R;
import java.util.Map;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class CommonBlockHandler {
    /**
     * 注意: 必须为 static 函数   多个方法之间方法名不能一样
     * @param exception
     * @return
     */
    public static R handleException(Map<String, Object> params, BlockException exception){
        return R.error(-1,"===被限流啦==="+exception);
    }
    public String getNacosConfigure() {
        return "===被限流啦===";
    }
    public static R handleException2(Integer id, BlockException exception){
        return R.error(-1,"===被限流啦==="+exception);
    }
    public static String handleException3(BlockException exception){
        return "===被限流啦==="+exception;
    }
}

创建CommonFallback


代码如下(示例):

package com.example.springcloudalibabasentineldemo.sentinel;
import com.example.springcloudalibabasentineldemo.utils.R;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class CommonFallback {
    /**
     * 注意: 必须为 static 函数
     * @param e
     * @return
     */
    public static R fallback(Integer id, Throwable e){
        return R.error(-2,"===被异常降级啦==="+e.getMessage());
    }
    public String getNacosConfigure() {
        return "===被异常降级啦===";
    }
}


创建MyBlockExceptionHandler


代码如下(示例):

package com.example.springcloudalibabasentineldemo.sentinel;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.example.springcloudalibabasentineldemo.utils.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Slf4j
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        log.info("BlockExceptionHandler BlockException================"+e.getRule());
        R r = null;
        if (e instanceof FlowException) {
            r = R.error(100,"接口限流了");
        } else if (e instanceof DegradeException) {
            r = R.error(101,"服务降级了");
        } else if (e instanceof ParamFlowException) {
            r = R.error(102,"热点参数限流了");
        } else if (e instanceof SystemBlockException) {
            r = R.error(103,"触发系统保护规则了");
        } else if (e instanceof AuthorityException) {
            r = R.error(104,"授权规则不通过");
        }
        //返回json数据
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getWriter(), r);
    }
}


创建MyRequestOriginParser


代码如下(示例):

package com.example.springcloudalibabasentineldemo.sentinel;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import javax.servlet.http.HttpServletRequest;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
//@Component
public class MyRequestOriginParser implements RequestOriginParser {
    /**
     * 通过request获取来源标识,交给授权规则进行匹配
     * @param request
     * @return
     */
    @Override
    public String parseOrigin(HttpServletRequest request) {
        // 标识字段名称可以自定义
        String origin = request.getParameter("serviceName");
//        if (StringUtil.isBlank(origin)){
//            throw new IllegalArgumentException("serviceName参数未指定");
//        }
        return origin;
    }
}


创建MyUrlBlockHandler


代码如下(示例):

package com.example.springcloudalibabasentineldemo.sentinel;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.example.springcloudalibabasentineldemo.utils.R;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Slf4j
public class MyUrlBlockHandler implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest request, HttpServletResponse response, BlockException e) throws IOException {
        log.info("UrlBlockHandler BlockException================"+e.getRule());
        R r = null;
        if (e instanceof FlowException) {
            r = R.error(100,"接口限流了");
        } else if (e instanceof DegradeException) {
            r = R.error(101,"服务降级了");
        } else if (e instanceof ParamFlowException) {
            r = R.error(102,"热点参数限流了");
        } else if (e instanceof SystemBlockException) {
            r = R.error(103,"触发系统保护规则了");
        } else if (e instanceof AuthorityException) {
            r = R.error(104,"授权规则不通过");
        }
        //返回json数据
        response.setStatus(500);
        response.setCharacterEncoding("utf-8");
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        new ObjectMapper().writeValue(response.getWriter(), r);
    }
}


创建UserServiceImpl


代码如下(示例):

package com.example.springcloudalibabasentineldemo.service.impl;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springcloudalibabasentineldemo.dao.UserDao;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.service.UserService;
import com.example.springcloudalibabasentineldemo.utils.PageUtils;
import com.example.springcloudalibabasentineldemo.utils.Query;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>()
        );
        return new PageUtils(page);
    }
    @Override
    @SentinelResource(value = "getUser")  //aop
    public UserEntity getUser(int id){
        UserEntity user = baseMapper.selectById(id);
        return user;
    }
    public UserEntity handleException(int id, BlockException ex) {
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername("===被限流降级啦===");
        return userEntity;
    }
}


创建UserService


代码如下(示例):

package com.example.springcloudalibabasentineldemo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springcloudalibabasentineldemo.entity.UserEntity;
import com.example.springcloudalibabasentineldemo.utils.PageUtils;
import java.util.Map;
/**
 * @description:
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public interface UserService extends IService<UserEntity> {
    PageUtils queryPage(Map<String, Object> params);
    UserEntity getUser(int id);
}


创建Constant


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.utils;
/**
 * @description:常量
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class Constant {
  /** 超级管理员ID */
  public static final int SUPER_ADMIN = 1;
    /**
     * 当前页码
     */
    public static final String PAGE = "page";
    /**
     * 每页显示记录数
     */
    public static final String LIMIT = "limit";
    /**
     * 排序字段
     */
    public static final String ORDER_FIELD = "sidx";
    /**
     * 排序方式
     */
    public static final String ORDER = "order";
    /**
     *  升序
     */
    public static final String ASC = "asc";
  /**
   * 菜单类型
   * 
   * @author chenshun
   * @email sunlightcs@gmail.com
   * @date 2016年11月15日 下午1:24:29
   */
    public enum MenuType {
        /**
         * 目录
         */
      CATALOG(0),
        /**
         * 菜单
         */
        MENU(1),
        /**
         * 按钮
         */
        BUTTON(2);
        private int value;
        MenuType(int value) {
            this.value = value;
        }
        public int getValue() {
            return value;
        }
    }
    /**
     * 定时任务状态
     * 
     * @author chenshun
     * @email sunlightcs@gmail.com
     * @date 2016年12月3日 上午12:07:22
     */
    public enum ScheduleStatus {
        /**
         * 正常
         */
      NORMAL(0),
        /**
         * 暂停
         */
      PAUSE(1);
        private int value;
        ScheduleStatus(int value) {
            this.value = value;
        }
        public int getValue() {
            return value;
        }
    }
    /**
     * 云服务商
     */
    public enum CloudService {
        /**
         * 七牛云
         */
        QINIU(1),
        /**
         * 阿里云
         */
        ALIYUN(2),
        /**
         * 腾讯云
         */
        QCLOUD(3);
        private int value;
        CloudService(int value) {
            this.value = value;
        }
        public int getValue() {
            return value;
        }
    }
}


创建PageUtils


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.List;
/**
 * @description:分页工具类
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class PageUtils implements Serializable {
  private static final long serialVersionUID = 1L;
  /**
   * 总记录数
   */
  private int totalCount;
  /**
   * 每页记录数
   */
  private int pageSize;
  /**
   * 总页数
   */
  private int totalPage;
  /**
   * 当前页数
   */
  private int currPage;
  /**
   * 列表数据
   */
  private List<?> list;
  /**
   * 分页
   * @param list        列表数据
   * @param totalCount  总记录数
   * @param pageSize    每页记录数
   * @param currPage    当前页数
   */
  public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
    this.list = list;
    this.totalCount = totalCount;
    this.pageSize = pageSize;
    this.currPage = currPage;
    this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
  }
  /**
   * 分页
   */
  public PageUtils(IPage<?> page) {
    this.list = page.getRecords();
    this.totalCount = (int)page.getTotal();
    this.pageSize = (int)page.getSize();
    this.currPage = (int)page.getCurrent();
    this.totalPage = (int)page.getPages();
  }
  public int getTotalCount() {
    return totalCount;
  }
  public void setTotalCount(int totalCount) {
    this.totalCount = totalCount;
  }
  public int getPageSize() {
    return pageSize;
  }
  public void setPageSize(int pageSize) {
    this.pageSize = pageSize;
  }
  public int getTotalPage() {
    return totalPage;
  }
  public void setTotalPage(int totalPage) {
    this.totalPage = totalPage;
  }
  public int getCurrPage() {
    return currPage;
  }
  public void setCurrPage(int currPage) {
    this.currPage = currPage;
  }
  public List<?> getList() {
    return list;
  }
  public void setList(List<?> list) {
    this.list = list;
  }
}


创建Query


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.utils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.springcloudalibabasentineldemo.xss.SQLFilter;
import org.apache.commons.lang.StringUtils;
import java.util.Map;
/**
 * @description:查询参数
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class Query<T> {
    public IPage<T> getPage(Map<String, Object> params) {
        return this.getPage(params, null, false);
    }
    public IPage<T> getPage(Map<String, Object> params, String defaultOrderField, boolean isAsc) {
        //分页参数
        long curPage = 1;
        long limit = 10;
        if(params.get(Constant.PAGE) != null){
            curPage = Long.parseLong((String)params.get(Constant.PAGE));
        }
        if(params.get(Constant.LIMIT) != null){
            limit = Long.parseLong((String)params.get(Constant.LIMIT));
        }
        //分页对象
        Page<T> page = new Page<>(curPage, limit);
        //分页参数
        params.put(Constant.PAGE, page);
        //排序字段
        //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险)
        String orderField = SQLFilter.sqlInject((String)params.get(Constant.ORDER_FIELD));
        String order = (String)params.get(Constant.ORDER);
        //前端字段排序
        if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){
            if(Constant.ASC.equalsIgnoreCase(order)) {
                return  page.addOrder(OrderItem.asc(orderField));
            }else {
                return page.addOrder(OrderItem.desc(orderField));
            }
        }
        //没有排序字段,则不排序
        if(StringUtils.isBlank(defaultOrderField)){
            return page;
        }
        //默认排序
        if(isAsc) {
            page.addOrder(OrderItem.asc(defaultOrderField));
        }else {
            page.addOrder(OrderItem.desc(defaultOrderField));
        }
        return page;
    }
}


创建R


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.utils;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
/**
 * @description:返回数据
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class R extends HashMap<String, Object> {
  private static final long serialVersionUID = 1L;
  public R() {
    put("code", 0);
    put("msg", "success");
  }
  public static R error() {
    return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
  }
  public static R error(String msg) {
    return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
  }
  public static R error(int code, String msg) {
    R r = new R();
    r.put("code", code);
    r.put("msg", msg);
    return r;
  }
  public static R ok(String msg) {
    R r = new R();
    r.put("msg", msg);
    return r;
  }
  public static R ok(Map<String, Object> map) {
    R r = new R();
    r.putAll(map);
    return r;
  }
  public static R ok() {
    return new R();
  }
  public R put(String key, Object value) {
    super.put(key, value);
    return this;
  }
}


创建HTMLFilter


代码如下(示例):

package com.example.springcloudalibabasentineldemo.xss;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 *
 * HTML filtering utility for protecting against XSS (Cross Site Scripting).
 *
 * This code is licensed LGPLv3
 *
 * This code is a Java port of the original work in PHP by Cal Hendersen.
 * http://code.iamcal.com/php/lib_filter/
 *
 * The trickiest part of the translation was handling the differences in regex handling
 * between PHP and Java.  These resources were helpful in the process:
 *
 * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html
 * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php
 * http://www.regular-expressions.info/modifiers.html
 *
 * A note on naming conventions: instance variables are prefixed with a "v"; global
 * constants are in all caps.
 *
 * Sample use:
 * String input = ...
 * String clean = new HTMLFilter().filter( input );
 *
 * The class is not thread safe. Create a new instance if in doubt.
 *
 * If you find bugs or have suggestions on improvement (especially regarding
 * performance), please contact us.  The latest version of this
 * source, and our contact details, can be found at http://xss-html-filter.sf.net
 *
 * @author Joseph O'Connell
 * @author Cal Hendersen
 * @author Michael Semb Wever
 */
public final class HTMLFilter {
    /** regex flag union representing /si modifiers in php **/
    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
    private static final Pattern P_END_ARROW = Pattern.compile("^>");
    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_AMP = Pattern.compile("&");
    private static final Pattern P_QUOTE = Pattern.compile("<");
    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
    // @xxx could grow large... maybe use sesat's ReferenceMap
    private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
    private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
    /** set of allowed html elements, along with allowed attributes for each element **/
    private final Map<String, List<String>> vAllowed;
    /** counts of open tags for each (allowable) html element **/
    private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
    /** html elements which must always be self-closing (e.g. "<img />") **/
    private final String[] vSelfClosingTags;
    /** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/
    private final String[] vNeedClosingTags;
    /** set of disallowed html elements **/
    private final String[] vDisallowed;
    /** attributes which should be checked for valid protocols **/
    private final String[] vProtocolAtts;
    /** allowed protocols **/
    private final String[] vAllowedProtocols;
    /** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/
    private final String[] vRemoveBlanks;
    /** entities allowed within html markup **/
    private final String[] vAllowedEntities;
    /** flag determining whether comments are allowed in input String. */
    private final boolean stripComment;
    private final boolean encodeQuotes;
    private boolean vDebug = false;
    /**
     * flag determining whether to try to make tags when presented with "unbalanced"
     * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>").  If set to false,
     * unbalanced angle brackets will be html escaped.
     */
    private final boolean alwaysMakeTags;
    /** Default constructor.
     *
     */
    public HTMLFilter() {
        vAllowed = new HashMap<>();
        final ArrayList<String> a_atts = new ArrayList<String>();
        a_atts.add("href");
        a_atts.add("target");
        vAllowed.put("a", a_atts);
        final ArrayList<String> img_atts = new ArrayList<String>();
        img_atts.add("src");
        img_atts.add("width");
        img_atts.add("height");
        img_atts.add("alt");
        vAllowed.put("img", img_atts);
        final ArrayList<String> no_atts = new ArrayList<String>();
        vAllowed.put("b", no_atts);
        vAllowed.put("strong", no_atts);
        vAllowed.put("i", no_atts);
        vAllowed.put("em", no_atts);
        vSelfClosingTags = new String[]{"img"};
        vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
        vDisallowed = new String[]{};
        vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp.
        vProtocolAtts = new String[]{"src", "href"};
        vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
        vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
        stripComment = true;
        encodeQuotes = true;
        alwaysMakeTags = true;
    }
    /** Set debug flag to true. Otherwise use default settings. See the default constructor.
     *
     * @param debug turn debug on with a true argument
     */
    public HTMLFilter(final boolean debug) {
        this();
        vDebug = debug;
    }
    /** Map-parameter configurable constructor.
     *
     * @param conf map containing configuration. keys match field names.
     */
    public HTMLFilter(final Map<String,Object> conf) {
        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
        vDisallowed = (String[]) conf.get("vDisallowed");
        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
        stripComment =  conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
    }
    private void reset() {
        vTagCounts.clear();
    }
    private void debug(final String msg) {
        if (vDebug) {
            Logger.getAnonymousLogger().info(msg);
        }
    }
    //---------------------------------------------------------------
    // my versions of some PHP library functions
    public static String chr(final int decimal) {
        return String.valueOf((char) decimal);
    }
    public static String htmlSpecialChars(final String s) {
        String result = s;
        result = regexReplace(P_AMP, "&amp;", result);
        result = regexReplace(P_QUOTE, "&quot;", result);
        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
        return result;
    }
    //---------------------------------------------------------------
    /**
     * given a user submitted input String, filter out any invalid or restricted
     * html.
     *
     * @param input text (i.e. submitted by a user) than may contain html
     * @return "clean" version of input, with only valid, whitelisted html elements allowed
     */
    public String filter(final String input) {
        reset();
        String s = input;
        debug("************************************************");
        debug("              INPUT: " + input);
        s = escapeComments(s);
        debug("     escapeComments: " + s);
        s = balanceHTML(s);
        debug("        balanceHTML: " + s);
        s = checkTags(s);
        debug("          checkTags: " + s);
        s = processRemoveBlanks(s);
        debug("processRemoveBlanks: " + s);
        s = validateEntities(s);
        debug("    validateEntites: " + s);
        debug("************************************************\n\n");
        return s;
    }
    public boolean isAlwaysMakeTags(){
        return alwaysMakeTags;
    }
    public boolean isStripComments(){
        return stripComment;
    }
    private String escapeComments(final String s) {
        final Matcher m = P_COMMENTS.matcher(s);
        final StringBuffer buf = new StringBuffer();
        if (m.find()) {
            final String match = m.group(1); //(.*?)
            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
        }
        m.appendTail(buf);
        return buf.toString();
    }
    private String balanceHTML(String s) {
        if (alwaysMakeTags) {
            //
            // try and form html
            //
            s = regexReplace(P_END_ARROW, "", s);
            s = regexReplace(P_BODY_TO_END, "<$1>", s);
            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
        } else {
            //
            // escape stray brackets
            //
            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
            //
            // the last regexp causes '<>' entities to appear
            // (we need to do a lookahead assertion so that the last bracket can
            // be used in the next pass of the regexp)
            //
            s = regexReplace(P_BOTH_ARROWS, "", s);
        }
        return s;
    }
    private String checkTags(String s) {
        Matcher m = P_TAGS.matcher(s);
        final StringBuffer buf = new StringBuffer();
        while (m.find()) {
            String replaceStr = m.group(1);
            replaceStr = processTag(replaceStr);
            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
        }
        m.appendTail(buf);
        s = buf.toString();
        // these get tallied in processTag
        // (remember to reset before subsequent calls to filter method)
        for (String key : vTagCounts.keySet()) {
            for (int ii = 0; ii < vTagCounts.get(key); ii++) {
                s += "</" + key + ">";
            }
        }
        return s;
    }
    private String processRemoveBlanks(final String s) {
        String result = s;
        for (String tag : vRemoveBlanks) {
            if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
            }
            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
            if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
            }
            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
        }
        return result;
    }
    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) {
        Matcher m = regex_pattern.matcher(s);
        return m.replaceAll(replacement);
    }
    private String processTag(final String s) {
        // ending tags
        Matcher m = P_END_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            if (allowed(name)) {
                if (!inArray(name, vSelfClosingTags)) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) - 1);
                        return "</" + name + ">";
                    }
                }
            }
        }
        // starting tags
        m = P_START_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            final String body = m.group(2);
            String ending = m.group(3);
            //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
            if (allowed(name)) {
                String params = "";
                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
                final List<String> paramNames = new ArrayList<String>();
                final List<String> paramValues = new ArrayList<String>();
                while (m2.find()) {
                    paramNames.add(m2.group(1)); //([a-z0-9]+)
                    paramValues.add(m2.group(3)); //(.*?)
                }
                while (m3.find()) {
                    paramNames.add(m3.group(1)); //([a-z0-9]+)
                    paramValues.add(m3.group(3)); //([^\"\\s']+)
                }
                String paramName, paramValue;
                for (int ii = 0; ii < paramNames.size(); ii++) {
                    paramName = paramNames.get(ii).toLowerCase();
                    paramValue = paramValues.get(ii);
//          debug( "paramName='" + paramName + "'" );
//          debug( "paramValue='" + paramValue + "'" );
//          debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
                    if (allowedAttribute(name, paramName)) {
                        if (inArray(paramName, vProtocolAtts)) {
                            paramValue = processParamProtocol(paramValue);
                        }
                        params += " " + paramName + "=\"" + paramValue + "\"";
                    }
                }
                if (inArray(name, vSelfClosingTags)) {
                    ending = " /";
                }
                if (inArray(name, vNeedClosingTags)) {
                    ending = "";
                }
                if (ending == null || ending.length() < 1) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) + 1);
                    } else {
                        vTagCounts.put(name, 1);
                    }
                } else {
                    ending = " /";
                }
                return "<" + name + params + ending + ">";
            } else {
                return "";
            }
        }
        // comments
        m = P_COMMENT.matcher(s);
        if (!stripComment && m.find()) {
            return  "<" + m.group() + ">";
        }
        return "";
    }
    private String processParamProtocol(String s) {
        s = decodeEntities(s);
        final Matcher m = P_PROTOCOL.matcher(s);
        if (m.find()) {
            final String protocol = m.group(1);
            if (!inArray(protocol, vAllowedProtocols)) {
                // bad protocol, turn into local anchor link instead
                s = "#" + s.substring(protocol.length() + 1, s.length());
                if (s.startsWith("#//")) {
                    s = "#" + s.substring(3, s.length());
                }
            }
        }
        return s;
    }
    private String decodeEntities(String s) {
        StringBuffer buf = new StringBuffer();
        Matcher m = P_ENTITY.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.decode(match).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        buf = new StringBuffer();
        m = P_ENTITY_UNICODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        buf = new StringBuffer();
        m = P_ENCODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
        s = validateEntities(s);
        return s;
    }
    private String validateEntities(final String s) {
        StringBuffer buf = new StringBuffer();
        // validate entities throughout the string
        Matcher m = P_VALID_ENTITIES.matcher(s);
        while (m.find()) {
            final String one = m.group(1); //([^&;]*)
            final String two = m.group(2); //(?=(;|&|$))
            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
        }
        m.appendTail(buf);
        return encodeQuotes(buf.toString());
    }
    private String encodeQuotes(final String s){
        if(encodeQuotes){
            StringBuffer buf = new StringBuffer();
            Matcher m = P_VALID_QUOTES.matcher(s);
            while (m.find()) {
                final String one = m.group(1); //(>|^)
                final String two = m.group(2); //([^<]+?)
                final String three = m.group(3); //(<|$)
                m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
            }
            m.appendTail(buf);
            return buf.toString();
        }else{
            return s;
        }
    }
    private String checkEntity(final String preamble, final String term) {
        return ";".equals(term) && isValidEntity(preamble)
                ? '&' + preamble
                : "&amp;" + preamble;
    }
    private boolean isValidEntity(final String entity) {
        return inArray(entity, vAllowedEntities);
    }
    private static boolean inArray(final String s, final String[] array) {
        for (String item : array) {
            if (item != null && item.equals(s)) {
                return true;
            }
        }
        return false;
    }
    private boolean allowed(final String name) {
        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
    }
    private boolean allowedAttribute(final String name, final String paramName) {
        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
    }
}


创建SQLFilter


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.xss;
import com.example.springcloudalibabasentineldemo.exception.RRException;
import org.apache.commons.lang.StringUtils;
/**
 * @description:SQL过滤
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class SQLFilter {
    /**
     * SQL注入过滤
     * @param str  待验证的字符串
     */
    public static String sqlInject(String str){
        if(StringUtils.isBlank(str)){
            return null;
        }
        //去掉'|"|;|\字符
        str = StringUtils.replace(str, "'", "");
        str = StringUtils.replace(str, "\"", "");
        str = StringUtils.replace(str, ";", "");
        str = StringUtils.replace(str, "\\", "");
        //转换成小写
        str = str.toLowerCase();
        //非法字符
        String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"};
        //判断是否包含非法字符
        for(String keyword : keywords){
            if(str.indexOf(keyword) != -1){
                throw new RRException("包含非法字符");
            }
        }
        return str;
    }
}


创建XssFilter


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.xss;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * @description:XSS过滤
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class XssFilter implements Filter {
  @Override
  public void init(FilterConfig config) throws ServletException {
  }
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
    XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
        (HttpServletRequest) request);
    chain.doFilter(xssRequest, response);
  }
  @Override
  public void destroy() {
  }
}


创建XssHttpServletRequestWrapper


代码如下(示例):

/**
 * Copyright (c) 2016-2019 人人开源 All rights reserved.
 *
 * https://www.renren.io
 *
 * 版权所有,侵权必究!
 */
package com.example.springcloudalibabasentineldemo.xss;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 * @description:XSS过滤处理
 * @author: zhiweiLiao
 * @date: 2022-09-13 15:28
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    //没被包装过的HttpServletRequest(特殊场景,需要自己过滤)
    HttpServletRequest orgRequest;
    //html过滤
    private final static HTMLFilter htmlFilter = new HTMLFilter();
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //非json类型,直接返回
        if(!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(super.getHeader(HttpHeaders.CONTENT_TYPE))){
            return super.getInputStream();
        }
        //为空,直接返回
        String json = IOUtils.toString(super.getInputStream(), "utf-8");
        if (StringUtils.isBlank(json)) {
            return super.getInputStream();
        }
        //xss过滤
        json = xssEncode(json);
        final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return true;
            }
            @Override
            public boolean isReady() {
                return true;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return bis.read();
            }
        };
    }
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(xssEncode(name));
        if (StringUtils.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    }
    @Override
    public String[] getParameterValues(String name) {
        String[] parameters = super.getParameterValues(name);
        if (parameters == null || parameters.length == 0) {
            return null;
        }
        for (int i = 0; i < parameters.length; i++) {
            parameters[i] = xssEncode(parameters[i]);
        }
        return parameters;
    }
    @Override
    public Map<String,String[]> getParameterMap() {
        Map<String,String[]> map = new LinkedHashMap<>();
        Map<String,String[]> parameters = super.getParameterMap();
        for (String key : parameters.keySet()) {
            String[] values = parameters.get(key);
            for (int i = 0; i < values.length; i++) {
                values[i] = xssEncode(values[i]);
            }
            map.put(key, values);
        }
        return map;
    }
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(xssEncode(name));
        if (StringUtils.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    }
    private String xssEncode(String input) {
        return htmlFilter.filter(input);
    }
    /**
     * 获取最原始的request
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    }
    /**
     * 获取最原始的request
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
        if (request instanceof XssHttpServletRequestWrapper) {
            return ((XssHttpServletRequestWrapper) request).getOrgRequest();
        }
        return request;
    }
}


创建UserDao.xml


代码如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springcloudalibabasentineldemo.dao.UserDao">
  <!-- 可根据自己的需求,是否要使用 -->
    <resultMap type="com.example.springcloudalibabasentineldemo.entity.UserEntity" id="userMap">
        <result property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="age" column="age"/>
    </resultMap>
</mapper>


文章关联地址:https://liaozhiwei.blog.csdn.net/article/details/127160493

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
2天前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
10天前
|
前端开发 Java 数据库连接
Spring 框架:Java 开发者的春天
Spring 框架是一个功能强大的开源框架,主要用于简化 Java 企业级应用的开发,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,并由Pivotal团队维护。
32 1
Spring 框架:Java 开发者的春天
|
18天前
|
设计模式 前端开发 Java
Spring MVC——项目创建和建立请求连接
MVC是一种软件架构设计模式,将应用分为模型、视图和控制器三部分。Spring MVC是基于MVC模式的Web框架,通过`@RequestMapping`等注解实现URL路由映射,支持GET和POST请求,并可传递参数。创建Spring MVC项目与Spring Boot类似,使用`@RestController`注解标记控制器类。
30 1
Spring MVC——项目创建和建立请求连接
|
18天前
|
Java 关系型数据库 MySQL
Maven——创建 Spring Boot项目
Maven 是一个项目管理工具,通过配置 `pom.xml` 文件自动获取所需的 jar 包,简化了项目的构建和管理过程。其核心功能包括项目构建和依赖管理,支持创建、编译、测试、打包和发布项目。Maven 仓库分为本地仓库和远程仓库,远程仓库包括中央仓库、私服和其他公共库。此外,文档还介绍了如何创建第一个 SpringBoot 项目并实现简单的 HTTP 请求响应。
85 1
Maven——创建 Spring Boot项目
|
10天前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
10天前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
24 2
|
10天前
|
JSON Java 开发工具
Java服务端集成Google FCM推送的注意事项和实际经验
本文分享了作者在公司APP海外发布过程中,选择Google FCM进行消息推送的集成经验。文章详细解析了Java集成FCM推送的多种实现方式,包括HTTP请求和SDK集成,并指出了通知栏消息和透传消息的区别与应用场景。同时,作者还探讨了Firebase项目的创建、配置和服务端集成的注意事项,帮助读者解决文档混乱和选择困难的问题。
16 1
|
15天前
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
27 1
|
17天前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
102 1
|
18天前
|
负载均衡 算法 Java
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?
40岁老架构师尼恩分享了关于SpringCloud核心组件的底层原理,特别是针对蚂蚁集团面试中常见的面试题进行了详细解析。内容涵盖了Nacos注册中心的AP/CP模式、Distro和Raft分布式协议、Sentinel的高可用组件、负载均衡组件的实现原理等。尼恩强调了系统化学习的重要性,推荐了《尼恩Java面试宝典PDF》等资料,帮助读者更好地准备面试,提高技术实力,最终实现“offer自由”。更多技术资料和指导,可关注公众号【技术自由圈】获取。
蚂蚁面试:Nacos、Sentinel了解吗?Springcloud 核心底层原理,你知道多少?