克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

EasyBoot

介绍

EasyBoot是一个追求易学、易用、易扩展的快速开发框架。

相关技术

项目说明

EasyBoot内主要是基础的功能和平台。

EasyPlugins项目里面主要包含一些扩展插件

EasyStarter简单的示例启动项目

EasyBoot项目结构

  • easy-core 核心模块,不带业务逻辑,包含了一些基础功能扩展,如配置项,菜单配置,权限认证等功能
  • easy-platform 基础平台模块,包含了用户管理,权限管理,等平台业务功能,带相关界面
  • easy-dev 开发工具模块,包括代码生成和一些小工具
  • easy-vue vue模板加载模板,包含了vue的主文件。提供了vue文件,mjs文件,less文件的页面端支持

系统功能

  • 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
  • 角色管理:对权限与菜单进行分配,角色可绑定用户和菜单/按钮权限
  • 部门管理:可配置系统组织架构,树形表格展示。部门有一个带级连关系的内部ID。
  • 字典管理:可维护常用一些固定的数据,如:状态,性别等
  • 配置项管理:管理各种常用可变配置
  • 用户日志:记录用户操作日志,可自定义日志
  • 慢SQL日志:记录运行慢的日志,方便维护和调优,阈值可设置
  • 定时任务:方便定时任务,有任务执行记录
  • 报表管理:XMReport集成,在线模板设计器,pdf导出
  • 代码生成:高灵活度生成前后端代码,减少大量重复的工作任务
  • API接口:可以导出api.json和在线调试

快速开始

  • 导入项目 EasyStarter,直接启动按SpringBoot项目启动即可。
  • 或者常规新建maven项目,然后修改pom.xml
<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">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>easyboot</artifactId>
        <groupId>com.rankeiot.easy</groupId>
        <version>1.1-SNAPSHOT</version>
    </parent>
    <groupId>yourgroupId</groupId>
    <artifactId>youartifactId</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <repositories>
        <repository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
    <dependencies>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-vue</artifactId>
        </dependency>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-dev</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-platform</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

启动后打开浏览器进入 http://localhost:8080

安装

目前只支持了mysql,当然sqltoy本身是适配了多数据库的。填写完数据库信息后点确定即可进行数据库的初始化。初始化完成后会在项目目录下生成application-dev.yml文件。 可将application-dev.yml移动到src/main/resources目录下面,这样打包后运行不需要重新配置。也可以将application-dev.yml放置与jar包同一目录(工作目录) 初始化完成后不出意外的化,我们会看到下面的界面

安装完成

进入系统后我们会看到一个非常干净的首页。可通过新建文件 src/main/resources/static/home.vue 来覆盖首页,其他页面也可以通过这种方式覆盖。

首页

到这里基本的系统已经跑起来了。

开发指南

建议使用IDEA进行开发,根据Maven的profile配置,IDEA会在项目打开的时候会显示对于的配置选项。EasyBoot开发依赖数据库设计,当设计好数据库后,我们可以从系统中直接导入表模型进行代码生成。

IDEA

开发的时候,maven默认选择了dev这个profile。在打包的时候应该选择prod,maven会根据参数替换application.yml中的配置,并去掉开发和接口api模块进行打包

代码生成

在开发模式下(profile=dev),进入http://localhost:8080,选择代码生成器进入下面菜单。通过导入数据库中以及设计好的数据库表的方式,我们可以导入模型,生成对应代码。数据库表设计时,请添加必要的表注释及字段注释。

代码生成器

后端指南

Easy Boot后端采用SpringBoot和sqltoy进行开发

模块划分

Easy Boot按照业务划分包模块,可在模块中配置模块的业务菜单,固定配置项,字典项等

对于需要独立出来的模块,需要进行下面的定义

//可参考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使用注解方式来声明权限


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";
}


/**
 *
 * 示例 @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<Integer> ids){
        // dao.loadAll(students);
        List<Student> 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<Student> detail(Integer id){
        Student student=dao.load(new Student(id));
        return Resp.of(student);
    }
    /**
     * 获取学生列表
     */
    @ApiOperation("列出学生")
    @Auth(StuMenu.STUDENT)
    @PostMapping("list")
    public Resp<Map> 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<StreamingResponseBody> 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();
    }
}

固定配置项

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();
        // ...
    }
}
 

固定字典项

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文件导出
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<StreamingResponseBody> 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<String, Object>) 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 文件导出
 <FileImport to="xxx/import">
  <Button icon="jeicon-upload" color="primary">导入文件</Button>
