前面几篇具体介绍了框架内置的action功能都有哪些,目前框架封装了7大功能,crud外加上传,导入,导出,除了内置的功能之外,框架还提供给开发者宽广的自定义空间,本篇借着开发上传,导入,导出3个功能来阐述一下如何进行自定义开发,接下来是实战示例
自定义控制器框架引擎内置的控制器为JSRuleActionController,它的固定访问路径为/json/rule
@Autowired protected JSRuleActionServiceservice; @PostMapping(value = "/start") public JSResult startWithTimeRes() { return service.start(); } @PostMapping(value = "/end") public void endWithTimeLog() { service.start(); }
这里需要注意的是有返回值的请求是/start,没有返回值的请求是/end,如果你不想使用这个控制器或者不想使用这个访问路径/json/rule,那么我们可以自己来自定义一个控制器
- 首先第1步,我们创建一个控制器类,如下
@RestController
@RequestMapping("/asdqwe/zxc")
public class MyTestController{
@Autowired
protected JSRuleActionService jsres;
@PostMapping(value = "/start")
public JSResult mystart() throws Exception {
return jsres.start();
}
@PostMapping(value = "/end")
public void myexports(HttpServletRequest request,HttpServletResponse response) throws Exception {
jsres.start();
}
}
自定义的控制器可以继承内置的JSRuleActionController也可以不继承,继承的话可能会与JSRuleActionController中的/start或/end冲突,所以这里我们选择不继承,自己随便写一个
- 注入JSRuleActionService这个服务bean,如果你想要拿到json处理完后的rule对象,你只需要在任何一个spring bean的类中通过如下代码进行注入获取
@Autowired public JSGlobalVariablevariable;
可以简单的通过JSRuleActionService这个类中的源码进行参考,而之所以注入这个服务是因为调用框架引擎需要这个服务,当然了你不用引擎就不需要这个服务,那么你自定义这个控制器也就没什么意义了
- 修改拦截器拦截路径,找到配置文件,修改如下参数
json.rule.intercept.path=/asdqwe/zxc
@JsonAlias({"ofp"})
public String outFilePath;
@JsonAlias({"f"})
public String fileName;
@JsonAlias({"aPath"})
public String absolutePath;
@JsonAlias({"rPath"})
public String relativePath;
@JsonAlias({"s"})
@JSRuleCheck(checkSubClass=true)
public List> sheets;
@JsonAlias({"c"})
public int cacheRow;
@JsonIgnore
public HttpServletResponse response;
public JSRuleExportExcel() {
this.outFilePath = null;
this.fileName = JSRuleEnum.poi_default_file_name;
this.cacheRow = SXSSFWorkbook.DEFAULT_WINDOW_SIZE;
}
}
除了文件的属性之外,导出excel还应该有excel独有的sheet对象,而sheet它又应该是一个数组
- 接下来是创建JSRuleExportSheet对象,这个sheet对象就是最终我们导出时需要封装的一些功能参数了
@Data @JsonIgnoreProperties(ignoreUnknown=true) public class JSRuleExportSheetimplements IJSRuleModel{ @JsonAlias({"r"}) @JSRuleCheck(checkSubClass=true) public R get; //配置部分 @JsonAlias({"dv"}) public String defaultValue; //单元格为空时的默认值 @JsonAlias({"df"}) @JSRuleCheck(type = {ZSDate.date_mode_1,ZSDate.date_time_mode_1,ZSDate.date_mode_2,ZSDate.date_time_mode_2,ZSDate.date_mode_3}) public String dateFormat; //日期参数的格式化 @JsonAlias({"mc"}) public boolean isMergeCell; //是否合并单元格 @JsonAlias({"wt"}) public boolean isWrapText; //是否允许在单元格内通过转义字符进行换行操作 @JsonAlias({"lbt"}) public String lineBreakTag; //单元格内换行转义字符 //参数部分 @JsonAlias({"tsn","template"}) public String templateSheetName; //模板sheet名称 @JsonAlias({"nsn","name"}) public String newSheetName; //创建sheet名称 @JsonAlias({"start"}) @JSRuleCheck(required=true) public int dataLine; //数据起始行 @JsonAlias({"p"}) public Map params; //参数集合 @JsonAlias({"da"}) public List
设计这些参数时不一定一下全部设计出来,可以后续不断的在这个类里面增加,这里导出功能我们直接对标阿里的easypoi的导出,目前框架里内置的导出以及easypoi都是通过apache的SXSSFWorkbook对象进行缓存写入的,这也是市面上开源框架中性能最好的一个了,经过实测框架内置导出功能导出10万条数据的性能大概是在2.1-2.6秒之间,阿里的easypoi则比较稳定的在4.588秒左右,因为都采用了SXSSFWorkbook,所以内存上不会有问题
除此之外,框架内置的导出功能还提供了如下功能
- 自定义模板,直接新建一个excel文件,在上面修修改改后做成模板上传到服务器上,如图
导出.jpg
第5行是命令行,它表示每列所对应的表的字段
值得注意的是,在这其中有一个单元格是红色的样式,内置导出功能模板命令行中的每一个单元格的样式都会被继承下来,也就是说E生日这一列的所有数据都会是红色的,导出结果如图导出结果.jpg
通过上面的图我们可以清楚的看到,每一列的样式都与模板命令行中定义的样式相同,空数据用/表示,这一点也是可以配置的,对应sheet对象中的defaultValue属性
除此之外,上面的2020-10-20 10:10:10原本是一个变量信息,这里通过属性params将其替换成了具体的值 - 合并单元格,如果相邻的两条数据某列值相同则自动合并单元格,但由于SXSSFWorkbook是会不断的清空内存,因此如果你要使用这个功能,就需要注意导出的数据不能高于缓存行数,也就是属性cacheRow,否则可能会出现合并单元格异常的问题
- 格式化日期,可以指定日期格式
- 动态创建sheet,这里我们通过json参数来进行说明,如下
{
"rule": {
"name": "export",
"actions": [
{
"name":"test_export",
"export":{
"excel":{
"fileName":"excel导出一下试试",
"absolutePath":"D:/jar/导出模板.xlsx",
"sheets":[
{
"get": {
"classes":["ZsImport"],
"page":{"pageSize":0}
},
"template":"lanliya",
"name":"sheetNameNo.1",
"start":5,
"params":{"asd":"2020-10-20 10:10:10"}
},{
"get": {
"classes":["ZsImport2"],
"page":{"pageSize":0}
},
"name":"sheetNameNo.2",
"start":4,
"params":{"asd":"2020-10-20 10:10:10"}
}
]
}
}
}
]
}
}
我们看到这里写了两个sheet,因此导出来的sheet就有两个,这也是很典型的对象设计
sheet会优先查看datas是否为null,如果为null则通过get对象去查询数据,最终装入datas里,如果数据为空,则依然会导出两个sheet,只是空的那个sheet没有导出任何数据
- fileName:这个属性是定义导出时客户端弹出框里文件默认的名字
- outFilePath:如果你不想通过弹窗的方式手动的指定文件保存的路径,那么这个路径设置以后将会自动写入到本地硬盘中
- template:模板sheet的名字
- name:对应的导出的excel的sheet的名字,新名字
- start:指令行的行号,这里是对应excel的行号
- params:除了数据指令行外,表头上任何一个地方需要替换的变量值的集合,变量使用<>尖括号
- datas:所要导出的数据
- get:对应的是查询对象,在datas为null的时候起作用,datas和get不能同时为null
至此,整个模型便创建完了,接下来就是具体怎么处理这些参数令其拥有相应的功能了,由于我直接在内核里增加的模型,写进了actionModel之中,所以有对应的接口,而如果是自定义模型,则需要继承JSRuleOrdinary模型(除了crud,普通的模型都可以继承这个类),json中的语法应该是如下所示,而不能直接写在action中,必须用o封装起来
{
"rule": {
"name": "export",
"actions": [
{
"name":"test_export",
"o":{
"export":{......}
}
}
]
}
}
而后处理这个规则的处理器需要实现IJSRuleOrdinaryProcessor接口,泛型就写上面继承JSRuleOrdinary的对象模型即可
总结:自定义规则无非也就是包含两块,一个是参数设计,也就是模型对象的设计,这也是json语法的设计,另一个就是对这些参数进行处理的程序逻辑,也就是需要实现IJSRuleOrdinaryProcessor接口处理的类,后续可能会有更好的方式提供给开发者进行自定义规则开发



