解决问题
日常我们数据在需要导出为 Excel xlsx 文件时,实际上大部分需求就是将对应数据按照顺序一行行写入到 xlsx 表格中,具体的实现其实很容易,就是用 xlsx 相关库编码即可。这样的实现路径存在如下问题:
1、大量重复工作
但是如果你有多个数据需要导出为 xlsx 文件,每个数据都要单独写调用 xlsx 单元格写入 api,非常枯燥又效率低下。
2、大量重复代码
导出为 xlsx 文件,除了 xlsx 格式相关的代码外,还有文件保存,保存文件路径检测等各种需要处理。
3、无法聚焦数据差异性
实际导出 excel xlsx 文件时,主要是各种数据的差异性,xlsx 相关的写入是类似的,手工的实现,在考虑数据的差异性时,还得考虑 xlsx 的操作等,无法聚焦。
4、分组输出工作量大
无法自动按照某一数据字段,将数据分组输出到不同的 xlsx 文件,硬编码实现有大量文件初始化和写入逻辑需要处理。
我们干什么
因此,这就有了 Xlsx-Group-Write 的出现了,主要实现如下功能:
1、聚焦数据处理
无需了解 xlsx 的写入 api,只需要聚焦数据如何写入到的哪一列。即可实现自动导出到xlsx,支持分类导出,支持加密导出等,比如有如下数据结构
struct MyDate{
name:String,
tel:String,
dep:String
}
我们只需要维护各字段对应将写入到表格的第几列即可完成 xlsx 导出。示例如下:
use xlsx_group_write::*;
use xlsx_group_write::data::XlsxColValueType;
struct MySimpleData {
pub name: String,
pub tel: String,
pub dep: String,
}
impl MySimpleData {
pub fn new(name: &str, tel: &str, dep: &str) -> Self {
Self {
name: name.into(),
tel: tel.into(),
dep: dep.into(),
}
}
}
impl XlsxGroupWrite for MySimpleData {
const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple;
fn line_writer_simple(&self, index: u32) -> Vec<XlsxColValue> {
vec![
XlsxColValue::new(index - 1, XlsxColValueType::NumberValue),
XlsxColValue::new(&self.name, XlsxColValueType::StringValue),
XlsxColValue::new(&self.tel, XlsxColValueType::StringValue),
XlsxColValue::new(&self.dep, XlsxColValueType::StringValue),
]
}
fn group_make(&self) -> String {
self.dep.clone()
}
fn get_template() -> XlsxInitTemplet {
XlsxInitTemplet::new_header("序号,姓名,手机,部门")
}
const OUTPUT_FILE_NAME_GETTER_SIMPLE: Option<OutputFileNameSimpleGetter> =
Some(OutputFileNameSimpleGetter::new(
"/tmp/test",
));
}
#[test]
fn test_simple_temp() {
let data = vec![
MySimpleData::new("张三", "185xxxx2228", "网金部"),
MySimpleData::new("李四", "185xxxx2229", "运管部"),
MySimpleData::new("王二", "185xxxx2230", "网金部"),
];
let resp = MySimpleData::write2xlsx_all(
&data
);
println!("{resp:#?}");
}
2、支持从某个xlsx文件模板生成导出数据
我们可以自己先编辑好一个excel表格的样式,设置好标题、表头、字体等,然后以此模板生成导出数据,例如:
use xlsx_group_write::*;
use xlsx_group_write::data::XlsxColValueType;
struct MyData {
pub name: String,
pub tel: String,
pub dep: String,
}
impl MyData {
pub fn new(name: &str, tel: &str, dep: &str) -> Self {
Self {
name: name.into(),
tel: tel.into(),
dep: dep.into(),
}
}
}
impl XlsxGroupWrite for MyData {
const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Simple;
fn line_writer_simple(&self, index: u32) -> Vec<XlsxColValue> {
vec![
XlsxColValue::new(index - 3, XlsxColValueType::NumberValue),
XlsxColValue::new(&self.name, XlsxColValueType::StringValue),
XlsxColValue::new(&self.tel, XlsxColValueType::StringValue),
XlsxColValue::new(&self.dep, XlsxColValueType::StringValue),
]
}
fn group_make(&self) -> String {
self.dep.clone()
}
fn get_template() -> XlsxInitTemplet {
XlsxInitTemplet::new_advance("/home/feiy/Desktop/temp.xlsx", 4)
}
fn add_custom_info_to_sheet(sheet: &mut Worksheet, group_id: &str) {
sheet
.get_cell_mut((&1, &2))
.set_value_string(&format!("{group_id},报表日期:2023年4月20日"));
}
const OUTPUT_FILE_NAME_GETTER_SIMPLE: Option<OutputFileNameSimpleGetter> =
Some(OutputFileNameSimpleGetter::new(
"/tmp/test",
));
}
#[test]
fn test_custom_info() {
let data = vec![
MyData::new("张三", "185xxxx2228", "网金部"),
MyData::new("李四", "185xxxx2229", "运管部"),
MyData::new("王二", "185xxxx2230", "网金部"),
];
let resp = MyData::write2xlsx_group_only(
&data,
);
println!("{resp:#?}");
}
3、灵活的自动分组导出和汇总导出数据
- write2xlsx_group_only
- 只导出分组数据
- 按照分组id,将不同数据导出到不同的xlsx文件中
- write2xlsx_merge_only
- write2xlsx_all
4、可实现完全个性化自行控制的行数据写入
如果您的数据并不是一个字段写入一列的,需要合并写入,或者需要自定义单元格样式,可以如下使用:
use xlsx_group_write::*;
use xlsx_group_write::data::XlsxColValueType;
struct MyData3 {
pub name: String,
pub tel: String,
pub dep: String,
}
impl MyData3 {
pub fn new(name: &str, tel: &str, dep: &str) -> Self {
Self {
name: name.into(),
tel: tel.into(),
dep: dep.into(),
}
}
}
impl XlsxGroupWrite for MyData3 {
const LINE_WRITER_MODEL: XlsxLineWriterModel = XlsxLineWriterModel::Advance;
fn line_writer_advance(
&self,
sheet: &mut Worksheet,
index: u32,
) -> Option<XlsxLineAdvanceWriterResult> {
xlsx_util::XlsxWriterTool::set_excel_cell_value_number(sheet, 1, index, index - 2);
xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 2, index, &self.name);
xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 3, index, &self.tel);
xlsx_util::XlsxWriterTool::set_excel_cell_value_str(sheet, 4, index, &self.dep);
None
}
fn get_template() -> XlsxInitTemplet {
XlsxInitTemplet::new_advance("/home/feiy/Desktop/temp.xlsx", 4)
}
fn get_output_file_name_advance(groupt_id: &str) -> String {
format!("/tmp/advance-{groupt_id}.xlsx")
}
fn add_custom_info_to_sheet(sheet: &mut Worksheet, group_id: &str) {
sheet
.get_cell_mut((&1, &2))
.set_value_string(&format!("{group_id},报表日期:2023年4月20日"));
}
}
#[test]
fn test_advance_write() {
let data = vec![
MyData3::new("张三", "185xxxx2228", "网金部"),
MyData3::new("李四", "185xxxx2229", "运管部"),
MyData3::new("王二", "185xxxx2230", "网金部"),
];
let resp = MyData3::write2xlsx_merge_only(
&data
);
println!("{resp:#?}");
}
个性化特性
- date 自动在文件名称中加入导出日期
- encrypt 支持xlsx文件加密,添加该特性后,向接口会增加密码参数
用法
- 添加依赖
[dependencies.xlsx_group_write]
version = "1"
# 根据需要添加对应特性
feature = ["date","encrypt"]
-
定义里的导出数据结构,并实现XlsxGroupWrite,并根据需要使用不同的方法和属性
-
调用不同的write2xlsx_方法导出数据到xlsx文件。