feat(SpringDemo): 添加接口重试机制
- 新增重试相关的异常类和枚举类型- 实现重试切面,支持接口级别的重试限制 - 添加重试控制器和相关注解 - 修改数据库连接配置,启用SSL Changes application.yaml AppTest.java AppTest.java BockingQueueDemo.java BuinessException.java DelayQueueDemo.java ErrorType.java FunctionInterfaceDemo.java FutureRelative.java LCR155.java LCR186.java LeetCod42_1.java LeetCode15.java LeetCode45.java LeetCode48.java LeetCode51.java LeetCode392.java LeetCode494.java LeetCode718.java LeetCode_32.java P1.java pom.xml pom.xml pom.xml pom.xml RetryAspect.java RetryController.java RetryLimit.java sadasf.bpmn20.xml sdoih.bpmn SpringDemoApplication.java workflow.md Unversioned Files C:\Users\wenhai\project\javaProject\LeetCode\Activiti7Demo\.gitignore C:\Users\wenhai\project\javaProject\LeetCode\Activiti7Demo\src\main\java\cn\whai\activiti\Activiti7DemoApplication.java C:\Users\wenhai\project\javaProject\LeetCode\Activiti7Demo\src\test\java\cn\whai\activiti\activiti7demo\Activiti7DemoApplicationTests.java C:\Users\wenhai\project\javaProject\LeetCode\Activiti7Demo\src\main\resources\application.yaml C:\Users\wenhai\project\javaProject\LeetCode\Activiti7Demo\pom.xml
This commit is contained in:
parent
9e8153e434
commit
ea493390a6
33
Activiti7Demo/.gitignore
vendored
Normal file
33
Activiti7Demo/.gitignore
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
80
Activiti7Demo/pom.xml
Normal file
80
Activiti7Demo/pom.xml
Normal file
@ -0,0 +1,80 @@
|
||||
<?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>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.5.5</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>cn.whai.activiti</groupId>
|
||||
<artifactId>Activiti7Demo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>Activiti7Demo</name>
|
||||
<description>Activiti7Demo Springboot</description>
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Activiti 7.x依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.activiti</groupId>
|
||||
<artifactId>activiti-spring-boot-starter</artifactId>
|
||||
<version>7.0.0.GA</version>
|
||||
<!-- 由于activiti7是使用mybatis作为orm框架,我这里整合mybatis-plus,所以需要排除mybatis -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- mysql 驱动 -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis-Plus依赖包 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,19 @@
|
||||
package cn.whai.activiti;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication(exclude = {
|
||||
//activiti 默认整合security,屏蔽Security认证
|
||||
SecurityAutoConfiguration.class,
|
||||
ManagementWebSecurityAutoConfiguration.class
|
||||
})
|
||||
public class Activiti7DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Activiti7DemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
18
Activiti7Demo/src/main/resources/application.yaml
Normal file
18
Activiti7Demo/src/main/resources/application.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
server:
|
||||
port: 18080
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: 123456
|
||||
activiti:
|
||||
db-history-used: true
|
||||
history-level: full
|
||||
database-schema-update: true
|
||||
check-process-definitions: false
|
||||
|
||||
mybatis-plus:
|
||||
configuration:
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
48
Activiti7Demo/src/main/resources/sadasf.bpmn20.xml
Normal file
48
Activiti7Demo/src/main/resources/sadasf.bpmn20.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
|
||||
xmlns:dc="http://www.omg.org/spec/DD/20100524/DC"
|
||||
xmlns:di="http://www.omg.org/spec/DD/20100524/DI"
|
||||
id="Definitions_1"
|
||||
targetNamespace="http://bpmn.io/schema/bpmn"
|
||||
exporter="bpmn-js (https://bpmn.io)"
|
||||
exporterVersion="10.3.0">
|
||||
|
||||
<bpmn:process id="Process_1" isExecutable="false">
|
||||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>SequenceFlow_1</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:userTask id="UserTask_1" name="任务">
|
||||
<bpmn:incoming>SequenceFlow_1</bpmn:incoming>
|
||||
<bpmn:outgoing>SequenceFlow_2</bpmn:outgoing>
|
||||
</bpmn:userTask>
|
||||
<bpmn:endEvent id="EndEvent_1">
|
||||
<bpmn:incoming>SequenceFlow_2</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="SequenceFlow_1" sourceRef="StartEvent_1" targetRef="UserTask_1" />
|
||||
<bpmn:sequenceFlow id="SequenceFlow_2" sourceRef="UserTask_1" targetRef="EndEvent_1" />
|
||||
</bpmn:process>
|
||||
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
|
||||
<bpmndi:BPMNShape id="StartEvent_1_di" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="173" y="102" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="UserTask_1_di" bpmnElement="UserTask_1">
|
||||
<dc:Bounds x="263" y="90" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="EndEvent_1_di" bpmnElement="EndEvent_1">
|
||||
<dc:Bounds x="423" y="102" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_1_di" bpmnElement="SequenceFlow_1">
|
||||
<di:waypoint x="209" y="120" />
|
||||
<di:waypoint x="263" y="120" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="SequenceFlow_2_di" bpmnElement="SequenceFlow_2">
|
||||
<di:waypoint x="363" y="120" />
|
||||
<di:waypoint x="423" y="120" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
@ -0,0 +1,24 @@
|
||||
package cn.whai.activiti.activiti7demo;
|
||||
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
import org.activiti.engine.ProcessEngineConfiguration;
|
||||
import org.activiti.engine.RepositoryService;
|
||||
import org.activiti.spring.SpringProcessEngineConfiguration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
@SpringBootTest
|
||||
class Activiti7DemoApplicationTests {
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
|
||||
}
|
||||
|
||||
}
|
57
Activiti7Demo/workflow.md
Normal file
57
Activiti7Demo/workflow.md
Normal file
@ -0,0 +1,57 @@
|
||||
## WordFlow 工作流引擎
|
||||
|
||||
是一种按照预定义规则【需要符合BPMN规范】进行部署,将业务和节点的流程进行分离【特定形式进行关联】,
|
||||
|
||||
|
||||
### 二、什么是Activiti7?
|
||||
|
||||
Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的
|
||||
建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行
|
||||
|
||||
https://www.activiti.org
|
||||
|
||||
2.2 Activiti7内部核心机制
|
||||
|
||||
1️⃣业务流程图要规范化,需要遵守一套标准。
|
||||
|
||||
2️⃣业务流程图本质上就是一个XML文件,而XML可以存放所要的数据。
|
||||
|
||||
3️⃣读取业务流程图的过程就是解析XML文件的过程。
|
||||
|
||||
4️⃣读取一个业务流程图的结点就相当于解析一个XML的结点,进一步将数据插入到MySQL表中,形成一条记录。
|
||||
|
||||
5️⃣将一个业务流程图的所有节点都读取并存入到MySQL表中。
|
||||
|
||||
6️⃣后面只要读取MySQL表中的记录就相当于读取业务流程图的一个节点。
|
||||
|
||||
7️⃣业务流程的推进,后面就转换为读取表中的数据,并且处理数据,结束的时候这一行数据就可以删除了。
|
||||
|
||||
### BPMN
|
||||
|
||||
BPMN(Business Process Model And Notation),业务流程模型和符号,是由BPMI(Business Process Management Initiative)开发的一套的业务流程建模符号,使用BPMN提供的符号可以创建业务流程。2004年5月发布了BPMN1.0规范。
|
||||
|
||||
> [processOn BPMN 概念](https://www.processon.com/knowledge/bpmndiagram)
|
||||
>
|
||||
> ### BPMN 的核心元素
|
||||
> - 活动:活动是 BPMN 中最基本的元素之一,它代表了业务流程中的一个具体任务或操作。可以自动/手动、
|
||||
> - 事件:事件是 BPMN 中用于表示流程中的特定时刻或状态的元素。例如,开始事件、结束事件、中间事件等。
|
||||
> - 网关:网关用于控制流程的执行路径,可以实现并行、条件、互斥等多种逻辑。
|
||||
> - 泳道:泳道用于将流程分解为多个并行的部分,每个泳道代表一个独立的执行路径。
|
||||
|
||||
> 一个BPMN的例子:
|
||||
> - 当事人填写请假单,启动流程后把请假单ID绑定到流程中;
|
||||
> - 部门经理对请假单进行审核;
|
||||
> - 然后人事经理进行复核并进行备案;
|
||||
> - 最后请假流程结束。
|
||||
|
||||
### Activiti支持的数据库
|
||||
|
||||
- Activiti的运行需要数据库的支撑,支持如下:
|
||||
- h2
|
||||
- MySQL
|
||||
- Oracle
|
||||
- Db2
|
||||
- postgres
|
||||
- mysql
|
||||
|
||||
- 在Navicat工具中创建`activiti`的数据库,用于后续的实验.
|
@ -2,7 +2,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.example</groupId>
|
||||
<groupId>com.whai</groupId>
|
||||
<artifactId>LeetCode</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
83
ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java
Normal file
83
ForJdk17/src/main/java/cn/whaifree/interview/js/P1.java
Normal file
@ -0,0 +1,83 @@
|
||||
package cn.whaifree.interview.js;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/10 19:27
|
||||
* @注释
|
||||
*/
|
||||
public class P1 {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.out.println(Arrays.toString(new P1().solve(new int[]{2,3,2,3,2})));
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
|
||||
*
|
||||
*
|
||||
* @param arr int整型一维数组
|
||||
* @return int整型一维数组
|
||||
*/
|
||||
public int[] solve (int[] arr) {
|
||||
// write code here
|
||||
|
||||
Map<Integer, List<Integer>> map = new HashMap<>();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (!map.containsKey(arr[i])) {
|
||||
map.put(arr[i], new ArrayList<>());
|
||||
}
|
||||
map.get(arr[i]).add(i + 1);
|
||||
}
|
||||
|
||||
int[] res = new int[arr.length];
|
||||
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
|
||||
List<Integer> value = entry.getValue();
|
||||
if (value.size() == 2) {
|
||||
Integer a = value.get(1);
|
||||
Integer b = value.get(0);
|
||||
res[b - 1] = a;
|
||||
res[a - 1] = b;
|
||||
}else {
|
||||
for (Integer i : value) {
|
||||
res[i - 1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
class p2{
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(new p2().solve(new int[]{1, 2}));
|
||||
}
|
||||
/**
|
||||
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
|
||||
*
|
||||
*
|
||||
* @param arr int整型一维数组
|
||||
* @return long长整型
|
||||
*/
|
||||
public long solve (int[] arr) {
|
||||
int n = arr.length;
|
||||
int[][] dp = new int[n][n];
|
||||
for (int len = 2; len <= n; len++) {
|
||||
for (int i = 0; i <= n - len; i++) {
|
||||
int j = i + len - 1;
|
||||
if (arr[i] == arr[j]) {
|
||||
dp[i][j] = dp[i + 1][j - 1];
|
||||
}else {
|
||||
dp[i][j] = Math.min(dp[i + 1][j], dp[i][j - 1]) +
|
||||
Math.abs(arr[i] - arr[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
int i = dp[0][n - 1];
|
||||
return i;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/9 18:04
|
||||
* @注释
|
||||
*/
|
||||
public class LCR155 {
|
||||
class Node {
|
||||
public int val;
|
||||
public Node left;
|
||||
public Node right;
|
||||
|
||||
public Node() {}
|
||||
|
||||
public Node(int _val) {
|
||||
val = _val;
|
||||
}
|
||||
|
||||
public Node(int _val,Node _left,Node _right) {
|
||||
val = _val;
|
||||
left = _left;
|
||||
right = _right;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
Node node = new Node(4);
|
||||
Node node1 = solution.treeToDoublyList(node);
|
||||
System.out.println(node1);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
Node head = new Node(-1);
|
||||
Node index = head;
|
||||
|
||||
public Node treeToDoublyList(Node root) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
in(root);
|
||||
index.right = head.right;
|
||||
head.right.left = index;
|
||||
return head.right;
|
||||
}
|
||||
|
||||
public void in(Node root) {
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
in(root.left);
|
||||
index.right = root;
|
||||
root.left = index;
|
||||
index = root;
|
||||
in(root.right);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/9 18:20
|
||||
* @注释
|
||||
*/
|
||||
public class LCR186 {
|
||||
|
||||
class Solution {
|
||||
public boolean checkDynasty(int[] places) {
|
||||
int[] set = new int[14];
|
||||
int min = Integer.MAX_VALUE;
|
||||
int max = Integer.MIN_VALUE;
|
||||
for (int i = 0; i < places.length; i++) {
|
||||
if (places[i] == 0) {
|
||||
continue;
|
||||
// 差值为5以内,并且不重复,就能推出这是个顺子
|
||||
}
|
||||
if (set[places[i]] != 0) {
|
||||
// 已经存在,直接返回
|
||||
return false;
|
||||
}
|
||||
set[places[i]]++;
|
||||
min = Math.min(min, places[i]);
|
||||
max = Math.max(max, places[i]);
|
||||
}
|
||||
return max - min < 5;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/11 10:36
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCod42_1 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] height = {4,2,0,3,2,5};
|
||||
int trap = new Solution().trap(height);
|
||||
System.out.println(trap);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 每个位置左边第一个比他大的
|
||||
* @param height
|
||||
* @return
|
||||
*/
|
||||
public int trap(int[] height) {
|
||||
Deque<Integer> stack = new ArrayDeque<>();
|
||||
stack.push(0);
|
||||
int res = 0;
|
||||
for (int i = 1; i < height.length; i++) {
|
||||
while (!stack.isEmpty() && height[stack.peek()] < height[i]) {
|
||||
// 单调递增
|
||||
Integer pop = stack.pop();
|
||||
int level = height[pop];
|
||||
if (!stack.isEmpty()) {
|
||||
int left = stack.peek();
|
||||
int right = i;
|
||||
int sub = Math.min(height[left], height[right]) - level;
|
||||
res += sub * (right - left - 1);
|
||||
}
|
||||
}
|
||||
stack.push(i);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/6 13:20
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode15 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1,2,-2,-1};
|
||||
System.out.println(new Solution().threeSum(nums));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
|
||||
public List<List<Integer>> threeSum(int[] nums) {
|
||||
Arrays.sort(nums);
|
||||
List<List<Integer>> res = new ArrayList<>();
|
||||
for (int left = 0; left < nums.length; left++) {
|
||||
|
||||
if (left > 0 && nums[left] == nums[left - 1]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int mid = left + 1;
|
||||
int right = nums.length - 1;
|
||||
while (mid < right) {
|
||||
int sum = nums[left] + nums[mid] + nums[right];
|
||||
if (sum == 0) {
|
||||
res.add(Arrays.asList(nums[left], nums[mid], nums[right]));
|
||||
|
||||
while (mid < right && nums[mid] == nums[mid + 1]) {
|
||||
mid++;
|
||||
}
|
||||
while (mid < right && nums[right] == nums[right - 1]) {
|
||||
right--;
|
||||
}
|
||||
mid++;
|
||||
right--;
|
||||
} else if (sum < 0) {
|
||||
mid++;
|
||||
} else {
|
||||
right--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/8 17:22
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode392 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
System.out.println(new Solution().isSubsequence("abc", "ahbgdc"));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public boolean isSubsequence(String s, String t) {
|
||||
if (s.isBlank()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int sIndex = 0;
|
||||
int i = 0;
|
||||
for (; i < t.length(); i++) {
|
||||
if (sIndex == s.length()) {
|
||||
break;
|
||||
}
|
||||
if (s.charAt(sIndex) == t.charAt(i)) {
|
||||
sIndex++;
|
||||
}
|
||||
}
|
||||
return sIndex == s.length();
|
||||
}
|
||||
|
||||
}
|
||||
@Test
|
||||
public void test2() {
|
||||
System.out.println(new Solution1().isSubsequence("abc", "ahbgdc"));
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
*
|
||||
* ''a h b g d c
|
||||
* '' 1 1 1 1 1 1 1
|
||||
* a 0 1 1 1 1 1 1
|
||||
* b 0 0 0 1 1 1 1
|
||||
* c 0 0 0 0 0 0 1
|
||||
*
|
||||
* 0-1背包问题,
|
||||
* @param s
|
||||
* @param t
|
||||
* @return
|
||||
*/
|
||||
public boolean isSubsequence(String s, String t) {
|
||||
boolean[][] dp = new boolean[s.length() + 1][t.length() + 1];
|
||||
for (int i = 0; i < t.length() + 1; i++) {
|
||||
dp[0][i] = true;
|
||||
}
|
||||
for (int i = 1; i <= s.length(); i++) {
|
||||
for (int j = 1; j <= t.length(); j++) {
|
||||
if (s.charAt(i - 1) != t.charAt(j - 1) || !dp[i - 1][j - 1]) {
|
||||
dp[i][j] = dp[i][j - 1];
|
||||
} else {
|
||||
dp[i][j] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[s.length()][t.length()];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/8 19:52
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode45 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {2,3,1,1,4};
|
||||
int jump = new Solution().jump(nums);
|
||||
System.out.println(jump);
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
*
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int jump(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
return 0;
|
||||
}
|
||||
int curCover = 0;
|
||||
int maxCover = 0;
|
||||
int jump = 0;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
maxCover = Math.max(maxCover, i + nums[i]);
|
||||
// 如果从这个 起跳点 起跳叫做第 1 次 跳跃,
|
||||
// 那么从后面 nums[0]个格子起跳 都 可以叫做第 2 次 跳跃。
|
||||
if (i == curCover) {
|
||||
curCover = maxCover;
|
||||
jump++;
|
||||
}
|
||||
if (curCover >= nums.length - 1) {
|
||||
return jump;
|
||||
}
|
||||
}
|
||||
return jump;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
int[] nums = {2,3,1,1,4};
|
||||
int jump = new Solution1().jump(nums);
|
||||
System.out.println(jump);
|
||||
}
|
||||
|
||||
class Solution1 {
|
||||
/**
|
||||
* [2,3,1,1,4]
|
||||
* 0 1 1 2 2
|
||||
* @param nums
|
||||
* @return
|
||||
*/
|
||||
public int jump(int[] nums) {
|
||||
if (nums.length == 1) {
|
||||
return 0;
|
||||
}
|
||||
// 动态规划
|
||||
int[] dp = new int[nums.length];
|
||||
dp[0] = 0;
|
||||
for (int i = 1; i < nums.length; i++) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (nums[j] >= i - j) {
|
||||
min = Math.min(min, dp[j] + 1);
|
||||
}
|
||||
}
|
||||
dp[i] = min;
|
||||
}
|
||||
return dp[nums.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/6 13:31
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode48 {
|
||||
|
||||
class Solution {
|
||||
public void rotate(int[][] matrix) {
|
||||
int len = matrix.length;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
for (int j = i; j < len; j++) {
|
||||
int x = i;
|
||||
int y = j;
|
||||
int n = len - 1;
|
||||
int tmp = matrix[x][y];
|
||||
matrix[x][y] = matrix[n - y][x];
|
||||
matrix[n - y][x] = matrix[n - x][n - y];
|
||||
matrix[n - x][n - y] = matrix[y][n - x];
|
||||
matrix[y][n - x] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/10 17:19
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode494 {
|
||||
|
||||
class Solution {
|
||||
|
||||
/**
|
||||
* 背包问题
|
||||
*
|
||||
* 1 2 1 1 1 ; 3
|
||||
* x为需要变成负数的数量
|
||||
*
|
||||
* sum = x * 2 + target
|
||||
*
|
||||
* x = sum-target /2
|
||||
*
|
||||
* 把nums里装到容量为x的背包中
|
||||
* 有几种方法可以装满
|
||||
*
|
||||
* 0 1 2 3
|
||||
* 1 1 1 0 0
|
||||
* 2 1 1 1 1
|
||||
* 2 1 1 2 2
|
||||
* 1
|
||||
* 1
|
||||
*
|
||||
* 1 2 -2 1 1
|
||||
* 1 2 -2 -1 -1
|
||||
* -1 2 -2 1 -1
|
||||
* -1 2 -2 -1 1
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param nums
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public int findTargetSumWays(int[] nums, int target) {
|
||||
Integer sum = Arrays.stream(nums).sum();
|
||||
int pkgSize = (sum - target) / 2;
|
||||
int[] dp = new int[pkgSize + 1];
|
||||
dp[0] = 1;
|
||||
for (int i = 0; i < nums.length; i++) {
|
||||
for (int j = pkgSize; j >= 0; j--) {
|
||||
if (j >= nums[i]) {
|
||||
dp[j] = dp[j] + dp[j - nums[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[pkgSize];
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] nums = {1};
|
||||
int target = 1;
|
||||
System.out.println(new Solution().findTargetSumWays(nums, target));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/8 18:34
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode51 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
for (List<String> solveNQueen : new Solution().solveNQueens(4)) {
|
||||
System.out.println(solveNQueen);
|
||||
}
|
||||
}
|
||||
class Solution {
|
||||
List<List<String>> res = new ArrayList<>();
|
||||
|
||||
public List<List<String>> solveNQueens(int n) {
|
||||
char[][] map = new char[n][n];
|
||||
for (char[] chars : map) {
|
||||
Arrays.fill(chars, '.');
|
||||
}
|
||||
backTracking(map, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void backTracking(char[][] map, int x) {
|
||||
if (x == map.length) {
|
||||
ArrayList<String> e = new ArrayList<>();
|
||||
for (char[] chars : map) {
|
||||
e.add(new String(chars));
|
||||
}
|
||||
res.add(e);
|
||||
return;
|
||||
}
|
||||
if (x > map.length) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
if (cal(map, x, i)) {
|
||||
map[x][i] = 'Q';
|
||||
backTracking(map, x + 1);
|
||||
map[x][i] = '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 往左上搜索
|
||||
public boolean cal(char[][] map, int x, int y) {
|
||||
// 往左边搜索
|
||||
for (int i = y; i >= 0; i--) {
|
||||
if (map[x][i] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 往上搜索
|
||||
for (int i = x; i >= 0; i--) {
|
||||
if (map[i][y] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 往左上搜索
|
||||
for (int i = x, j = y; i >= 0 && j >= 0; i--, j--) {
|
||||
if (map[i][j] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 往右上搜索
|
||||
for (int i = x, j = y; i >= 0 && j < map.length; i--, j++) {
|
||||
if (map[i][j] == 'Q') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/8 17:16
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode718 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.findLength(new int[]{1, 2, 3, 2, 1, 5, 8, 9}, new int[]{3, 2, 1, 5, 8, 4, 7}));
|
||||
}
|
||||
|
||||
class Solution {
|
||||
/**
|
||||
* 连续
|
||||
* 0-i 0-j内最长公共的子数组的长度
|
||||
*
|
||||
* 1 2 3 2 1
|
||||
* 3 0 0 1 0 0
|
||||
* 2 0 1 0 2 0
|
||||
* 1 1 0 1
|
||||
* 4
|
||||
* 7
|
||||
*
|
||||
* @param nums1
|
||||
* @param nums2
|
||||
* @return
|
||||
*/
|
||||
public int findLength(int[] nums1, int[] nums2) {
|
||||
|
||||
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
|
||||
|
||||
int max = 0;
|
||||
for (int i = 1; i <= nums1.length; i++) {
|
||||
for (int j = 1; j <= nums2.length; j++) {
|
||||
if (nums1[i - 1] == nums2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||
max = Math.max(max, dp[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package cn.whaifree.redo.redo_all_241016;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/11 11:36
|
||||
* @注释
|
||||
*/
|
||||
public class LeetCode_32 {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Solution solution = new Solution();
|
||||
System.out.println(solution.longestValidParentheses("(()(()()"));
|
||||
|
||||
}
|
||||
|
||||
class Solution {
|
||||
public int longestValidParentheses(String s) {
|
||||
|
||||
boolean[] mark = new boolean[s.length()];
|
||||
|
||||
char[] arr = s.toCharArray();
|
||||
Deque<Integer> stack = new ArrayDeque<>();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (arr[i] == '(') {
|
||||
stack.push(i);
|
||||
} else if (!stack.isEmpty()) {
|
||||
Integer pop = stack.pop();
|
||||
mark[pop] = true;
|
||||
mark[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
int left = 0;
|
||||
int right = 0;
|
||||
int maxLen = 0;
|
||||
while (right < mark.length) {
|
||||
if (!mark[right]) {
|
||||
maxLen = Math.max(maxLen, right - left);
|
||||
left = right + 1;
|
||||
}
|
||||
right++;
|
||||
}
|
||||
return Math.max(maxLen, right - left);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package cn.whaifree.tech;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/5 22:22
|
||||
* @注释
|
||||
*/
|
||||
public class BockingQueueDemo {
|
||||
|
||||
|
||||
static int size = 3;
|
||||
static List<String> instanceId = List.of();
|
||||
static {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
instanceId.add("instance" + i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
BlockingQueue<String> queue = new LinkedBlockingQueue<>();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
queue.addAll(instanceId);
|
||||
}
|
||||
}).start();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cn.whaifree.tech.demo.thread;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/5 14:24
|
||||
* @注释
|
||||
*/
|
||||
public class DelayQueueDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
}
|
||||
}
|
@ -17,9 +17,14 @@ public class FutureRelative {
|
||||
final static ExecutorService executorService = Executors.newFixedThreadPool(10,
|
||||
Executors.defaultThreadFactory());
|
||||
|
||||
final static ExecutorService executorService1 = Executors.newScheduledThreadPool(10);
|
||||
|
||||
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
futureTaskDemo();
|
||||
|
||||
// futureTaskDemo();
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.example;
|
||||
package com.whai;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
@ -2,7 +2,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.example</groupId>
|
||||
<groupId>com.whai</groupId>
|
||||
<artifactId>LeetCode</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.whaifree.tech;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.example;
|
||||
package com.whai;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
|
@ -2,7 +2,7 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.example</groupId>
|
||||
<groupId>com.whai</groupId>
|
||||
<artifactId>LeetCode</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
@ -2,8 +2,10 @@ package cn.whaifree.springdemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAspectJAutoProxy
|
||||
public class SpringDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -0,0 +1,22 @@
|
||||
package cn.whaifree.springdemo.controller.interceptRetry;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/10 15:26
|
||||
* @注释
|
||||
*/
|
||||
public class BuinessException extends RuntimeException {
|
||||
@Getter
|
||||
private ErrorType type;
|
||||
private Integer code;
|
||||
|
||||
|
||||
public BuinessException(ErrorType type, Integer code) {
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.whaifree.springdemo.controller.interceptRetry;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/10 15:26
|
||||
* @注释
|
||||
*/
|
||||
public enum ErrorType {
|
||||
RetryType("Retry Too Many", 503);
|
||||
|
||||
private String type;
|
||||
private Integer code;
|
||||
ErrorType (String type, Integer code) {
|
||||
this.type = type;
|
||||
this.code = code;
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package cn.whaifree.springdemo.controller.interceptRetry;
|
||||
|
||||
import cn.whaifree.springdemo.controller.interceptRetry.aspect.RetryLimit;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/9 21:56
|
||||
* @注释
|
||||
*/
|
||||
@RestController
|
||||
public class RetryController {
|
||||
|
||||
@PostMapping("/try")
|
||||
@RetryLimit(limitCount = 3, limitTime = 1, limitKey = "ip", resMsg = "retry请求频繁")
|
||||
public String tryMethod(int success) {
|
||||
if (success == 1) {
|
||||
throw new BuinessException(ErrorType.RetryType, 500);
|
||||
}
|
||||
return "tryMethod";
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package cn.whaifree.springdemo.controller.interceptRetry.aspect;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.whaifree.springdemo.controller.interceptRetry.BuinessException;
|
||||
import cn.whaifree.springdemo.controller.interceptRetry.ErrorType;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mysql.cj.util.LogUtils;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.Getter;
|
||||
import org.apache.catalina.util.RequestUtil;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/9 21:57
|
||||
* @注释
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
@Order(100)
|
||||
public class RetryAspect {
|
||||
|
||||
/**
|
||||
* 一个Cache只能有一个有效期,
|
||||
* 所以要根据有效期进行分组
|
||||
* <p>
|
||||
* 【exprieTime,【keyOfIp,time】】
|
||||
* <p>
|
||||
* <p>
|
||||
* 对不同时间用不同cache实现
|
||||
*/
|
||||
Map<Integer, Cache<String, AtomicInteger>> cacheMap = new HashMap<>();
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
|
||||
for (String beanDefinitionName : beanDefinitionNames) {
|
||||
// 这里有疑问,可能拿到RetryAspect走getBean导致循环依赖,RetryAspect循环依赖RetryAspect
|
||||
if (beanDefinitionName.equalsIgnoreCase(this.getClass().getSimpleName())) {
|
||||
continue;
|
||||
}
|
||||
Object bean = applicationContext.getBean(beanDefinitionName);
|
||||
|
||||
Method[] methods = bean.getClass().getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
try {
|
||||
// 手动用反射获取不到注解
|
||||
RetryLimit retryLimit = AnnotationUtils.findAnnotation(method, RetryLimit.class);
|
||||
// RetryLimit retryLimit = method.getAnnotation(RetryLimit.class);
|
||||
if (retryLimit == null) {
|
||||
continue;
|
||||
}
|
||||
int expireTime = retryLimit.limitTime();
|
||||
Cache<String, AtomicInteger> build = Caffeine.newBuilder().expireAfterAccess(Duration.ofMinutes(expireTime)).maximumSize(1000).build();
|
||||
cacheMap.put(expireTime, build);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
System.out.println(cacheMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Around("@annotation(cn.whaifree.springdemo.controller.interceptRetry.aspect.RetryLimit)")
|
||||
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
|
||||
// 获取方法签名,设置方法可以访问
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
method.setAccessible(true);
|
||||
|
||||
// 获取注解
|
||||
RetryLimit retryAn = AnnotationUtils.findAnnotation(method, RetryLimit.class);
|
||||
if (retryAn == null) {
|
||||
return joinPoint.proceed();
|
||||
}
|
||||
|
||||
// 如果包含注解,放入缓存,key为ip或者其他限流key,value为次数
|
||||
Cache<String, AtomicInteger> cache = cacheMap.get(retryAn.limitTime());
|
||||
String limitKey = retryAn.limitKey();
|
||||
if (limitKey == null || limitKey.equals("ip")) {
|
||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = requestAttributes.getRequest();
|
||||
limitKey = request.getRemoteAddr();
|
||||
}else if (limitKey.equals("userId")) {
|
||||
// 其他策略
|
||||
}
|
||||
// 如果缓存中没有这个ip访问过,初始化为0
|
||||
AtomicInteger atomicInteger = cache.get(limitKey, s -> new AtomicInteger(0));
|
||||
if (atomicInteger.intValue() >= retryAn.limitCount()) {
|
||||
throw new RuntimeException(retryAn.resMsg());
|
||||
}
|
||||
|
||||
try {
|
||||
return joinPoint.proceed();
|
||||
} catch (BuinessException e) {
|
||||
// 如果不是验证错误,向上抛出
|
||||
if (!e.getType().equals(ErrorType.RetryType)) {
|
||||
throw e;
|
||||
}
|
||||
// 如果验证错误,对atomic++
|
||||
atomicInteger.incrementAndGet();
|
||||
String msg = retryAn.resMsg() + ",重试次数:" + atomicInteger.intValue();
|
||||
throw new RuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package cn.whaifree.springdemo.controller.interceptRetry.aspect;
|
||||
|
||||
import cn.whaifree.springdemo.controller.interceptRetry.ErrorType;
|
||||
import cn.whaifree.springdemo.utils.ResVo;
|
||||
import org.springframework.data.redis.connection.ReturnType;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
* @Author whai文海
|
||||
* @Date 2024/11/9 21:57
|
||||
* @注释
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RetryLimit {
|
||||
|
||||
int limitCount() default 3;
|
||||
int limitTime() default 60;
|
||||
String limitKey() default "ip";
|
||||
String resMsg() default "请求过于频繁";
|
||||
ErrorType errorType() default ErrorType.RetryType;
|
||||
|
||||
}
|
@ -8,7 +8,7 @@ my:
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://localhost:3306/springTest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://localhost:3306/springTest?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: 123456
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
4
pom.xml
4
pom.xml
@ -4,10 +4,10 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.example</groupId> <!--groupId表示当前 Maven 项目隶属的组织或公司-->
|
||||
<groupId>com.whai</groupId> <!--groupId表示当前 Maven 项目隶属的组织或公司-->
|
||||
<artifactId>LeetCode</artifactId> <!--当前 Maven 项目的名称-->
|
||||
<version>1.0-SNAPSHOT</version><!--定义了 Maven 项目当前所处版本-->
|
||||
<packaging>jar</packaging>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>ForJdk8</module>
|
||||
<module>ForJdk17</module>
|
||||
|
2
sdoih.bpmn
Normal file
2
sdoih.bpmn
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1730813700188" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema"/>
|
Loading…
Reference in New Issue
Block a user