# EasyBoot **Repository Path**: ApeCoder/easy-boot ## Basic Information - **Project Name**: EasyBoot - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: 1.1 - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-05-10 - **Last Updated**: 2024-11-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # EasyBoot ## 介绍 EasyBoot是一个追求易学、易用、易扩展的快速开发框架。 ## 相关技术 - 后端基础框架 [SpringBoot](https://spring.io/projects/spring-boot) - ORM框架 [Sqtoy](https://gitee.com/sagacity/sagacity-sqltoy) - HTTP客户端 [Forest](https://forest.dtflyx.com/) - 前端框架 [Vue3](https://cn.vuejs.org/) - 前端UI组件 [HeyUI](https://v2.heyui.top/) - 前端加载器 [RequireJs](https://requirejs.org/) - 前端加载器(待选) [es-module-shims](https://github.com/guybedford/es-module-shims) ## 项目说明 [EasyBoot](https://gitee.com/rankeiot/easyboot)内主要是基础的功能和平台。 [EasyPlugins](https://gitee.com/rankeiot/easyplugins)项目里面主要包含一些扩展插件 [EasyStarter](https://gitee.com/rankeiot/easystarter)简单的示例启动项目 ### EasyBoot项目结构 - easy-core 核心模块,不带业务逻辑,包含了一些基础功能扩展,如配置项,菜单配置,权限认证等功能 - easy-platform 基础平台模块,包含了用户管理,权限管理,等平台业务功能,带相关界面 - easy-dev 开发工具模块,包括代码生成和一些小工具 - easy-vue vue模板加载模板,包含了vue的主文件。提供了vue文件,mjs文件,less文件的页面端支持 ### 系统功能 - 用户管理:提供用户的相关配置,新增用户后,默认密码为123456 - 角色管理:对权限与菜单进行分配,角色可绑定用户和菜单/按钮权限 - 部门管理:可配置系统组织架构,树形表格展示。部门有一个带级连关系的内部ID。 - 字典管理:可维护常用一些固定的数据,如:状态,性别等 - 配置项管理:管理各种常用可变配置 - 用户日志:记录用户操作日志,可自定义日志 - 慢SQL日志:记录运行慢的日志,方便维护和调优,阈值可设置 - 定时任务:方便定时任务,有任务执行记录 - 报表管理:XMReport集成,在线模板设计器,pdf导出 - 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务 - API接口:可以导出api.json和在线调试 ## 快速开始 - 导入项目 [EasyStarter](https://gitee.com/rankeiot/easystarter),直接启动按SpringBoot项目启动即可。 - 或者常规新建maven项目,然后修改pom.xml ```xml 4.0.0 easyboot com.rankeiot.easy 1.1-SNAPSHOT yourgroupId youartifactId 1.0-SNAPSHOT 17 17 UTF-8 rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true always rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true com.rankeiot.easy easy-vue com.rankeiot.easy easy-dev runtime true org.springframework.boot spring-boot-devtools runtime true com.rankeiot.easy easy-platform org.projectlombok lombok compile true mysql mysql-connector-java org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok true ``` 启动后打开浏览器进入 http://localhost:8080 ![安装](doc/install.png) 目前只支持了mysql,当然sqltoy本身是适配了多数据库的。填写完数据库信息后点确定即可进行数据库的初始化。初始化完成后会在项目目录下生成application-dev.yml文件。 可将application-dev.yml移动到src/main/resources目录下面,这样打包后运行不需要重新配置。也可以将application-dev.yml放置与jar包同一目录(工作目录) 初始化完成后不出意外的化,我们会看到下面的界面 ![安装完成](doc/installed.png) 进入系统后我们会看到一个非常干净的首页。可通过新建文件 src/main/resources/static/home.vue 来覆盖首页,其他页面也可以通过这种方式覆盖。 ![首页](doc/index.png) 到这里基本的系统已经跑起来了。 ## 开发指南 建议使用IDEA进行开发,根据Maven的profile配置,IDEA会在项目打开的时候会显示对于的配置选项。EasyBoot开发依赖数据库设计,当设计好数据库后,我们可以从系统中直接导入表模型进行代码生成。 ![IDEA](doc/idea.png) 开发的时候,maven默认选择了dev这个profile。在打包的时候应该选择prod,maven会根据参数替换application.yml中的配置,并去掉开发和接口api模块进行打包 ### 代码生成 在开发模式下(profile=dev),进入http://localhost:8080,选择代码生成器进入下面菜单。通过导入数据库中以及设计好的数据库表的方式,我们可以导入模型,生成对应代码。数据库表设计时,请添加必要的表注释及字段注释。 ![代码生成器](doc/designer.png) ### 后端指南 Easy Boot后端采用SpringBoot和sqltoy进行开发 #### 模块划分 Easy Boot按照业务划分包模块,可在模块中配置模块的业务菜单,固定配置项,字典项等 对于需要独立出来的模块,需要进行下面的定义 ```java //可参考com.rankeiot.platform.PlatformModule @Configuration public class DemoModule implements Module { public void start(ApplicationContext context) { //注册菜单 //regMenu(TestMenu.class); } } //按spring自动组件的要求,新建文件 /sources/META-INF/spring.factories,加入: //org.springframework.boot.autoconfigure.EnableAutoConfiguration=模块完整类名,如:com.rankeiot.platform.PlatformModule ``` ### 业务菜单和权限 Easy Framework使用注解方式来声明权限 ```java import com.rankeiot.core.anno.Menu; import com.rankeiot.core.anno.Permission; //这里声明了菜单以及权限 @Menu(value = "测试", icon = "icon-file", id = TestMenu.ID) public interface TestMenu { String ID = "Demo"; @Menu(value = "示例", path = "test/demo.vue", icon = "icon-file") String DEMO = ID + ".demo"; // demo增删改权限 @Permission(value = "新增", parent = DEMO) String DEMO_ADD = DEMO + ".add"; @Permission(value = "修改", parent = DEMO) String DEMO_EDIT = DEMO + ".edit"; @Permission(value = "删除", parent = DEMO) String DEMO_DELETE = DEMO + ".delete"; } ``` ```java /** * * 示例 @Auth 表示需要登录,@Auth(string)表示调用该方法需要的权限,也可指定所需角色(role) * 当传入多个权限或者角色时,表示有当中任意一个条件满足即可调用该方法 * 以下@Api和ApiOperation注解为Swagger注解,使用Swagger注解的Controller才会出现在API文档中 * 除此外,Controller写法与常规SpringBoot Controller相同 * */ @Api(tags="学生") @Auth @RestController @RequestMapping("demo") @RequiredArgsConstructor public class DemoController { final SqlToyLazyDao dao; /** * 新增学生 */ @ApiOperation("新增学生") @Auth(StuMenu.STUDENT_ADD) @PostMapping("add") public Resp add(@Valid @RequestBody Student student){ dao.save(student); return Resp.ok(); } /** * 删除学生 */ @ApiOperation("删除学生") @Auth(StuMenu.STUDENT_DELETE) @Transactional @PostMapping("delete") public Resp delete(List ids){ // dao.loadAll(students); List students = CollectionUtil.map(ids,Student::new); dao.deleteAll(students); return Resp.ok(); } /** * 更新学生 */ @ApiOperation("更新学生") @Auth(StuMenu.STUDENT_EDIT) @PostMapping("save") public Resp save(@Valid @RequestBody Student student){ dao.update(student); return Resp.ok(); } /** * 获取学生 */ @ApiOperation("获取学生详细") @Auth(StuMenu.STUDENT) @GetMapping("detail") public Resp detail(Integer id){ Student student=dao.load(new Student(id)); return Resp.of(student); } /** * 获取学生列表 */ @ApiOperation("列出学生") @Auth(StuMenu.STUDENT) @PostMapping("list") public Resp list(QueryPage query){ Page result = dao.findPageBySql(query.page(),"student_list",query.getParams()); return Resp.of(result); } /** * 导出学生 */ @ApiOperation("导出学生") @Auth(StuMenu.STUDENT) @PostMapping(value="export",produces = "application/vnd.ms-excel") public ResponseEntity export(QueryParams query){ return Resp.export("学生" + DateUtil.format(new Date(), "yyMMdd") + ".xlsx" , out -> { ExcelStreamExporter exporter = new ExcelStreamExporter(out); dao.fetchStream(query.getQueryExecutor("student_list").resultType(Student.class), exporter); }); } /** * 导入学生 */ @ApiOperation("导入学生") @Auth(StuMenu.STUDENT_ADD) @Transactional @PostMapping("import") public Resp importData(MultipartFile file) throws IOException { if(file==null){ Resp.fail("未上传文件"); } ExcelBatchImporter importer=new ExcelBatchImporter(file.getInputStream(), Student.class); importer.start((batchData,lastIndex)->{ dao.saveAll(batchData); }); return Resp.ok(); } } ``` #### 固定配置项 ```java import com.rankeiot.core.config.ControlType; import com.rankeiot.core.config.IConfigItem; import com.rankeiot.core.config.Item; /** * 系统配置项,通过enum+@Item注解的方式声明配置项,配置项的key值为enum类名+条目名, * 比如下面这个DemoName的Key值为DemoConfig.DemoName。该可以值作为数据库中t_config表的sn列 * 或者前端调用时使用,如: _config[key] * 当front=true时,表示可以在前端页面中直接使用_config[key]获取对应key的配置值 * 固定配置项需要在模块配置中注册,在任意代码初始化的地方调用注册方法即可,一般是在main方法或Configuration类中调用 * ConfigManager.register("配置所属分组",DemoConfig.class); * 也可在Module的start 方法中调用 * regConfigs(DemoConfig.class); */ public enum DemoConfig implements IConfigItem { @Item(title="测试配置",defaultValue = "Hello",front = true) DemoName; //后端获取配置项的值 public static void demo(){ String str= DemoConfig.DemoName.value().asString(); Date date= DemoConfig.DemoName.value().asDate(); // ... } } ``` #### 固定字典项 ```java import com.rankeiot.core.dict.IFixedDict; import com.rankeiot.core.dict.Title; /** * 在任意代码初始化的地方调用注册方法,一般是在main方法或Configuration类中调用 * FixedDictManager.regFixedDict(Gender.class); * 会把该固定字典项注册到系统,在系统的字典菜单中可以看到该字典 * 也可在Module的start 方法中调用 * regFixedDict(Gender.class); */ /** * 字典常规写法,表示 * * 性别:Gender * 男:M * 女:F */ @Title("性别") @Getter @RequiredArgsConstructor public enum Gender implements ITitleFixedDict { M("男"), F("女"); final String title; } /** * 字典,可以指定特定值,但是无法直接通过字面量转换为Enum,如下:表示 * 性别:Gender * 男:1 * 女:0 */ @Title("性别") @Getter @RequiredArgsConstructor public enum Gender implements ITitleFixedDict { M("1","男"), F("0","女"); final String value; final String title; } /** * 字典常规写法,效果同示例1,表示 * * 性别:Gender * 男:M * 女:F */ @Title("性别") public enum Gender implements IFixedDict { @Title("男") //Male M, @Title("女")//Female F } ``` #### 后端Excel导入导出 后端通过定义Excel Bean的方式来实现Excel的导入导出 - Excel文件导出 ```java import com.rankeiot.core.anno.Excel; @Data public class ExportVo{ @Excel("姓名") String name; @Excel("出生日期") @JsonFormat(pattern="yyyy年MM月dd日") Date brith; //也可通过 @Translate() 注解处理格式 } public class ExportImportController{ //在spring 的controller中通过 ResponseEntity 导出 public ResponseEntity exportExcel(QueryParams query){ return Resp.export("导出文件名.xlsx",out->{ ExcelStreamExporter exporter=new ExcelStreamExporter(out); //可设置数据转换翻译 //exporter.translate("field",Translator) QueryExecutor qe=new QueryExecutor("export sql id",(Map) query.getParams()); qe.resultType(ExportVo.class); dao.fetchStream(qe,exporter); }); } //简单导入 public void importExcel(MultipartFile mf){ ExcelBatchImporter bi=new ExcelBatchImporter(mf.getInputStream(),ExportVo.class); //可设置数据转换翻译 //exporter.translate("field",Translator) //默认500条一批数据读入,如果需要全部读入内存后处理,可在下面缓存后处理 //bi.setBatchSize(500); bi.start((batch,index)->{ // }); } } ``` - Excel 文件导出 ```vue ``` ```java //文件上传方法 @PostMapping("xx/import") public SseEmitter importFile(@RequestParam("file") MultipartFile file) { UserInfo user=Current.user(); return FrontendProcess.create(p -> { p.info("文件上传完成,导入中..."); ExcelBatchImporter bi = new ExcelBatchImporter(file.getInputStream(), ExpendRecordImportVo.class); bi.start((list, idx) -> { //list就是处理好的数据列表 }); p.info("导入完成..."); }); } //数据模板 @Data //指定起始行 @ExcelTemplate(startRow = 2) public static class ExpendRecordImportVo { //指定字段列 @Excel(columnName = "A") private String projectName; } ``` #### 短信集成 pom.xml中加入依赖,在后台配置界面配置好阿里云短信服务的相关配置后,可以通过com.rankeiot.platform.service.SmsService进行相关的短信发送操作 ```xml com.aliyun dysmsapi20170525 ``` #### 小程序支持 easy-platform.jar 中的uni/api目录下内置了两个uni-app的后端接口文件。把它放入uni项目中,配置后端路径。 支持前端用户登录,用户信息获取,ajax请求自动处理token 同时在后端配置设置中配置好对应的小程序ID和secretKey可使用小程序的登录和手机快捷登录 ### 前端指南 EasyBoot 前端开发框架基于Vue3,~~采用RequireJS结合自定义loader做vue文件加载。~~ 采用es-module-shims做vue和js,css文件加载。 在调试模式下,loader直接加载.vue模板文件,通过loader将模板动态编译为js模块。打包发布时,vue模板文件会被打包为压缩混淆的js文件,loader直接加载js文件,减少响应的数据量,加快响应速度。需要注意的是,前端所有文件应放在文件夹resources/static/下面,该目录对应了web请求的根目录。 本文默认前端掌握[ES6](ES6.md)及Vue3基础知识 #### 前端框架支持 EasyBoot ~~完全支持[RequireJS](https://requirejs.org/),可以按照RequireJS文档配置自定义的三方库。~~ 使用[es-module-shims](https://github.com/guybedford/es-module-shims)实现了ES modules的加载, Vue UI库方面,EasyBoot 集成了好用的[HeyUI](https://www.heyui.top/),同时也集成了其他常用的Vue库,如果要引入自定义三方库,三方库需要支持Vue3及RequireJS(AMD规范,可通过配置shim方式配置常用库,如:Jquery) ,另外,EasyBoot支持加载以.mjs结尾的js模块文件,和以.less结尾的less文件,mjs文件为满足[esm](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules)模块需求的js文件,EasyBoot将其转换为了CMD模块,支持大多数的esm语法,支持部分ES6语法,支持程度视浏览器兼容性而定,EasyBoot没有除了做压缩混淆外,没有做额外的语法支持 ```javascript //hello.mjs 满足esm语法 function hello(){ } export default{ hello } //引用 import {hello} from './hello' ``` ```less /**demo.less**/ .some{ .color{ color:red; } } /** * html中引用 * */ /** * js文件中引用 * require('./demo.css') * mjs或者vue模块中引用 * require('./demo.css') 或 import './demo.css' */ ``` #### framework.js framework中封装了常用的一些方法 ```javascript //ajax 相关,ajax相关操作除特殊说明外,均返回promise import {ajax} from 'framework' //get 请求 let promise=ajax.get(url,{...params}) //post 请求 let promise=ajax.post(url,{...params}) //put 请求 let promise=ajax.put(url,{...params}) //delete 请求 let promise=ajax.delete(url,{...params}) //post 以表单方式提交 ajax.formPost(url,{...params}) //post 上传单个, let params={ file:File } //或者多个文件 let params={ file:[...files] } //或者 命名的多个文件,需要后端对应属性名 let params={ file:file, file1:file1 } ajax.upload(url,{...params}) /** * 文件下载,也可以用window.open(url)等方式下载文件, * 若需要登录用户授权,可以添加url参数 _token=sessionStorage._token */ ajax.download(url,params={},method="POST") //ajax方式的文件下载 downloadA(path, fileName = "", params = {}, method = 'GET') /** * 加载带缓存数据,可直接用于vue数据绑定, * @param url * @param defaultValue * @returns VueRef */ ajax.data(url, defaultValue) /** * 通过url创建数据集,可用于datatable,select等数据绑定 */ ajax.createDs(uri, pageAble = false) //数据集使用 const ds=ajax.createDs('someurl',true) //数据集中的数据,可以直接绑定到datatable上 ds.data //设置附加查询参数,也可直接绑定到vue查询控件上 ds.params.param1='value1' //加载数据,也可通过该方法重新加载数据 ds.load() //设置数据转换,每次数据加载后会通过这方法转换数据 ds.transformer((v)=>v); //清空数据 ds.clean() //设置自定义数据 ds.putData([...data]) //可在数据加载前修改查询参数 ds.on('beforeLoad',(params)=>undefined) //可在数据加载后修改响应数据 ds.on('load',(data)=>undefined) //数据加载错误时调用 ds.on('error',(error)=>undefined) ``` ```javascript //其他用法 import {uuid,format,hasPermission,hasRole,mapState,mapActions} from 'framework' //生成一个随机id 如:'1gk2o6462g94p92' uuid() //数据格式化,两种调用方式 '1.00' format(1,"####.00") const fmt=format("####.00"); fmt(1) //日期格式化,两种调用方式 '2022-12-12' format(Date.now(),"yyyy-MM-dd") const fmt=format("yyyy-MM-dd"); fmt(Date.now()) //判断用户是否有某个权限/角色 hasPermission('some.priv') hasRole('some.role') //引用vue store,也可直接使用 vuex const [user,theme]=mapState(['user','theme']) const loadUserInfo = mapActions(['loadUserInfo']) ``` ```javascript //framework util中包含了一些数据操作的方法 import {util} from 'framework' /** * 数组转换为map * @param list 数组 * @param getId * @param getValue * @returns {{}} */ util.asMap(list, getId = (it, idx) => idx, getValue = it => it) /** * 数组转换为树,parentId为0,false,null的或者获取不到parent的节点转为根节点 * @param list * @param getId * @param getParentId * @param getValue * @returns {*[]} */ util.asTree(list, getId = it => it, getParentId = it => null, getValue = it => it) /** * 获取一个对象中的多个值 */ util.fields(obj, fields) let obja={a:1,b:2,c:3} //obj2={a:1,b:2} let obj2=util.fields(obj,"a,b") //折叠/展开字段。由于现在后台本身支持类似的解码,所以本方法使用较少 // 输出 {a:"1,2,3",b:"1,2,3"} util.fold({a:[1,2,3],b:[1,2,3]}, "a,b") // 输出 {a:[1,2,3],b:[1,2,3]} util.unfold({a:"1,2,3",b:"1,2,3"}, "a,b") //清除对象的数据,输出: {a:null,b:null} util.clean({a:1,b:1}) /** * 导入Excel文件到浏览器 * * * */ function doImport(file){ //是否作为对象数组导出,以第一行为key值,默认为false,导出为二维数组 let asObj=true util.importExcel(file,asObj).then(r =>{ console.log(r) }) } import {useEvent,useStore,toRef,useDlg,getToken} from 'framework' //事件总线 //定义事件总线,其中server为服务器推送事件 let events=userEvent("server") //派发事件,server总线中的事件由后台派发com.rankeiot.platform.service.ServerEventPushService 派发 events.dispatchEvent("eventname",data) //添加监听 events.addEventListener("eventname",listener) //全局状态,第二个参数为默认值,可以是直接值,函数,异步函数,返回值为ref类型 let theme=useStore('theme','green') //将直接值,函数返回值,异步函数响应值转换为ref let data=toRef(ajax.get('xxxx')) /** * 封装内联对话框需要数据和方法 * dlg.isOpen * dlg.data * dlg.open(opendata=null) * dlg.close() * dlg.submit() */ let dlg=useDlg({},function onSubmit(){ }) //获取用户认证所需token let token = getToken() ``` #### 扩展组件 EasyBoot添加了部分Vue组件 ```vue 把图片文件拖入到这里 ``` ##### DataSet 组件 用于获取后台数据的封装 ```vue ``` 参数 | 参数 | 类型 | 默认值 | 说明 | |-----------|----------|--------------|-------------------------------| | url | string | | 获取数据的URL地址 | | pageable | boolean | false | 是否分页 | | pageSize | number | 10 | 每页数据长度 | | method | string | post | 数据提交方式 | | lazy | boolean | false | lazy为true时,需要手动调用 load 方法载入数据 | | transform | Function | (data)=>data | 数据转换方法,用于在显示前处理数据 | 事件 | 事件 | 参数 | 说明 | |------------|-------|----------------------------------------| | beforeLoad | param | 在请求前被调用,传入请求参数param,可通过修改param的值修改请求 | | load | data | 在请求完成后,数据展示前被调用 ,传入参数为响应的数据,可在这里修改展示数据 | | afterLoad | data | 在数据转换完成后被调用,传入转换处理过的数据 | 属性方法,通常通过 ref 的方式获取到其引用,同时slot中具有相同属性 | 方法/属性 | 类型 | 说明 | |------------|-------------------|-------------------------------------| | load | ()=>{} | 载入数据 | | reload | ()=>{} | 重新载入数据,相较于load,reload会把分页设置为第一页 | | setData | (data)=>{} | 手动设置其数据 | | setSort | ({prop,type})=>{} | 设置排序,prop为排序的字段,type为 desc/asc 排序类型 | | params | Object | 当前的查询参数 ,在slot中可用于绑定查询参数 | | pagination | {page,size} | 当前的分页状态,可用于绑定分页条 | | loading | ref(bool) | 当前数据加载状态,可用于绑定数据加载装状态 | ##### Dialog 对话框组件 用于打开对话框,用HeyUI Modal实现,继承了[Modal弹出框组件](https://v2.heyui.top/component/message/modal)所有属性 不通处在于这里指定的url所对应组件为懒加载 ```vue ``` dlg.vue ```vue ``` ##### Chart Echarts的图表实现 options 即为Echarts的options ```vue ``` ##### 前端导入Excel ```vue ``` ### 登录签名(token)算法 ```js //过期时间(s) 默认1800s let expire = 1800; //到期时间 let time = parseInt(Date.now() / 1000) + expire; //到期时间转换为7位36进制的字符串,不足位数以0补全 let t = leftPad(time.toString(36), '0', 7); //后端应用签名,一般为启动类类名,可通过配置 spring.application.name 这个配置项/环境变量来设置 let appSign='com.ranke.xxx.xxApplication' //userType为一位字符串一般为U或M,表示用户类型为用户或者会员,用户后端寻找用户 let value=userType+username //盐,用于验证签名,md5以hex形式展示 let salt=md5hex(username + "$" + password) + appSign let v = value + time + salt; //最后的token,长度为7+24+n,其中base64算法为urlbase64,即结果中的‘+/’会变为‘-_’ let token=t + md5base64(v) + urlbase64(value) ``` ### 应用插件系统 #### 基座平台 ```xml 4.0.0 easyboot com.rankeiot.easy ${lastVersion} com.your.groupid yourartifact 1.0-SNAPSHOT rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true always rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true always com.rankeiot.easy easy-vue com.rankeiot.easy easy-platform mysql mysql-connector-java javax.servlet javax.servlet-api 3.1.0 org.springframework.boot spring-boot-maven-plugin org.projectlombok lombok ``` ```java public static void main(String[] args) { new PlatformApplication().start(args); } ``` #### 应用插件 应用插件配置说明 插件目录结构,将插件的jar文件及依赖jar(主框架已经包含的不需要再次添加)文件和插件描述文件plugin.json一起打为zip包(没有二级目录) ``` / ├── plugin.json ├── lib1.jar ├── lib2.jar ├── ... ``` 描述文件,其中id,version,framework为必填项,其他为选填项 ```json5 { "id":"plugin-id", //插件ID,必填 "version":"1.0-SNAPSHOT",//插件版本号,必填 "framework": "1.1-SNAPSHOT", //主框架版本,必填 "name":"插件名称", "author":"EasyBoot", "description":"一个插件", "homepage":"https://gitee.com/desire1/app_manager", "depends":[ {"id":"other-plugin","version":"1.0.0"} //其他插件依赖 ] } ``` 应用功能文件结构 ``` /root ├── pom.xml ├── src │ ├── main │ │ ├── java │ │ │ └── yourpackage │ │ │ └── YourModule.java │ │ └── resources │ │ ├── META-INF │ │ │ └── spring │ │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ │ ├── static │ │ │ └── moduledir │ │ │ └── somefunction.vue │ │ ├── application-plugin.yml //可选的插件默认配置文件,按spirng的规范来配置 │ │ └── plugin.json │ └── test │ ├── java │ │ └── yourpackage │ │ └── MainTestApp.java │ └── resources │ └── application.yml //测试用配置文件 ``` MainTestApp.java ```java //MainTestApp.java public static void main(String[] args) { new PlatformApplication().start(args); } ``` plugin.json ```json { "id": "${artifactId}", "version": "${version}", "framework": "${easy.ver}", "author": "EasyBoot", "name": "${name}", "description": "${description}", "depends": [ ] } ``` pom ```xml 4.0.0 easyboot com.rankeiot.easy ${lastVersion} com.your.groupid yourartifact 1.0-SNAPSHOT DemoAPP demo app是一个测试接口应用 rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true always rankeiot-public-central central https://rankeiot-maven.pkg.coding.net/repository/public/central/ true true always com.rankeiot.easy easy-vue com.rankeiot.easy easy-platform mysql mysql-connector-java org.projectlombok lombok compile true javax.servlet javax.servlet-api 3.1.0 org.apache.maven.plugins maven-resources-plugin copy-resources generate-resources copy-resources ${project.build.outputDirectory}/ src/main/resources true plugin.json ${*} ``` 应用模块配置类 ```java package com.your.groupid; //配置类的包名尽量不要与其他模块及框架的包名冲突 @Configuration public class YourModule implements Module { public void start(ApplicationContext applicationContext) { //注册所需的各种功能 //regFixedDict(AppPlatform.class); //regFixedDict(ResourceType.class); //regMenu(AppMenu.class); //regConfigs(AppMgConfig.class); } } ``` 插件自动扫描配置 - 新增文件 /src/main/java/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - 放入模块文件名,如: ```properties com.your.groupid.YourModule ``` 插件默认配置文件 - /src/main/java/resources/plugin_config.yml 里面放springboot相关配置,系统会自动加载,但是如果别的插件也配置了同一个配置项目,会被覆盖