# esay-do
**Repository Path**: yuzhanfeng/easy-do
## Basic Information
- **Project Name**: esay-do
- **Description**: 学习和使用微服务项目的一个成果展示,准备做成一个开发脚手架、实现集成各种常用插件并且可插拔,少依赖,组装灵活、其他功能及核心代码以后陆续集成。
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://www.gebilaoyu.club
- **GVP Project**: No
## Statistics
- **Stars**: 6
- **Forks**: 0
- **Created**: 2021-03-14
- **Last Updated**: 2024-04-10
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# easy-do
#### 介绍
使用微服务项目的成果积累,开发脚手架、集成各种常用插件,可插拔,少依赖,组装灵活、其他功能及核心代码以后陆续实现。
目前绝大部分涉及配置集成类的模块全部做成了starter,基本每个模块都可以单独打包进入新项目,做到开箱即用!
#### 核心理念
插件! 插件! 插件! 核心理念就是各种常用功能全部做成插件
项目临时遇到需要的单独功能搭建一遍一遍百度很烦?从其他项目拷贝再修改很重复?那就用easydo吧!
你需要做的只有一件事,那就是引入依赖。
系统演示地址:http://easydo.plus 只是一个简单的前端展示。
###本人词穷,这事当前已实现的比较完善的功能:
###### 1.代码生成 -再 ruoyi 的gen基础上增加动态数据源、在线模板管理 https://gitee.com/yuzhanfeng/easy-do-generate-standalone
###### 2.oauth2授权授权服务组件(扩展token用户信息,一系列自定义配置)
###### 3.oauth2资源服务服务组件 对请求鉴权、自动请求授权服务鉴权、细粒度权限控制注解 、鉴权工具类
###### 4.oauth2客户端组件 自动请求授权服务获取token,微服务调用自动获取token
###### 5.redis使用组件的简单封装,fastjson序列化存储
###### 6.jdbc动态数据源,封装了数据源管理api
###### 7.jpa组件,快速开发的基类
###### 8.mybatis and mybatis plus 封装为插件,自动装配,快速开发的基类
###### 9.文件存储服务,基于minio 抽象了统一操作接口,后续支持扩展其他文件服务支持
###### 10.接口文档组件 kni4j的封装,采用稳定版本,无需代码配置,直接引入依赖即可使用
###### 11.xxl-job客户端,支持注解配置自动注册任务、兼容最新版
###### 12.全线基于springboot cloud Alibaba nacos 快速构建微服务模块
```xml
easy-do-core //核心基础模块
easy-do-utils //工具
easy-do-log //日志记录
easy-do-cloud-core //微服务web应用相关基础模块
easy-do-web-nacos //nacos web相关自动装配模块
easy-do-jpa-starter //JPA组件
easy-do-redis-starter //redis组件
easy-do-mybatis-starter //mybatis组件
easy-do-mybatis //mybatis-plus主键
easy-do-knife4j //接口文档、在线调试接口、一键下载生成接口文档
easy-do-oauth2-core //oauth2鉴权服务的基础模块
easy-do-oauth2-api //oauth2-api模块
easy-do-oauth2-server // 授权服务组件
easy-do-oauth2-client // 客户端组件
easy-do-oauth2-resources // 资源服务主键
easy-do-xxl-job // xxl-job分布式调度支持、自动注册实现
easy-do-jdbc-dynamic-datasource-starter //基于spring-jdbc实现的动态数据源,具有管理接口
easy-do-generate ///快速代码生成插件 网页操作 在线管理模板
easy-do-file-store-stater //文件存储插件 目前支持minio上传、下载、以及文件资源管理接口
```
###2021.11.1:
###easy-do-xxl-job
特性
- 支持xxl-job-admin 1.3.0, 1.2.0版本未测试,理论上兼容
- 事件自动注册执行器、自动注册调度任务、细粒度配置任务参数
```yaml
easydo.plus
easy-do-xxl-job
1.0.1
```
```yaml
xxl:
job:
admin:
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
addresses: http://127.0.0.1:8080/xxl-job-admin
username: admin
password: 123456
### 执行器通讯TOKEN [选填]:非空时启用;
accessToken:
executor:
### 自动注册的执行器名称
title: job-center
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
appname: job-center
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
address:
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题
ip:
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
port: 0
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logpath:
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能
logretentiondays: -1
```
使用示例
```java
/**
* XxlJob开发示例(Bean模式)
*
* 开发步骤:
* 1、任务开发:在Spring Bean实例中,开发Job方法;
* 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
* 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
* 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
*
* @author xuxueli 2019-12-11 21:52:51
*/
@Component
public class SampleXxlJob {
private static final Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
@AutoRegister(scheduleConf = "0 * 0/1 * * ?", desc = "简单任务示例(Bean模式)", author = "easy-do")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
/**
* 2、分片广播任务
*/
@XxlJob("shardingJobHandler")
@AutoRegister(scheduleConf = "0 * 0/1 * * ?", desc = "分片广播任务", author = "easy-do")
public void shardingJobHandler() throws Exception {
}
/**
* 3、命令行任务
*/
@XxlJob("commandJobHandler")
@AutoRegister(glueType = GlueTypeEnum.GLUE_POWERSHELL,scheduleConf = "0 * 0/1 * * ?", desc = "命令行任务", author = "easy-do")
public void commandJobHandler() throws Exception {
}
/**
* 4、跨平台Http任务
* 参数示例:
* "url: http://www.baidu.com\n" +
* "method: get\n" +
* "data: content\n";
*/
@XxlJob("httpJobHandler")
@AutoRegister(scheduleConf = "0 * 0/1 * * ?", desc = "跨平台Http任务", author = "easy-do")
public void httpJobHandler() throws Exception {
}
/**
* 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑;
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
@AutoRegister(scheduleConf = "0 * 0/1 * * ?", desc = "生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑", author = "easy-do")
public void demoJobHandler2() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
public void init(){
logger.info("init");
}
public void destroy(){
logger.info("destory");
}
}
```
AutoRegister注解说明
```java
/**
* @author RaoYuan
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface AutoRegister {
/**r任务详细*/
String desc();
/**调度配置参数*/
String scheduleConf() default "";
/**调度类型*/
ScheduleTypeEnum scheduleType() default ScheduleTypeEnum.CRON;
/**负责人*/
String author();
/**执行器路由策略*/
RouteStrategyEnum executorRouteStrategy() default RouteStrategyEnum.FIRST;
/**任务ID*/
String childJobId() default "";
/**阻塞处理策略*/
BlockStrategy executorBlockStrategy() default BlockStrategy.SERIAL_EXECUTION;
/**运行模式*/
GlueTypeEnum glueType() default GlueTypeEnum.BEAN;
/**超时时间*/
int executorTimeout() default 0;
/**失败重试次数*/
int executorFailRetryCount() default 0;
/**任务参数*/
String executorParam() default "";
/**GLUE备注*/
String glueRemark() default "GLUE代码初始化";
/**GLUE源码(命令行、java等调度方式使用)*/
String glueSource() default "";
/**报警接收的邮箱*/
String alarmEmail() default "";
/**调度过期策略*/
MisfireStrategyEnum misfireStrategy() default MisfireStrategyEnum.DO_NOTHING;
}
```
------------------------------
easy-do-xxl-job
一、 **Oauth2鉴权模块**
鉴权服务、资源服务、客户端服务分别为两个starter模块 ,按照服务需求引入依赖即可自动装配
鉴权服务(easy-do-oauth2-server):
```
easydo.plus
easy-do-oauth2-server
1.0.1
```
- 实现tokenInfo(oauth/token)返回用户数据的强扩展(用户信息、全部鉴权信息 配置文件可控制是否开启)
- 实现openfeign微服务调用token传递、支持以client方式获取token调用其他资源服务,
- 数据库持久化管理客户端信息、
- 支持配置文件设置自定义登录、授权页面、
- Redis存储token 序列化(默认关闭fastjson序列化,配置文件控制开关),
配置文件详解
```yaml
################OAuth授权相关配置#######################
security:
oauth2:
whiteList: ${WHITELIST:/actuator/**,/doc.html**,/swagger-resources,/v2/api-docs}
client:
oauth-server-name: ${OAUTH_SERVER_NAME:oauth-server}
oauth-server-uri: ${OAUTH_SERVER:http://localhost}
client-id: ${CLIENT_ID:oauth-server}
client-secret: ${CLIENT_SECRET:oauth-server-secret}
grant-type: ${GRANT_TYPE:client_credentials}
access-token-uri: ${OAUTH_SERVER:http://localhost}/oauth/token}
customize:
access-token-validity-seconds: ${ACCESS_TOKEN_VALIDITY_SECONDS:72000} #token有效时间
refresh-token-validity-seconds: ${REFRESH_TOKEN_VALIDITY_SECONDS:259200} #刷新token有效时间
enable-fastJson-serializer: ${ENABLE_FASTJSON_SERIALIZER:true} #是否开启fastjson序列化
oath-token-prefix: ${OATH_TOKEN_PREFIX:'OAUTH2_TOKEN:'} #redisToken前缀
oauth-code-prefix: ${OAUTH_CODE_PREFIX:'AuthorizationCode:'} #redis授权码前缀
code-client-prefix: ${CODE_CLIENT_PREFIX:'ClientToAuthCode:'} #redis授权码客户端id前缀
oauth-code-length: 12 #授权码长度
login-path: ${LOGIN_PATH:/login} #自定义登陆页面控制层请求路径
login-html: ${LOGIN_HTML:login} #登陆页面html文件名
login-submit-url-key: ${LOGIN_SUBMIT_URL_KEY:loginSubmitUrl} #登录页面提交url的Key thymeleaf页面取值
confirm-access-path: ${CONFIRM_ACCESS_PATH:/custom/confirm_access} #自定义授权跳转页面的控制层路径
confirm-access-html-prefix: ${CONFIRM_ACCESS_HTML_PREFIX:oauth} #自定义授权页面的html文件名前缀
token-info-all: ${TOKEN_INFO_ALL:false} #checkToken请求 是否返回全部Authentication信息
token-info-user: ${TOKEN_INFO_USER:true} #checkToken请求 是否返回登录用户的详细信息
```
二、 资源服务(easy-do-oauth2-resource-starter):
```
easydo.plus
easy-do-oauth2-resource-starter
1.0.1
```
配置文件填写授权服务地址、 客户端id 、密钥 等信息
```yaml
security:
oauth2:
whiteList: ${WHITELIST:/actuator/**,/doc.html**,/swagger-resources,/v2/api-docs}
resource:
id: ${RESOURCE_ID:user-center}
token-info-uri: ${OAUTH_SERVER:http://localhost}/oauth/check_token
client:
client-id: ${CLIENT_ID:user-center}
client-secret: ${CLIENT_SECRET:user-center-secret}
```
启动类开启自动机权限注解
```java
@EnableCustomizePreAuthorize
@EasyDoEnableOpenFeignClients
@SpringBootApplication
public class UserCenterMybatisPlusApplication
```
自定义权限注解使用
```java
//跳过授权,不需要登录、携带token、可匿名访问
@IgnoreThePermissions
// 权限字符校验,系统管理中配置的角色菜单权限字段
@ApiOperation(value = "分页条件查询oauth2客户端信息列表")
@CustomizePreAuthorize(hasPermission = {"usercenter:clentDetails:page"})
@PostMapping("/page")
public MPDataResult page(OauthClientDetailsQo qo) {
IPage page = oauthClientDetailsService.page(qo);
return ok(page);
}
//scope作用域校验
@PreAuthorize("hasScope('oauth-server')")
@RequestMapping("/findByUserName")
public R findByUserName(String userName) {
}
//注解内所有用法
/**具有权限字段则通过*/
String[] hasPermission() default {};
/**不具有指定权限字段则通过*/
String[] notHasPermission() default {};
/**具有特定scpo则通过*/
String[] hasScope() default {};
/**不具有指定scpo则通过*/
String[] notHasScope() default {};
/**指定的客户端才能访问*/
String hasClient() default "";
/**不是指定的客户端才能访问*/
String notHasClient() default "";
/**指定的资源服务才能访问*/
String[] hasResource() default {};
/**不是指定的资源服务才能访问*/
String[] notHasResource() default {};
/**scope具有写权限*/
boolean read() default false;
/**scope具有读取权限*/
boolean write() default false;
/**scope具有创建权限*/
boolean create() default false;
/**scope具有删除权限*/
boolean delete() default false;
/**scope具有ALL权限*/
boolean all() default false;
```
- 自定义Oauth2工具类 能够轻松获取用户信息和客户端信息。
- 自定义鉴权注解,实现细粒度权限控制,完美拓展原生的PreAuthorize注解
- 支持scope鉴权、角色鉴权、权限码鉴权、资源id鉴权、客户端id鉴权 admin用户自动放过
- 自定义注解,不需要写表达式,直接在注解设置相关属性即可(基于AOP Oauth2Utils 和自定义权限校验表达式)。
三、 客户端服务(easy-do-oauth2-resource-starter),直接引入:
```
easydo.plus
easy-do-oauth2-client
1.0.1
```
配置文件填写授权服务地址、 客户端id 、密钥 等信息
```yaml
security:
oauth2:
client:
oauth-server-name: ${OAUTH_SERVER_NAME:oauth-server}
oauth-server-uri: ${OAUTH_SERVER:http://localhost}
client-id: ${CLIENT_ID:oauth-server}
client-secret: ${CLIENT_SECRET:oauth-server-secret}
grant-type: ${GRANT_TYPE:client_credentials}
access-token-uri: ${OAUTH_SERVER:http://localhost}/oauth/token}
```
```java
@OauthFeignClient(name = "user-center",path = "/user", fallbackFactory = UserServiceFallbackFactory.class)
//注解的默认配置类支持token自动获取并传递
Class>[] configuration() default {Oauth2FeignClientInterceptor.class};
```
- openfeign调用自动获取token 、自动获取鉴权信息,保证通信安全性的同时更便捷。
四、 接口文档 (easy-do-knife4j):
- 集成自knife4j 做了再次封装,直接引入,无需额外代码配置。
```
easydo.plus
easy-do-knife4j
1.0.1
```
```yaml
knife4j:
enable: true
custom:
basePackage: plus.easydo.server.user.mp.controller
title: 接口文档标题
groupName: 分组名称
description: 接口文档描述
version: 1.0
prefix: /
contact:
name: easy-do
url: www.easy-do.plus
email: gebilaoyu@foxmail.com
# documents:
# -
# group: 2.X版本
# name: 隔壁老于
# #文件夹
# locations: classpath:markdowns/*
# #单个文件
# locations: classpath:md/sign.md
setting:
language: zh-CN
enableSwaggerModels: true
enableDocumentManage: true
swaggerModelName: 实体类列表
enableVersion: false
enableReloadCacheParameter: false
enableAfterScript: true
enableFilterMultipartApiMethodType: POST
enableFilterMultipartApis: false
enableRequestCache: true
enableHost: false
#enableHostText: 127.0.0.1:8000
enableHomeCustom: false
homeCustomLocation: classpath:markdown/home.md
enableSearch: true
enableFooter: true
enableFooterCustom: true
footerCustomContent: Apache License 2.0 | Copyright 2021-[easy-do](https://gitee.com/yuzhanfeng/easy-do)
enableDynamicParameter: true
enableDebug: true
enableOpenApi: true
enableGroup: true
cors: false
production: false
basic:
enable: false
username: admin
password: admin
```
五. mybais-plus (easy-do-mybatis) 集成动态数据源、无需额外配置,引入依赖即可
- 动态数据源集成自(项目地址:https://gitee.com/baomidou/dynamic-datasource-spring-boot-starter) 做了再次封装,直接引入,无需额外代码配置。
```
easydo.plus
easy-do-mybatis
1.0.1
```
提供的快速开发java类,以及使用示例
```java
//几个常用的类
plus.easydo.starter.mybatis.plus.base.BaseController
plus.easydo.starter.mybatis.plus.entity.MPBaseEntity
plus.easydo.starter.mybatis.plus.qo.MpBaseQo.clss
plus.easydo.starter.mybatis.plus.result.MPDataResult
plus.easydo.starter.mybatis.plus.result.MPResultUtil
//使用示例
/**
* 用户信息
*
* @author ruoyi
*/
@RestController
@RequestMapping("/user")
public class SysUserController extends MPBaseController {
@PreAuthorize("hasScope('oauth-server')")
@RequestMapping("/findByUserName")
public R findByUserName(String userName) {
SysUser user = userService.selectUserByUserName(userName);
return ok(user);
}
/**
* 获取用户列表
*/
@CustomizePreAuthorize(hasPermission = {"system:user:list"})
@PostMapping("/page")
public MPDataResult page(@RequestBody UserQo qo) {
IPage page = userService.page(qo);
return ok(page);
}
/**
* 新增用户
*/
@PreAuthorize("hasPermission('system:user:add')")
@PostMapping
public R