This commit is contained in:
zhaohu
2026-06-12 16:14:58 +08:00
parent cf71897528
commit a7ba0f21e5
235 changed files with 33574 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
FROM bladex/alpine-java:openjdk17_cn_slim
LABEL maintainer="bladejava@qq.com"
RUN mkdir -p /blade/desk
WORKDIR /blade/desk
EXPOSE 8105
COPY ./target/blade-demo.jar ./app.jar
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
@@ -0,0 +1,19 @@
#自定义配置
demo:
name: demo-name
#放行配置
blade:
secure:
skip-url:
- /demo/**
datasource:
demo:
master:
url: jdbc:mysql://localhost:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
slave:
url: jdbc:mysql://localhost:3306/bladex_slave?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
+87
View File
@@ -0,0 +1,87 @@
<?xml version="1.0"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springblade</groupId>
<artifactId>blade-service</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-demo</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<!-- Boot核心依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId>
</dependency>
<!-- 动态数据源依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-db-dynamic</artifactId>
</dependency>
<!-- Swagger依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-swagger</artifactId>
</dependency>
<!-- 对象存储依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-oss</artifactId>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<!-- 业务编排依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-liteflow</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-literule</artifactId>
</dependency>
<!-- 工程自定义业务api -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-demo-api</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 自动装配依赖 -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>${docker.fabric.skip}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,45 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo;
import org.springblade.core.cloud.client.BladeCloudApplication;
import org.springblade.core.launch.BladeApplication;
import org.springblade.core.launch.constant.AppConstant;
/**
* Demo启动器
*
* @author Chill
*/
@BladeCloudApplication
public class DemoApplication {
public static void main(String[] args) {
BladeApplication.run(AppConstant.APPLICATION_DEMO_NAME, DemoApplication.class, args);
}
}
@@ -0,0 +1,48 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.config;
import com.example.demo.props.DemoProperties;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 配置feign、mybatis包名、properties
*
* @author Chill
*/
@Configuration(proxyBeanMethods = false)
@ComponentScan({"org.springblade", "com.example"})
@EnableFeignClients({"org.springblade", "com.example"})
@MapperScan({"org.springblade.**.mapper.**", "com.example.**.mapper.**"})
@EnableConfigurationProperties(DemoProperties.class)
public class DemoConfiguration {
}
@@ -0,0 +1,68 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.controller;
import com.example.demo.props.DemoProperties;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Demo控制器
*
* @author Chill
*/
@RefreshScope
@RestController
@RequestMapping("demo")
@RequiredArgsConstructor
@Tag(name = "配置接口", description = "即时刷新配置")
public class DemoController {
/**
* 需要导入blade-demo-dev.yaml文件至nacos
*/
@Value("${demo.name:1}")
private String name;
private final DemoProperties properties;
@GetMapping("name")
public String getName() {
return name;
}
@GetMapping("name-by-props")
public String getNameByProps() {
return properties.getName();
}
}
@@ -0,0 +1,76 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.controller;
import com.example.demo.pojo.entity.Notice;
import com.example.demo.service.IDynamicService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 多数据源
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@RequestMapping("dynamic")
@Tag(name = "多数据源接口", description = "多数据源")
public class DynamicController {
private final IDynamicService dynamicService;
/**
* master列表
*/
@GetMapping("/master-list")
@ApiOperationSupport(order = 1)
@Operation(summary = "master列表", description = "master列表")
public R<List<Notice>> masterList() {
List<Notice> list = dynamicService.masterList();
return R.data(list);
}
/**
* slave列表
*/
@GetMapping("/slave-list")
@ApiOperationSupport(order = 1)
@Operation(summary = "slave列表", description = "slave列表")
public R<List<Notice>> slaveList() {
List<Notice> list = dynamicService.slaveList();
return R.data(list);
}
}
@@ -0,0 +1,47 @@
package com.example.demo.controller;
import com.example.demo.rule.liteflow.context.BizContext;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.flow.LiteflowResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* LiteFlowController
*
* @author BladeX
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("liteflow")
@Tag(name = "LiteFlow接口", description = "LiteFlow")
public class LiteFlowController {
@Resource
private FlowExecutor flowExecutor;
@GetMapping("/test")
public String test() {
// 构建上下文
BizContext bizContext = new BizContext();
bizContext.setId(1L);
bizContext.setName("测试名称");
bizContext.setCategory(1);
bizContext.setIsPublish(Boolean.TRUE);
// 启动 demoChain 的规则引擎
LiteflowResponse resp = flowExecutor.execute2Resp("demoChain", null, bizContext);
if (resp.isSuccess()) {
BizContext contextBean = resp.getContextBean(BizContext.class);
return JsonUtil.toJson(contextBean);
} else {
return "fail";
}
}
}
@@ -0,0 +1,156 @@
package com.example.demo.controller;
import com.example.demo.rule.literule.context.Address;
import com.example.demo.rule.literule.context.OrderContext;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.engine.RuleEngineExecutor;
import org.springblade.core.literule.provider.LiteRuleResponse;
import org.springblade.core.literule.provider.RuleConfig;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.concurrent.Executors;
/**
* LiteRuleController
*
* @author BladeX
*/
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("literule")
@Tag(name = "LiteRule接口", description = "LiteRule")
public class LiteRuleController {
@Resource
private RuleEngineExecutor ruleExecutor;
@GetMapping("/test")
public String test() {
// 测试成功场景
testSuccessCase(ruleExecutor);
// 测试失败场景
testFailureCase(ruleExecutor);
// 测试异步执行
testAsyncExecution(ruleExecutor);
return "执行完毕请查看控制台输出";
}
/**
* 测试成功场景
*/
private static void testSuccessCase(RuleEngineExecutor ruleExecutor) {
log.info("=== [1] 开始测试:正常场景 ===");
// 构建上下文
OrderContext context = OrderContext.builder()
.orderId("ORD-001")
.amount(new BigDecimal("1200"))
.paymentType("ALIPAY")
.shippingAddress(Address.builder()
.country("China")
.province("Guangdong")
.city("Shenzhen")
.detail("Nanshan District")
.build())
.build();
// 构建配置
RuleConfig config = RuleConfig.builder()
.enableTimeMonitor(true)
.printExecutionTime(true)
.enableLogging(true)
.build();
// 执行规则链
LiteRuleResponse<OrderContext> response = ruleExecutor.execute(
"orderChain",
context,
config
);
// 处理响应
log.info("[1.1] 规则链执行结果:{}", response.isSuccess() ? "成功" : "失败");
log.info("[1.2] 规则链执行耗时:{}毫秒", response.getExecutionTime());
log.info("[1.3] 订单状态:{}", response.getContext().getStatus());
log.info("[1.4] 最终金额:{}", response.getContext().getAmount());
}
/**
* 测试失败场景
*/
private static void testFailureCase(RuleEngineExecutor ruleExecutor) {
log.info("=== [2] 开始测试:失败场景 ===");
// 构建上下文(缺少必要字段)
OrderContext context = OrderContext.builder()
.orderId("") // 空订单ID
.amount(new BigDecimal("-100")) // 负数金额
.paymentType("UNKNOWN") // 未知支付方式
.shippingAddress(Address.builder()
.country("USA")
.province("California")
.city("San Francisco")
.detail("Silicon Valley")
.build())
.build();
// 执行规则链
LiteRuleResponse<OrderContext> response = ruleExecutor.execute(
"orderChain",
context
);
// 处理响应
log.info("[2.1] 规则链执行结果:{}", response.isSuccess() ? "成功" : "失败");
log.info("[2.2] 错误信息:{}", response.getContext().getErrorMessages());
}
/**
* 测试异步执行
*/
private static void testAsyncExecution(RuleEngineExecutor ruleExecutor) {
log.info("=== [3] 开始测试:异步执行 ===");
// 构建上下文
OrderContext context = OrderContext.builder()
.orderId("ORD-002")
.amount(new BigDecimal("800"))
.paymentType("WECHAT")
.shippingAddress(Address.builder()
.country("USA")
.province("California")
.city("San Francisco")
.detail("Silicon Valley")
.build())
.build();
// 异步执行规则链
ruleExecutor.executeAsync(
"orderChain",
context,
Executors.newSingleThreadExecutor()
).thenAccept(response -> {
log.info("[3.1] 异步规则链执行完成");
log.info("[3.2] 规则链执行结果:{}", response.isSuccess() ? "成功" : "失败");
log.info("[3.3] 规则链执行耗时:{}毫秒", response.getExecutionTime());
log.info("[3.4] 订单状态:{}", response.getContext().getStatus());
log.info("[3.5] 最终金额:{}", response.getContext().getAmount());
});
// 等待异步执行完成
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
@@ -0,0 +1,130 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.demo.pojo.entity.Notice;
import com.example.demo.service.INoticeService;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springblade.common.cache.CacheNames;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 控制器
*
* @author Chill
*/
@RestController
@RequestMapping("notice")
@AllArgsConstructor
@Tag(name = "用户博客", description = "博客接口")
public class NoticeController extends BladeController implements CacheNames {
private final INoticeService noticeService;
/**
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入notice")
public R<Notice> detail(Notice notice) {
Notice detail = noticeService.getOne(Condition.getQueryWrapper(notice));
return R.data(detail);
}
/**
* 分页
*/
@GetMapping("/list")
@Parameters({
@Parameter(name = "category", description = "公告类型", in = ParameterIn.QUERY, schema = @Schema(type = "integer")),
@Parameter(name = "title", description = "公告标题", in = ParameterIn.QUERY, schema = @Schema(type = "string"))
})
@ApiOperationSupport(order = 2)
@Operation(summary = "分页", description = "传入notice")
public R<IPage<Notice>> list(@Parameter(hidden = true) @RequestParam Map<String, Object> notice, Query query) {
IPage<Notice> pages = noticeService.page(Condition.getPage(query), Condition.getQueryWrapper(notice, Notice.class));
return R.data(pages);
}
/**
* 新增
*/
@PostMapping("/save")
@ApiOperationSupport(order = 3)
@Operation(summary = "新增", description = "传入notice")
public R save(@RequestBody Notice notice) {
return R.status(noticeService.save(notice));
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperationSupport(order = 4)
@Operation(summary = "修改", description = "传入notice")
public R update(@RequestBody Notice notice) {
return R.status(noticeService.updateById(notice));
}
/**
* 新增或修改
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 5)
@Operation(summary = "新增或修改", description = "传入notice")
public R submit(@RequestBody Notice notice) {
return R.status(noticeService.saveOrUpdate(notice));
}
/**
* 删除
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 6)
@Operation(summary = "逻辑删除", description = "传入notice")
public R remove(@ApiParam(value = "主键集合") @RequestParam String ids) {
boolean temp = noticeService.deleteLogic(Func.toLongList(ids));
return R.status(temp);
}
}
@@ -0,0 +1,57 @@
package com.example.demo.controller;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.boot.file.LocalFile;
import org.springblade.core.oss.MinioTemplate;
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* UploadController
*
* @author Chill
*/
@RestController
@AllArgsConstructor
@RequestMapping("/notice/upload")
@Tag(name = "对象存储接口", description = "oss上传测试")
public class UploadController extends BladeController {
private final MinioTemplate minioTemplate;
/**
* minio上传demo
*
* @param file 上传文件
* @return BladeFile
*/
@SneakyThrows
@PostMapping("put-object")
public R<BladeFile> putMinioObject(@RequestParam MultipartFile file) {
BladeFile bladeFile = minioTemplate.putFile(file);
return R.data(bladeFile);
}
/**
* 上传本地文件
*
* @param file 上传文件
* @return LocalFile
*/
@SneakyThrows
@PostMapping("put-local-object")
public R<LocalFile> putLocalObject(@RequestParam MultipartFile file) {
LocalFile localFile = getFile(file);
localFile.transfer();
return R.data(localFile);
}
}
@@ -0,0 +1,56 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.feign;
import com.example.demo.pojo.entity.Notice;
import com.example.demo.mapper.NoticeMapper;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import org.springblade.core.tool.api.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Notice Feign
*
* @author Chill
*/
@Hidden
@RestController
@AllArgsConstructor
public class NoticeClient implements INoticeClient {
private final NoticeMapper mapper;
@Override
@GetMapping(TOP)
public R<List<Notice>> top(Integer number) {
return R.data(mapper.topList(number));
}
}
@@ -0,0 +1,69 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.launcher;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.constant.NacosConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
/**
* 启动参数拓展
*
* @author Chill
*/
@AutoService(LauncherService.class)
public class DemoLauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
Properties props = System.getProperties();
// 指定注册配置信息
props.setProperty("spring.config.import", String.join(",",
NacosConstant.dataId(),
NacosConstant.dataId(profile),
NacosConstant.dataId(appName, profile),
NacosConstant.dataId("blade-example", profile))
);
// 指定注册IP
// PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.ip", "127.0.0.1");
// 指定注册端口
// PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.port", "8200");
// 自定义命名空间
// PropsUtil.setProperty(props, "spring.cloud.nacos.config.namespace", LauncherConstant.NACOS_NAMESPACE);
// PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.namespace", LauncherConstant.NACOS_NAMESPACE);
// 自定义分组
// PropsUtil.setProperty(props, "spring.cloud.nacos.config.group", NacosConstant.NACOS_CONFIG_GROUP);
// PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.group", NacosConstant.NACOS_CONFIG_GROUP);
}
@Override
public int getOrder() {
return 20;
}
}
@@ -0,0 +1,56 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.demo.pojo.entity.Notice;
import java.util.List;
/**
* Mapper 接口
*
* @author Chill
*/
public interface NoticeMapper extends BaseMapper<Notice> {
/**
* 前N条数据
* @param number
* @return
*/
List<Notice> topList(Integer number);
/**
* 自定义分页
* @param page
* @param notice
* @return
*/
List<Notice> selectNoticePage(IPage page, Notice notice);
}
@@ -0,0 +1,39 @@
<?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.demo.mapper.NoticeMapper">
<!-- 通用查询映射结果 -->
<resultMap id="noticeResultMap" type="com.example.demo.pojo.entity.Notice">
<result column="id" property="id"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="status" property="status"/>
<result column="is_deleted" property="isDeleted"/>
<result column="release_time" property="releaseTime"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="baseColumnList">
select id,
create_user AS createUser,
create_time AS createTime,
update_user AS updateUser,
update_time AS updateTime,
status,
is_deleted AS isDeleted,
title, content
</sql>
<select id="topList" resultMap="noticeResultMap">
select * from blade_notice limit #{number}
</select>
<select id="selectNoticePage" resultMap="noticeResultMap">
select * from blade_notice where title like concat(concat('%', #{notice.title}), '%') and is_deleted = 0
</select>
</mapper>
@@ -0,0 +1,18 @@
package com.example.demo.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* DemoProperties
*
* @author Chill
*/
@Data
@ConfigurationProperties(prefix = "demo")
public class DemoProperties {
/**
* 名称
*/
private String name;
}
@@ -0,0 +1,48 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.rule.liteflow;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
/**
* A业务
*
* @author Chill
*/
@Slf4j
@LiteflowComponent(id = "abizRule", name = "A业务")
public class AbizRule extends NodeComponent {
@Override
public void process() throws Exception {
log.info("A业务执行完毕");
}
}
@@ -0,0 +1,57 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.rule.liteflow;
import com.example.demo.rule.liteflow.context.BizContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeSwitchComponent;
import lombok.extern.slf4j.Slf4j;
/**
* A业务
*
* @author Chill
*/
@Slf4j
@LiteflowComponent(id = "bbizRule", name = "B业务")
public class BbizRule extends NodeSwitchComponent {
@Override
public String processSwitch() throws Exception {
// 获取上下文
BizContext contextBean = this.getContextBean(BizContext.class);
// 获取条件
Boolean isPublish = contextBean.getIsPublish();
log.info("B业务执行判断");
// 进行节点判断
if (isPublish) {
return "cbizRule";
} else {
return "dbizRule";
}
}
}
@@ -0,0 +1,53 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.rule.liteflow;
import com.example.demo.rule.liteflow.context.BizContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
/**
* A业务
*
* @author Chill
*/
@Slf4j
@LiteflowComponent(id = "cbizRule", name = "C业务")
public class CbizRule extends NodeComponent {
@Override
public void process() throws Exception {
// 获取上下文
BizContext contextBean = this.getContextBean(BizContext.class);
// 修改上下文
contextBean.setName(contextBean.getName() + "-> C");
log.info("C业务执行完毕");
}
}
@@ -0,0 +1,54 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.rule.liteflow;
import com.example.demo.rule.liteflow.context.BizContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
/**
* A业务
*
* @author Chill
*/
@Slf4j
@LiteflowComponent(id = "dbizRule", name = "D业务")
public class DbizRule extends NodeComponent {
@Override
public void process() throws Exception {
// 获取上下文
BizContext contextBean = this.getContextBean(BizContext.class);
// 修改上下文
contextBean.setName(contextBean.getName() + "-> D");
log.info("D业务执行完毕");
}
}
@@ -0,0 +1,21 @@
package com.example.demo.rule.liteflow.context;
import lombok.Data;
/**
* 上下文类
*
* @author Chill
*/
@Data
public class BizContext {
private Long id;
private String name;
private Integer category;
private Boolean isPublish;
}
@@ -0,0 +1,26 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleComponent;
import com.example.demo.rule.literule.context.OrderContext;
/**
* AlipayRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "alipayRule")
public class AlipayRule extends RuleComponent {
@Override
protected void process() {
OrderContext context = getContextBean(OrderContext.class);
log.info("[规则4-支付宝] 处理支付宝支付:订单号={}, 金额={}",
context.getOrderId(), context.getAmount());
// 模拟支付处理
context.setStatus("PAID");
}
}
@@ -0,0 +1,26 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleComponent;
import com.example.demo.rule.literule.context.OrderContext;
/**
* BankPayRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "bankPayRule")
public class BankPayRule extends RuleComponent {
@Override
protected void process() {
OrderContext context = getContextBean(OrderContext.class);
log.info("[规则4-银行] 处理银行卡支付:订单号={}, 金额={}",
context.getOrderId(), context.getAmount());
// 模拟支付处理
context.setStatus("PAID");
}
}
@@ -0,0 +1,53 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleComponent;
import com.example.demo.rule.literule.context.Address;
import com.example.demo.rule.literule.context.OrderContext;
import java.math.BigDecimal;
/**
* OrderAmountRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "orderAmountRule")
public class OrderAmountRule extends RuleComponent {
@Override
protected void process() {
OrderContext context = getContextBean(OrderContext.class);
BigDecimal amount = context.getAmount();
// 计算折扣
BigDecimal discount = calculateDiscount(amount);
// 计算运费
BigDecimal shipping = calculateShipping(context.getShippingAddress());
// 更新订单金额
BigDecimal finalAmount = amount.subtract(discount).add(shipping);
context.setAmount(finalAmount);
log.info("[规则2] 订单金额计算完成:{} = {} - {} + {}", finalAmount, amount, discount, shipping);
}
private BigDecimal calculateDiscount(BigDecimal amount) {
// 折扣计算逻辑:金额大于1000打9折
if (amount.compareTo(new BigDecimal("1000")) > 0) {
return amount.multiply(new BigDecimal("0.1"));
}
return BigDecimal.ZERO;
}
private BigDecimal calculateShipping(Address address) {
// 运费计算逻辑:根据地址计算
if ("China".equals(address.getCountry())) {
return new BigDecimal("10");
}
return new BigDecimal("50");
}
}
@@ -0,0 +1,52 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleComponent;
import com.example.demo.rule.literule.context.Address;
import com.example.demo.rule.literule.context.OrderContext;
import java.math.BigDecimal;
/**
* OrderValidateRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "orderValidateRule")
public class OrderValidateRule extends RuleComponent {
@Override
protected void process() {
OrderContext context = getContextBean(OrderContext.class);
// 校验订单ID
if (isEmpty(context.getOrderId())) {
context.addError("订单ID不能为空");
log.info("[规则1] 订单校验不通过:{}", context.getErrorMessages());
return;
}
// 校验金额
if (context.getAmount() == null || context.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
context.addError("订单金额无效");
log.info("[规则1] 订单校验不通过:{}", context.getErrorMessages());
return;
}
// 校验地址
Address address = context.getShippingAddress();
if (address == null) {
context.addError("收货地址不能为空");
log.info("[规则1] 订单校验不通过:{}", context.getErrorMessages());
return;
}
log.info("[规则1] 订单校验通过:{}", context.getOrderId());
}
private boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
}
@@ -0,0 +1,45 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleSwitchComponent;
import com.example.demo.rule.literule.context.OrderContext;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* PaymentRouteRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "paymentSwitchRule")
public class PaymentSwitchRule extends RuleSwitchComponent {
private static final Map<String, String> PAYMENT_RULE_MAP = new HashMap<>();
static {
PAYMENT_RULE_MAP.put("ALIPAY", "alipayRule");
PAYMENT_RULE_MAP.put("WECHAT", "wechatPayRule");
PAYMENT_RULE_MAP.put("BANK", "bankPayRule");
}
@Override
protected List<String> process() {
OrderContext context = getContextBean(OrderContext.class);
String paymentType = context.getPaymentType();
log.info("[规则3] 支付路由选择:{}", paymentType);
String payName = PAYMENT_RULE_MAP.get(paymentType);
if (payName != null) {
return Collections.singletonList(payName);
} else {
context.addError("不支持的支付方式:" + paymentType);
return Collections.emptyList();
}
}
}
@@ -0,0 +1,26 @@
package com.example.demo.rule.literule;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.literule.annotation.LiteRuleComponent;
import org.springblade.core.literule.core.RuleComponent;
import com.example.demo.rule.literule.context.OrderContext;
/**
* WechatPayRule
*
* @author BladeX
*/
@Slf4j
@LiteRuleComponent(id = "wechatPayRule")
public class WechatPayRule extends RuleComponent {
@Override
protected void process() {
OrderContext context = getContextBean(OrderContext.class);
log.info("[规则4-微信] 处理微信支付:订单号={}, 金额={}",
context.getOrderId(), context.getAmount());
// 模拟支付处理
context.setStatus("PAID");
}
}
@@ -0,0 +1,25 @@
package com.example.demo.rule.literule.builder;
import org.springblade.core.literule.annotation.RuleEngineComponent;
import org.springblade.core.literule.builder.LiteRule;
import org.springblade.core.literule.builder.RuleBuilder;
import org.springblade.core.literule.builder.chain.RuleChain;
/**
* 订单处理规则链构建器
*/
@RuleEngineComponent(id = "orderChain")
public class OrderRuleBuilder implements RuleBuilder {
@Override
public RuleChain build() {
// 创建支付处理分支规则
RuleChain paymentRule = LiteRule.SWITCH("paymentSwitchRule")
.TO("alipayRule", "wechatPayRule", "bankPayRule")
.build();
// 创建完整规则链
return LiteRule.THEN("orderValidateRule", "orderAmountRule")
.THEN(paymentRule)
.build();
}
}
@@ -0,0 +1,22 @@
package com.example.demo.rule.literule.context;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 地址实体
*
* @author BladeX
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Address {
private String country;
private String province;
private String city;
private String detail;
}
@@ -0,0 +1,24 @@
package com.example.demo.rule.literule.context;
import lombok.*;
import org.springblade.core.literule.core.RuleContextComponent;
import java.math.BigDecimal;
/**
* 订单上下文
*
* @author BladeX
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class OrderContext extends RuleContextComponent {
private String orderId;
private BigDecimal amount;
private String paymentType;
private String status;
private Address shippingAddress;
}
@@ -0,0 +1,54 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.service;
import com.example.demo.pojo.entity.Notice;
import org.springblade.core.mp.base.BaseService;
import java.util.List;
/**
* 服务类
*
* @author Chill
*/
public interface IDynamicService extends BaseService<Notice> {
/**
* master数据源的列表
*
* @return
*/
List<Notice> masterList();
/**
* slave数据源的列表
*
* @return
*/
List<Notice> slaveList();
}
@@ -0,0 +1,47 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.core.mp.base.BaseService;
import com.example.demo.pojo.entity.Notice;
/**
* 服务类
*
* @author Chill
*/
public interface INoticeService extends BaseService<Notice> {
/**
* 自定义分页
* @param page
* @param notice
* @return
*/
IPage<Notice> selectNoticePage(IPage<Notice> page, Notice notice);
}
@@ -0,0 +1,30 @@
package com.example.demo.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.example.demo.pojo.entity.Notice;
import com.example.demo.mapper.NoticeMapper;
import com.example.demo.service.IDynamicService;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* DynamicServiceImpl
*
* @author Chill
*/
@Service
public class DynamicServiceImpl extends BaseServiceImpl<NoticeMapper, Notice> implements IDynamicService {
@Override
public List<Notice> masterList() {
return this.list();
}
@Override
@DS("slave")
public List<Notice> slaveList() {
return this.list();
}
}
@@ -0,0 +1,48 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package com.example.demo.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.demo.mapper.NoticeMapper;
import com.example.demo.service.INoticeService;
import org.springblade.core.mp.base.BaseServiceImpl;
import com.example.demo.pojo.entity.Notice;
import org.springframework.stereotype.Service;
/**
* 服务实现类
*
* @author Chill
*/
@Service
public class NoticeServiceImpl extends BaseServiceImpl<NoticeMapper, Notice> implements INoticeService {
@Override
public IPage<Notice> selectNoticePage(IPage<Notice> page, Notice notice) {
return page.setRecords(baseMapper.selectNoticePage(page, notice));
}
}
@@ -0,0 +1,30 @@
#服务器端口
server:
port: 8200
#Spring配置
spring:
datasource:
#主数据源信息
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${blade.datasource.demo.master.url}
username: ${blade.datasource.demo.master.username}
password: ${blade.datasource.demo.master.password}
#动态数据源信息
dynamic:
druid:
#通用校验配置
validation-query: select 1
#设置默认的数据源或者数据源组,默认值即为master
primary: master
datasource:
slave:
druid:
#独立校验配置
validation-query: select 1
#oracle校验
#validation-query: select 1 from dual
driver-class-name: com.mysql.cj.jdbc.Driver
url: ${blade.datasource.demo.slave.url}
username: ${blade.datasource.demo.slave.username}
password: ${blade.datasource.demo.slave.password}
@@ -0,0 +1,31 @@
#服务器端口
server:
port: 8200
#数据源配置
#spring:
# datasource:
# url: ${blade.datasource.prod.url}
# username: ${blade.datasource.prod.username}
# password: ${blade.datasource.prod.password}
spring:
#排除DruidDataSourceAutoConfigure
autoconfigure:
exclude: com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure
datasource:
dynamic:
druid:
proxy-filters:
- sqlLogInterceptor
#设置默认的数据源或者数据源组,默认值即为master
primary: master
datasource:
master:
url: ${blade.datasource.demo.master.url}
username: ${blade.datasource.demo.master.username}
password: ${blade.datasource.demo.master.password}
slave:
url: ${blade.datasource.demo.slave.url}
username: ${blade.datasource.demo.slave.username}
password: ${blade.datasource.demo.slave.password}
@@ -0,0 +1,31 @@
#服务器端口
server:
port: 8200
#数据源配置
#spring:
# datasource:
# url: ${blade.datasource.test.url}
# username: ${blade.datasource.test.username}
# password: ${blade.datasource.test.password}
spring:
#排除DruidDataSourceAutoConfigure
autoconfigure:
exclude: com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure
datasource:
url: ${blade.datasource.test.url}
username: ${blade.datasource.test.username}
password: ${blade.datasource.test.password}
dynamic:
druid:
proxy-filters:
- sqlLogInterceptor
#设置默认的数据源或者数据源组,默认值即为master
primary: master
# datasource:
# master:
# slave:
# url: ${blade.datasource.test.slave.url}
# username: ${blade.datasource.test.slave.username}
# password: ${blade.datasource.test.slave.password}
@@ -0,0 +1,29 @@
#mybatis-plus配置
mybatis-plus:
mapper-locations: classpath:com/example/**/mapper/*Mapper.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.example.**.entity
#swagger扫描路径配置
swagger:
base-packages:
- org.springblade
- com.example
#oss配置
oss:
enabled: true
name: minio
tenant-mode: false
endpoint: http://127.0.0.1:9000
access-key: D99KGE6ZTQXSATTJWU24
secret-key: QyVqGnhIQQE734UYSUFlGOZViE6+ZlDEfUG3NjhJ
bucket-name: bladex
#blade配置
blade:
#本地文件上传
file:
remote-mode: true
upload-domain: http://localhost:8999
remote-path: /usr/share/nginx/html
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<flow>
<chain name="demoChain">
THEN(
abizRule,
SWITCH(bbizRule).TO(cbizRule, dbizRule)
);
</chain>
</flow>
@@ -0,0 +1,31 @@
package org.springblade.test;
import com.example.demo.DemoApplication;
import com.example.demo.service.INoticeService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springblade.core.test.BladeBootTest;
import org.springblade.core.test.BladeSpringExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* Blade单元测试
*
* @author Chill
*/
@ExtendWith(BladeSpringExtension.class)
@SpringBootTest(classes = DemoApplication.class)
@BladeBootTest(appName = "blade-demo", profile = "test", enableLoader = true)
public class BladeDemoTest {
@Autowired
private INoticeService noticeService;
@Test
public void contextLoads() {
long count = noticeService.count();
System.out.println("notice数量:[" + count + "] 个");
}
}
@@ -0,0 +1,298 @@
package org.springblade.test;
import lombok.Data;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.jackson.Sensitive;
import org.springblade.core.tool.sensitive.SensitiveConfig;
import org.springblade.core.tool.sensitive.SensitiveType;
import org.springblade.core.tool.sensitive.SensitiveUtil;
import org.springblade.core.tool.sensitive.SensitiveWord;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* SensitiveUtil使用示例
* 展示各种使用场景和数据脱敏效果
*
* @author BladeX
*/
public class SensitiveTest {
public static void main(String[] args) {
// 演示所有使用场景
demonstrateBasicUsage();
demonstrateCustomConfig();
demonstrateSingleType();
demonstrateMultipleTypes();
demonstrateCustomRegex();
demonstrateSensitiveWords();
demonstrateComplexExample();
demonstrateJacksonSerializer();
}
/**
* 1. 基础用法演示 - 使用默认配置
*/
private static void demonstrateBasicUsage() {
System.out.println("\n=== 1.基础用法演示 ===");
String content = "客户信息:\n" +
"手机号: 13812345678\n" +
"邮箱: test@example.com\n" +
"身份证: 310123199001011234\n" +
"银行卡: 6222021234567890123";
String result = SensitiveUtil.process(content);
System.out.println("原始内容:\n" + content);
System.out.println("\n处理后:\n" + result);
}
/**
* 2. 自定义配置演示
*/
private static void demonstrateCustomConfig() {
System.out.println("\n=== 2.自定义配置演示 ===");
// 创建自定义配置
SensitiveConfig config = SensitiveConfig.builder()
.sensitiveTypes(EnumSet.of(
SensitiveType.MOBILE,
SensitiveType.EMAIL
))
.sensitiveWords(EnumSet.of(
SensitiveWord.SECURE,
SensitiveWord.AUTHENTICATION
))
.customPatterns(Map.of(
"CustomerId", Pattern.compile("(?<=CustomerID:)\\s*\\w+"),
"ProjectCode", Pattern.compile("(?<=ProjectCode:)\\s*\\w+")
))
.processLineByLine(true)
.replacement("***已隐藏***")
.build();
String content = "用户数据:\n" +
"手机: 13812345678\n" +
"CustomerID: USER123456\n" +
"ProjectCode: PRJ789\n" +
"password=admin123\n" +
"token=abcdef";
// 转换为LogVO示例
LogVO logVO = SensitiveUtil.process(content, config, data -> {
LogVO dto = new LogVO();
dto.setContent(data);
dto.setTimestamp(System.currentTimeMillis());
return dto;
});
System.out.println("原始内容:\n" + content);
System.out.println("\n处理后:\n" + logVO.getContent());
}
/**
* 3. 单个敏感类型处理演示
*/
private static void demonstrateSingleType() {
System.out.println("\n=== 3.单个敏感类型处理演示 ===");
String content = "联系方式:13812345678,邮箱:test@example.com";
String result = SensitiveUtil.process(content, SensitiveType.MOBILE);
System.out.println("原始内容:" + content);
System.out.println("处理后:" + result);
}
/**
* 4. 多个敏感类型处理演示
*/
private static void demonstrateMultipleTypes() {
System.out.println("\n=== 4.多个敏感类型处理演示 ===");
String content = "用户资料:\n" +
"手机:13812345678\n" +
"银行卡:6222021234567890123";
UserVO userVO = SensitiveUtil.process(content, EnumSet.of(
SensitiveType.MOBILE,
SensitiveType.BANK_CARD
), data -> {
UserVO vo = new UserVO();
vo.setUserInfo(data);
return vo;
});
System.out.println("原始内容:\n" + content);
System.out.println("\n处理后:\n" + userVO.getUserInfo());
}
/**
* 5. 自定义正则处理演示
*/
private static void demonstrateCustomRegex() {
System.out.println("\n=== 5.自定义正则处理演示 ===");
// 简单版本
String simpleContent = "订单号:ORDER20250101001";
String simpleResult = SensitiveUtil.processWithRegex(
simpleContent,
"ORDER\\d{8}\\d{3}"
);
System.out.println("简单版本:");
System.out.println("原始内容:" + simpleContent);
System.out.println("处理后:" + simpleResult);
// 自定义替换符版本
String customContent = "项目编号:PRJ20250101";
String customResult = SensitiveUtil.processWithRegex(
customContent,
"PRJ\\d{8}",
"PRJ********"
);
System.out.println("\n自定义替换符版本:");
System.out.println("原始内容:" + customContent);
System.out.println("处理后:" + customResult);
}
/**
* 6. 敏感词处理演示
*/
private static void demonstrateSensitiveWords() {
System.out.println("\n=== 6.敏感词处理演示 ===");
String content = "系统配置:\n" +
"password=admin123\n" +
"api_key=sk_test_123456\n" +
"secret=my_secret_key\n" +
"test=my_test_key";
List<String> sensitiveWords = Arrays.asList("password", "api_key", "secret");
// 完整版本的敏感词处理
String result = SensitiveUtil.processWithWords(
content,
sensitiveWords,
"***",// 可不填
true // 可不填
);
System.out.println("原始内容:\n" + content);
System.out.println("\n处理后:\n" + result);
}
/**
* 7. 复杂场景示例
*/
private static void demonstrateComplexExample() {
System.out.println("\n=== 7.复杂场景示例 ===");
String content = "API调用日志:\n" +
"时间:2024-01-01 10:30:00\n" +
"请求头:\n" +
"Authorization: Bearer sk_test_123456\n" +
"请求体:\n" +
"{\n" +
" \"user\": {\n" +
" \"mobile\": \"13812345678\",\n" +
" \"email\": \"test@example.com\",\n" +
" \"idCard\": \"310123199001011234\",\n" +
" \"test\": \"2333333333\"\n" +
" },\n" +
" \"payment\": {\n" +
" \"cardNo\": \"6222021234567890123\",\n" +
" \"secretKey\": \"payment_secret_123\"\n" +
" }\n" +
"}";
// 创建复杂配置
SensitiveConfig complexConfig = SensitiveConfig.builder()
.sensitiveTypes(EnumSet.of(
SensitiveType.MOBILE,
SensitiveType.EMAIL,
SensitiveType.ID_CARD
))
.sensitiveWords(EnumSet.allOf(SensitiveWord.class))
.customPatterns(Map.of(
"Bearer", Pattern.compile("Bearer\\s+[\\w-]+"),
"SecretKey", Pattern.compile("(?<=secretKey\":\\s*\")[^\"]+")
))
.processLineByLine(true)
.replacement("***")
.build();
ApiLogVO apiLogVO = SensitiveUtil.process(content, complexConfig, data -> {
ApiLogVO vo = new ApiLogVO();
vo.setRequestLog(data);
vo.setTimestamp(System.currentTimeMillis());
return vo;
});
System.out.println("原始内容:\n" + content);
System.out.println("\n处理后:\n" + apiLogVO.getRequestLog());
}
/**
* 8. jackson序列化场景
*/
private static void demonstrateJacksonSerializer() {
System.out.println("\n=== 8.jackson序列化场景 ===");
AccountVO accountVO = new AccountVO();
accountVO.setMobile("13812345678");
accountVO.setEmail("test@example.com");
accountVO.setCredential("系统配置:\n" +
"password=admin123\n" +
"api_key=sk_test_123456\n" +
"secret=my_secret_key\n" +
"test=my_test");
accountVO.setToken("Bearer password 123456");
accountVO.setOrderId("订单号:ORDER20250101001");
System.out.println("原始内容:\n" + accountVO);
System.out.println("\n处理后:\n" + JsonUtil.toJson(accountVO));
}
/**
* 数据传输对象
*/
@Data
static class LogVO {
private String content;
private long timestamp;
}
@Data
static class UserVO {
private String userInfo;
}
@Data
static class ApiLogVO {
private String requestLog;
private long timestamp;
}
@Data
static class AccountVO {
@Sensitive(type = SensitiveType.MOBILE)
private String mobile;
@Sensitive(type = SensitiveType.EMAIL)
private String email;
@Sensitive(word = SensitiveWord.SECURE)
private String credential;
@Sensitive(words = {"password", "secret"})
private String token;
@Sensitive(regex = "ORDER(.{2}).*(.{2})", replacement = "ORDER$1****$2")
private String orderId;
}
}
@@ -0,0 +1,60 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.test.launcher;
import org.springblade.common.constant.LauncherConstant;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.constant.NacosConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springblade.core.launch.utils.PropsUtil;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
/**
* 启动参数拓展
*
* @author Chill
*/
@AutoService(LauncherService.class)
public class DemoTestLauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
Properties props = System.getProperties();
PropsUtil.setProperty(props, "spring.cloud.nacos.config.extension-configs[0].data-id", NacosConstant.dataId("example", profile));
PropsUtil.setProperty(props, "spring.cloud.nacos.config.extension-configs[0].group", NacosConstant.NACOS_CONFIG_GROUP);
PropsUtil.setProperty(props, "spring.cloud.nacos.config.extension-configs[0].refresh", NacosConstant.NACOS_CONFIG_REFRESH);
PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", LauncherConstant.NACOS_DEV_ADDR);
PropsUtil.setProperty(props, "spring.cloud.nacos.config.server-addr", LauncherConstant.NACOS_DEV_ADDR);
PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.SENTINEL_DEV_ADDR);
}
@Override
public int getOrder() {
return 10;
}
}
@@ -0,0 +1,41 @@
#服务器端口
server:
port: 8200
#数据源配置
#spring:
# datasource:
# url: ${blade.datasource.dev.url}
# username: ${blade.datasource.dev.username}
# password: ${blade.datasource.dev.password}
spring:
datasource:
dynamic:
druid:
#通用校验配置
validation-query: select 1
#启用sql日志拦截器
proxy-filters:
- sqlLogInterceptor
#设置默认的数据源或者数据源组,默认值即为master
primary: master
datasource:
master:
druid:
#独立校验配置
validation-query: select 1
#oracle校验
#validation-query: select 1 from dual
url: ${blade.datasource.demo.master.url}
username: ${blade.datasource.demo.master.username}
password: ${blade.datasource.demo.master.password}
slave:
druid:
#独立校验配置
validation-query: select 1
#oracle校验
#validation-query: select 1 from dual
url: ${blade.datasource.demo.slave.url}
username: ${blade.datasource.demo.slave.username}
password: ${blade.datasource.demo.slave.password}
@@ -0,0 +1,10 @@
#服务器端口
server:
port: 8200
#数据源配置
spring:
datasource:
url: ${blade.datasource.test.url}
username: ${blade.datasource.test.username}
password: ${blade.datasource.test.password}
@@ -0,0 +1,21 @@
#mybatis-plus配置
mybatis-plus:
mapper-locations: classpath:com/example/**/mapper/*Mapper.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: com.example.**.entity
#swagger扫描路径配置
swagger:
base-packages:
- org.springbalde
- com.example
#oss配置
oss:
enabled: true
name: minio
tenant-mode: false
endpoint: http://127.0.0.1:9000
access-key: D99KGE6ZTQXSATTJWU24
secret-key: QyVqGnhIQQE734UYSUFlGOZViE6+ZlDEfUG3NjhJ
bucket-name: bladex