</FileImport>
    //文件上传方法
    @PostMapping("xx/import")
    public SseEmitter importFile(@RequestParam("file") MultipartFile file) {
        UserInfo user=Current.user();
        return FrontendProcess.create(p -> {
                p.info("文件上传完成,导入中...");
                ExcelBatchImporter<ExpendRecordImportVo> 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进行相关的短信发送操作

    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>dysmsapi20170525</artifactId>
    </dependency>

小程序支持

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及Vue3基础知识

前端框架支持

EasyBoot 完全支持RequireJS,可以按照RequireJS文档配置自定义的三方库。 使用es-module-shims实现了ES modules的加载, Vue UI库方面,EasyBoot 集成了好用的HeyUI,同时也集成了其他常用的Vue库,如果要引入自定义三方库,三方库需要支持Vue3及RequireJS(AMD规范,可通过配置shim方式配置常用库,如:Jquery) ,另外,EasyBoot支持加载以.mjs结尾的js模块文件,和以.less结尾的less文件,mjs文件为满足esm模块需求的js文件,EasyBoot将其转换为了CMD模块,支持大多数的esm语法,支持部分ES6语法,支持程度视浏览器兼容性而定,EasyBoot没有除了做压缩混淆外,没有做额外的语法支持

//hello.mjs 满足esm语法
function hello(){
    
}
export default{
    hello
}
//引用
import {hello} from './hello'

/**demo.less**/
.some{
  .color{
    color:red;
  }
}
/**
* html中引用
* <link href='./demo.css'/>
 */
/**
* js文件中引用
* require('./demo.css')
* mjs或者vue模块中引用
* require('./demo.css') 或 import './demo.css'
 */

framework.js

framework中封装了常用的一些方法

//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)

//其他用法
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'])
//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文件到浏览器
 * <FileInput accept=".xlsx" @change="doImport">
 *      <Button>Excel导入浏览器</Button>
 * </FileInput>
 */
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组件

<!--数据集合,与framework中createDs方法对应,具体使用方法产考生成的代码中的list页面-->
<DataSet url="some/url">
  <template #default="table">
    <Table :datas="table.data" :loading="table.loading"/>
  </template>
</DataSet>

<!--组件对话框,基于HeyUI中的Modal组件实现,具体使用方法产考生成的代码中的list页面-->
<Dialog href="dialog/url"></Dialog>

<!--Chart 基于Echarts的图表实现,options为Echarts中的options-->
<EChart :options="options"/>
<!--基于 [Chart.js](https://www.chartjs.org) 轻便好用-->
<Chart :options="options"/>

<!--FileDrop 文件拖入组件,拖入文件后会触发事件,可以用于表格中拖入文件上传等-->
<FileDrop accet=".png,.jpg" @drop="onFileDrop">
  把图片文件拖入到这里
</FileDrop>

<!--FileInput 类似于<input type='file'/>-->
<FileInput v-model="form.file" @change="onFileChange">
  <!--可在这里自定义显示-->
</FileInput>

<!--ImageViewer 图片预览-->
<ImageViewer :urlList="['img1.png','img2.jpg']" :initialIndex="0" v-model="show"/>

<!--代码编辑器 基于Monaco Editor-->
<MonacoEditor v-model="source" language="javascript" @change="onchange" @save="onCtrAndSPressed"/>

<!--RichTextEditor 富文本编辑器 基于wangEditor-->
<RichTextEditor v-model="source"/>

<!--FileUploader 文件上传组件,类似于HeyUI的Uploader,支持文件拖拽上传,文件拖拽排序。除v-model外,其他属性为非必需属性-->
<FileUploader v-model="files"
              accept=".jpg,.png"
              :readonly="false"
              :limit="-1"
              uploadPath="file/upload"
              deletePath="file/delete"
              @delete="onFileItemDelete">
</FileUploader>
<!-- 高德地图 经纬度绑定-->
 <AMapInput v-model:lngLat="lngLat"/>
<!--二维码 https://www.jsdelivr.com/package/npm/qrcode.vue-next-->
<QRCode value="需要显示的值"/>
DataSet 组件

用于获取后台数据的封装

<template>
  <DataSet url="some/url">
    <template #default="table">
      <Input v-model="table.params.queryParamA"/>
      <Table :datas="table.data" :loading="table.loading"/>
    </template>
  </DataSet>
</template>

参数

参数 类型 默认值 说明
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弹出框组件所有属性 不通处在于这里指定的url所对应组件为懒加载

<template>
  <Dialog href="path/dlg.vue" ref="dlgRef" hasDivider hasCloseIcon>
    <template #header>对话框标题</template>
    <template #footer="dlg">
      <Button @click="dlg.cancel">取消</Button>
      <Button :loading="dlg.loading" color="primary" @click="dlg.submit">确认</Button>
    </template>
  </Dialog>
</template>
<script setup>
import {ref} from 'vue'
const dlgRef=ref()

await dlgRef.value.open()

</script>

dlg.vue

<templage>

</templage>
<script setup>
//通过params获取 对话框open方法传入的参数
const {params,dialog} = defineProps({
  params: Object,
  dialog:Object
})

//设置数据提交监听
dialog.onSubmit(()=>{
  //状态修改为数据提交中
  dialog.loading(true)
  //处理完成后把数据作为open方法的返回值
  dialog.success("some data")
  //处理失败时把数据状态设置回来
  dialog.loading( false)
})
//dialog.cancel() 关闭对话框
</script>
Chart Echarts的图表实现

options 即为Echarts的options

<Chart :options="options"/>
前端导入Excel
<template>
  <FileInput accept=".xlsx" @change="onFile">
    <Button> 测试Excel导入</Button>
  </FileInput>
</template>
<script setup>
import xlsx from 'xlsx'
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = function (e) {
  const data = e.target.result;
  const excel = xlsx.read(data, {
    type: 'binary'
  });
  const result = [];
  for (let i = 0; i < excel.SheetNames.length; i++) {
    const newData = xlsx.utils.sheet_to_json(excel.Sheets[excel.SheetNames[i]]);
    result.push(...newData)
  }
  //获取到导入的数据
  console.log(JSON.stringify(result));
}
</script>

登录签名(token)算法

//过期时间(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 version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>easyboot</artifactId>
        <groupId>com.rankeiot.easy</groupId>
        <version>${lastVersion}</version>
    </parent>
    <groupId>com.your.groupid</groupId>
    <artifactId>yourartifact</artifactId>
    <version>1.0-SNAPSHOT</version>
    <repositories>
        <repository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
    <dependencies>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-vue</artifactId>
        </dependency>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-platform</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
public static void main(String[] args) {
    new PlatformApplication().start(args);
}

应用插件

应用插件配置说明 插件目录结构,将插件的jar文件及依赖jar(主框架已经包含的不需要再次添加)文件和插件描述文件plugin.json一起打为zip包(没有二级目录)

/
├── plugin.json
├── lib1.jar
├── lib2.jar
├── ...

描述文件,其中id,version,framework为必填项,其他为选填项

{
  "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

//MainTestApp.java
public static void main(String[] args) {
    new PlatformApplication().start(args);
}

plugin.json

{
  "id": "${artifactId}",
  "version": "${version}",
  "framework": "${easy.ver}",
  "author": "EasyBoot",
  "name": "${name}",
  "description": "${description}",
  "depends": [

  ]
}

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>easyboot</artifactId>
        <groupId>com.rankeiot.easy</groupId>
        <version>${lastVersion}</version>
    </parent>
    <groupId>com.your.groupid</groupId>
    <artifactId>yourartifact</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>DemoAPP</name>
    <description>
        demo app是一个测试接口应用
    </description>
    <repositories>
        <repository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>rankeiot-public-central</id>
            <name>central</name>
            <url>https://rankeiot-maven.pkg.coding.net/repository/public/central/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
    <dependencies>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-vue</artifactId>
        </dependency>
        <dependency>
            <groupId>com.rankeiot.easy</groupId>
            <artifactId>easy-platform</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
    <!--插件自动生成配置模板-->
    <build>
        <plugins>
            <!--生成plugin.json-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>generate-resources</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.outputDirectory}/</outputDirectory>
                            <resources>
                                <resource>
                                    <directory>src/main/resources</directory>
                                    <filtering>true</filtering>
                                    <includes>
                                        <include>plugin.json</include>
                                    </includes>
                                </resource>
                            </resources>
                            <delimiters>
                                <delimiter>${*}</delimiter>
                            </delimiters>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- 根据条件配置需要导出的依赖-->
            <!--
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib/</outputDirectory>
                            <includeArtifactIds>
                                commons-beanutils,commons-text
                            </includeArtifactIds>
                        </configuration>
                    </execution>
                    <execution>
                        <id>list-dependencies</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>list</goal>
                        </goals>
                        <configuration>
                            <outputFile>${project.build.directory}/dependency-list.text</outputFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            -->
        </plugins>
    </build>
</project>

应用模块配置类

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
  • 放入模块文件名,如:
com.your.groupid.YourModule

插件默认配置文件

  • /src/main/java/resources/plugin_config.yml 里面放springboot相关配置,系统会自动加载,但是如果别的插件也配置了同一个配置项目,会被覆盖
MIT License Copyright (c) 2024 非著名职业BUG撰写师 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

暂无描述 展开 收起
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化