diff --git a/dao/pom.xml b/dao/pom.xml
index a142267..4b9e9aa 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -44,5 +44,10 @@
swagger-annotations
1.6.14
+
+
+ com.alibaba
+ easyexcel
+
diff --git a/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillDto.java b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillDto.java
index 6234230..43ca3ee 100644
--- a/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillDto.java
+++ b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillDto.java
@@ -37,4 +37,5 @@ public class BillDto {
@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd")
private LocalDate endDate;
-}
\ No newline at end of file
+}
+
diff --git a/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillExportDto.java b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillExportDto.java
new file mode 100644
index 0000000..27fafe7
--- /dev/null
+++ b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/BillExportDto.java
@@ -0,0 +1,33 @@
+package cn.bunny.dao.dto.financial.bill;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Schema(name = "BillExportDto对象", title = "导出账单信息", description = "导出账单信息")
+public class BillExportDto {
+
+ @Schema(name = "userId", title = "绑定的用户id")
+ private Long userId;
+
+ @Schema(name = "startDate", title = "开始交易日期")
+ @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd")
+ @NotNull(message = "开始日期不能为空")
+ private LocalDate startDate;
+
+ @Schema(name = "endDate", title = "结束交易日期")
+ @JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd")
+ @NotNull(message = "结束日期不能为空")
+ private LocalDate endDate;
+
+}
\ No newline at end of file
diff --git a/dao/src/main/java/cn/bunny/dao/dto/financial/bill/user/BillAddUserDto.java b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/user/BillAddUserDto.java
index f289df7..fd191bd 100644
--- a/dao/src/main/java/cn/bunny/dao/dto/financial/bill/user/BillAddUserDto.java
+++ b/dao/src/main/java/cn/bunny/dao/dto/financial/bill/user/BillAddUserDto.java
@@ -1,5 +1,6 @@
package cn.bunny.dao.dto.financial.bill.user;
+import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Max;
@@ -24,23 +25,28 @@ public class BillAddUserDto {
@NotNull(message = "类型不能为空")
@Min(value = -1, message = "类型格式不正确")
@Max(value = 1, message = "类型格式不正确")
+ @ExcelProperty(index = 0)
private Byte type;
@Schema(name = "amount", title = "金额")
@NotNull(message = "金额不能为空")
@Min(value = 0, message = "金额格式不正确")
+ @ExcelProperty("金额")
private BigDecimal amount;
@Schema(name = "description", title = "描述")
+ @ExcelProperty("描述")
private String description;
@Schema(name = "transactionDate", title = "交易日期")
@NotNull(message = "交易日期不能为空")
@JsonFormat(locale = "zh", timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @ExcelProperty("交易日期")
private LocalDateTime transactionDate;
@Schema(name = "categoryId", title = "类别id")
@NotNull(message = "类别id不能为空")
+ @ExcelProperty("类别id")
private Long categoryId;
}
\ No newline at end of file
diff --git a/dao/src/main/java/cn/bunny/dao/excel/BillUserExportExcel.java b/dao/src/main/java/cn/bunny/dao/excel/BillUserExportExcel.java
new file mode 100644
index 0000000..1c9d87e
--- /dev/null
+++ b/dao/src/main/java/cn/bunny/dao/excel/BillUserExportExcel.java
@@ -0,0 +1,47 @@
+package cn.bunny.dao.excel;
+
+import cn.bunny.dao.common.vo.BaseVo;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+@Schema(name = "BillUserVo对象", title = "用户账单信息返回内容", description = "用户账单信息返回内容")
+public class BillUserExportExcel extends BaseVo {
+
+ @Schema(name = "username", title = "类型:1 - 收入,-1 - 支出")
+ @ExcelProperty("类型:1 - 收入,-1 - 支出")
+ private String type;
+
+ @Schema(name = "amount", title = "金额")
+ @ExcelProperty("金额")
+ private BigDecimal amount;
+
+ @Schema(name = "description", title = "描述")
+ @ExcelProperty("描述")
+ private String description;
+
+ @Schema(name = "transactionDate", title = "交易日期")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JsonSerialize(using = LocalDateTimeSerializer.class)
+ @JsonDeserialize(using = LocalDateTimeDeserializer.class)
+ @ExcelProperty("交易日期")
+ private LocalDateTime transactionDate;
+
+ @Schema(name = "categoryName", title = "类别分类")
+ @ExcelProperty("类别分类")
+ private String categoryName;
+
+}
\ No newline at end of file
diff --git a/dao/src/main/java/cn/bunny/dao/vo/financial/user/BillUserVo.java b/dao/src/main/java/cn/bunny/dao/vo/financial/user/BillUserVo.java
index 086c0f4..b95c516 100644
--- a/dao/src/main/java/cn/bunny/dao/vo/financial/user/BillUserVo.java
+++ b/dao/src/main/java/cn/bunny/dao/vo/financial/user/BillUserVo.java
@@ -1,6 +1,7 @@
package cn.bunny.dao.vo.financial.user;
import cn.bunny.dao.common.vo.BaseVo;
+import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -23,18 +24,22 @@ import java.time.LocalDateTime;
public class BillUserVo extends BaseVo {
@Schema(name = "username", title = "类型:1 - 收入,-1 - 支出")
+ @ExcelProperty(index = 0)
private Byte type;
@Schema(name = "amount", title = "金额")
+ @ExcelProperty("金额")
private BigDecimal amount;
@Schema(name = "description", title = "描述")
+ @ExcelProperty("描述")
private String description;
@Schema(name = "transactionDate", title = "交易日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
+ @ExcelProperty("交易日期")
private LocalDateTime transactionDate;
@Schema(name = "categoryId", title = "分类Id")
@@ -43,6 +48,7 @@ public class BillUserVo extends BaseVo {
private String categoryId;
@Schema(name = "categoryName", title = "类别分类")
+ @ExcelProperty("类别分类")
private String categoryName;
}
diff --git a/pom.xml b/pom.xml
index 5917148..2122b39 100644
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,7 @@
2.2
3.1
5.1.0
+ 4.0.2
4.3.1
2.12.3
2.3.2
@@ -151,6 +152,12 @@
quartz
${quartz-scheduler.version}
+
+
+ com.alibaba
+ easyexcel
+ ${easyexcel.version}
+
diff --git a/service/pom.xml b/service/pom.xml
index c32eb8d..2e3bc49 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -84,12 +84,6 @@
spring-context-support
6.1.6
-
-
- com.alibaba
- easyexcel
- 4.0.2
-
diff --git a/service/src/main/java/cn/bunny/services/controller/financial/BillController.java b/service/src/main/java/cn/bunny/services/controller/financial/BillController.java
index bda3e6c..f83e2b5 100644
--- a/service/src/main/java/cn/bunny/services/controller/financial/BillController.java
+++ b/service/src/main/java/cn/bunny/services/controller/financial/BillController.java
@@ -1,6 +1,7 @@
package cn.bunny.services.controller.financial;
import cn.bunny.dao.dto.financial.bill.BillDto;
+import cn.bunny.dao.dto.financial.bill.BillExportDto;
import cn.bunny.dao.dto.financial.bill.ExpendWithIncomeDto;
import cn.bunny.dao.dto.financial.bill.admin.BillAddDto;
import cn.bunny.dao.dto.financial.bill.admin.BillUpdateDto;
@@ -18,6 +19,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -67,13 +69,25 @@ public class BillController {
return Mono.just(Result.success(pageResult));
}
- @Operation(summary = "账单收入和支出", description = "账单收入和支出")
+ @Operation(summary = "账单收入和支出图表展示", description = "账单收入和支出图表展示")
@GetMapping("noManage/getExpendOrIncome")
public Mono> getExpendOrIncome(ExpendWithIncomeDto dto) {
ExpendWithIncomeListVo vo = billService.getExpendOrIncome(dto);
return Mono.just(Result.success(vo));
}
+ @Operation(summary = "导出用户账单信息", description = "导出用户账单信息")
+ @PostMapping("noManage/exportBill")
+ public void exportBill(@Valid @RequestBody BillExportDto dto, HttpServletResponse response) {
+ billService.exportBill(dto, response);
+ }
+
+ @Operation(summary = "管理员导出账单信息", description = "管理员导出账单信息")
+ @PostMapping("exportBillByAdmin")
+ public void exportBillByAdmin(@Valid @RequestBody BillExportDto dto, HttpServletResponse response) {
+ billService.exportBillByAdmin(dto, response);
+ }
+
@Operation(summary = "添加账单信息", description = "添加账单信息")
@PostMapping("addBill")
public Mono> addBill(@Valid @RequestBody BillAddDto dto) {
diff --git a/service/src/main/java/cn/bunny/services/excel/BillAddUserDAO.java b/service/src/main/java/cn/bunny/services/excel/BillAddUserDAO.java
new file mode 100644
index 0000000..fe99a69
--- /dev/null
+++ b/service/src/main/java/cn/bunny/services/excel/BillAddUserDAO.java
@@ -0,0 +1,11 @@
+package cn.bunny.services.excel;
+
+import cn.bunny.dao.dto.financial.bill.user.BillAddUserDto;
+
+import java.util.List;
+
+public class BillAddUserDAO {
+ public void save(List list) {
+ // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
+ }
+}
\ No newline at end of file
diff --git a/service/src/main/java/cn/bunny/services/excel/BillAddUserListener.java b/service/src/main/java/cn/bunny/services/excel/BillAddUserListener.java
new file mode 100644
index 0000000..5a6e64d
--- /dev/null
+++ b/service/src/main/java/cn/bunny/services/excel/BillAddUserListener.java
@@ -0,0 +1,60 @@
+package cn.bunny.services.excel;
+
+import cn.bunny.dao.dto.financial.bill.user.BillAddUserDto;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.read.listener.ReadListener;
+import com.alibaba.excel.util.ListUtils;
+import com.alibaba.fastjson2.JSON;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+@Slf4j
+public class BillAddUserListener implements ReadListener {
+
+ private static final int BATCH_COUNT = 100;
+ private final BillAddUserDAO billAddUserDAO;
+ private List cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
+
+ public BillAddUserListener() {
+ billAddUserDAO = new BillAddUserDAO();
+ }
+
+ public BillAddUserListener(BillAddUserDAO billAddUserDAO) {
+ this.billAddUserDAO = billAddUserDAO;
+ }
+
+ /**
+ * 这个每一条数据解析都会来调用
+ *
+ * @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
+ */
+ @Override
+ public void invoke(BillAddUserDto data, AnalysisContext context) {
+ log.info("解析到一条数据:{}", JSON.toJSONString(data));
+ cachedDataList.add(data);
+ // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
+ if (cachedDataList.size() >= BATCH_COUNT) {
+ saveData();
+ // 存储完成清理 list
+ cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
+ }
+ }
+
+ /**
+ * 所有数据解析完成了 都会来调用
+ */
+ @Override
+ public void doAfterAllAnalysed(AnalysisContext context) {
+ saveData();
+ }
+
+ /**
+ * 加上存储数据库
+ */
+ private void saveData() {
+ log.info("{}条数据,开始存储数据库!", cachedDataList.size());
+ billAddUserDAO.save(cachedDataList);
+ log.info("存储数据库成功!");
+ }
+}
diff --git a/service/src/main/java/cn/bunny/services/factory/BillFactory.java b/service/src/main/java/cn/bunny/services/factory/BillFactory.java
new file mode 100644
index 0000000..7f9a0b4
--- /dev/null
+++ b/service/src/main/java/cn/bunny/services/factory/BillFactory.java
@@ -0,0 +1,97 @@
+package cn.bunny.services.factory;
+
+import cn.bunny.common.service.exception.BunnyException;
+import cn.bunny.dao.dto.financial.bill.BillExportDto;
+import cn.bunny.dao.dto.financial.bill.ExpendWithIncomeDto;
+import cn.bunny.dao.excel.BillUserExportExcel;
+import cn.bunny.dao.pojo.result.ResultCodeEnum;
+import cn.bunny.dao.vo.financial.user.expendAndIncome.ExpendWithIncome;
+import cn.bunny.services.mapper.financial.BillMapper;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+@Component
+public class BillFactory {
+
+ @Autowired
+ private BillMapper billMapper;
+
+ public void exportBill(BillExportDto dto, HttpServletResponse response) {
+ LocalDate startDate = dto.getStartDate();
+ LocalDate endDate = dto.getEndDate();
+
+ // 设置日期范围
+ String dateRange = startDate + "~" + endDate;
+
+ // 导出后的文件名
+ String filename = URLEncoder.encode(dateRange, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
+
+ // 初始化查询条件,将日期向后移一天查询包含当前的数据
+ ExpendWithIncomeDto expendWithIncomeDto = new ExpendWithIncomeDto();
+ BeanUtils.copyProperties(dto, expendWithIncomeDto);
+ expendWithIncomeDto.setEndDate(endDate.plusDays(1));
+
+ // 设置收入和支出的值
+ AtomicReference income = new AtomicReference<>(new BigDecimal(0));
+ AtomicReference expend = new AtomicReference<>(new BigDecimal(0));
+
+ // 查询数据
+ List expendWithIncomeList = billMapper.selectListByExpendWithIncomeDto(expendWithIncomeDto);
+ List excelList = expendWithIncomeList.stream().map(expendWithIncome -> {
+ BillUserExportExcel billUserExportExcel = new BillUserExportExcel();
+ BeanUtils.copyProperties(expendWithIncome, billUserExportExcel);
+
+ // 设置收支类型
+ String type;
+ if (expendWithIncome.getType().equals(Byte.parseByte("1"))) {
+ type = "收入";
+ income.updateAndGet(amount -> amount.add(expendWithIncome.getAmount()));
+ } else {
+ type = "支出";
+ expend.updateAndGet(bigDecimal -> bigDecimal.add(expendWithIncome.getAmount()));
+ }
+ billUserExportExcel.setType(type);
+
+ return billUserExportExcel;
+ }).toList();
+
+ // 查找模板文件
+ String filenameTemplate = Objects.requireNonNull(getClass().getResource("/static/bill-template.xlsx")).getFile();
+ if (filenameTemplate == null) throw new BunnyException(ResultCodeEnum.MISSING_TEMPLATE_FILES);
+
+ try (ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(filenameTemplate).build()) {
+ // 填充数据
+ WriteSheet writeSheet = EasyExcel.writerSheet().build();
+ excelWriter.fill(excelList, writeSheet);
+
+ // 写入模板数据
+ Map map = new HashMap<>();
+ map.put("dateRange", dateRange);
+ map.put("income", income.get());
+ map.put("expend", expend.get());
+ map.put("profit", income.get().subtract(expend.get()));
+ excelWriter.fill(map, writeSheet);
+
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+ response.setCharacterEncoding("utf-8");
+ response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + filename + ".xlsx");
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/service/src/main/java/cn/bunny/services/service/financial/BillService.java b/service/src/main/java/cn/bunny/services/service/financial/BillService.java
index 3af1a81..2758c89 100644
--- a/service/src/main/java/cn/bunny/services/service/financial/BillService.java
+++ b/service/src/main/java/cn/bunny/services/service/financial/BillService.java
@@ -1,6 +1,7 @@
package cn.bunny.services.service.financial;
import cn.bunny.dao.dto.financial.bill.BillDto;
+import cn.bunny.dao.dto.financial.bill.BillExportDto;
import cn.bunny.dao.dto.financial.bill.ExpendWithIncomeDto;
import cn.bunny.dao.dto.financial.bill.admin.BillAddDto;
import cn.bunny.dao.dto.financial.bill.admin.BillUpdateDto;
@@ -13,6 +14,7 @@ import cn.bunny.dao.vo.financial.user.BillUserVo;
import cn.bunny.dao.vo.financial.user.expendAndIncome.ExpendWithIncomeListVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
+import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@@ -89,4 +91,20 @@ public interface BillService extends IService {
* @return 账单收入和支出
*/
ExpendWithIncomeListVo getExpendOrIncome(ExpendWithIncomeDto dto);
+
+ /**
+ * 导出用户账单
+ *
+ * @param dto 日期选择
+ * @param response 响应体
+ */
+ void exportBill(BillExportDto dto, HttpServletResponse response);
+
+ /**
+ * 管理员导出账单信息
+ *
+ * @param dto 日期选择
+ * @param response 响应体
+ */
+ void exportBillByAdmin(BillExportDto dto, HttpServletResponse response);
}
diff --git a/service/src/main/java/cn/bunny/services/service/financial/impl/BillServiceImpl.java b/service/src/main/java/cn/bunny/services/service/financial/impl/BillServiceImpl.java
index a38b93d..47782fd 100644
--- a/service/src/main/java/cn/bunny/services/service/financial/impl/BillServiceImpl.java
+++ b/service/src/main/java/cn/bunny/services/service/financial/impl/BillServiceImpl.java
@@ -3,6 +3,7 @@ package cn.bunny.services.service.financial.impl;
import cn.bunny.common.service.context.BaseContext;
import cn.bunny.common.service.exception.BunnyException;
import cn.bunny.dao.dto.financial.bill.BillDto;
+import cn.bunny.dao.dto.financial.bill.BillExportDto;
import cn.bunny.dao.dto.financial.bill.ExpendWithIncomeDto;
import cn.bunny.dao.dto.financial.bill.admin.BillAddDto;
import cn.bunny.dao.dto.financial.bill.admin.BillUpdateDto;
@@ -16,6 +17,7 @@ import cn.bunny.dao.vo.financial.user.BillUserVo;
import cn.bunny.dao.vo.financial.user.expendAndIncome.CategoryAmount;
import cn.bunny.dao.vo.financial.user.expendAndIncome.ExpendWithIncome;
import cn.bunny.dao.vo.financial.user.expendAndIncome.ExpendWithIncomeListVo;
+import cn.bunny.services.factory.BillFactory;
import cn.bunny.services.factory.HomeFactory;
import cn.bunny.services.mapper.financial.BillMapper;
import cn.bunny.services.service.financial.BillService;
@@ -23,6 +25,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -44,6 +47,8 @@ public class BillServiceImpl extends ServiceImpl implements Bi
@Autowired
private HomeFactory homeFactory;
+ @Autowired
+ private BillFactory billFactory;
/**
* * 账单信息 服务实现类
@@ -208,6 +213,30 @@ public class BillServiceImpl extends ServiceImpl implements Bi
.build();
}
+ /**
+ * 导出用户账单
+ *
+ * @param dto 日期选择
+ * @param response 返回响应
+ */
+ @Override
+ public void exportBill(BillExportDto dto, HttpServletResponse response) {
+ dto.setUserId(BaseContext.getUserId());
+ billFactory.exportBill(dto, response);
+ }
+
+
+ /**
+ * 管理员导出账单信息
+ *
+ * @param dto 日期选择
+ * @param response 响应体
+ */
+ @Override
+ public void exportBillByAdmin(BillExportDto dto, HttpServletResponse response) {
+ billFactory.exportBill(dto, response);
+ }
+
/**
* 删除|批量删除账单信息
*
diff --git a/service/src/main/resources/mapper/financial/BillMapper.xml b/service/src/main/resources/mapper/financial/BillMapper.xml
index b46f03f..05d1fea 100644
--- a/service/src/main/resources/mapper/financial/BillMapper.xml
+++ b/service/src/main/resources/mapper/financial/BillMapper.xml
@@ -62,7 +62,7 @@
select *
from t_bill b left join t_category tc on b.category_id = tc.id
-
+
and b.user_id = #{dto.userId}
diff --git a/service/src/main/resources/static/bill-template.xlsx b/service/src/main/resources/static/bill-template.xlsx
new file mode 100644
index 0000000..d35b08c
Binary files /dev/null and b/service/src/main/resources/static/bill-template.xlsx differ
diff --git a/service/src/test/java/cn/bunny/services/service/financial/impl/BillServiceImplTest.java b/service/src/test/java/cn/bunny/services/service/financial/impl/BillServiceImplTest.java
new file mode 100644
index 0000000..4eba565
--- /dev/null
+++ b/service/src/test/java/cn/bunny/services/service/financial/impl/BillServiceImplTest.java
@@ -0,0 +1,84 @@
+package cn.bunny.services.service.financial.impl;
+
+import cn.bunny.common.service.exception.BunnyException;
+import cn.bunny.dao.dto.financial.bill.ExpendWithIncomeDto;
+import cn.bunny.dao.excel.BillUserExportExcel;
+import cn.bunny.dao.pojo.result.ResultCodeEnum;
+import cn.bunny.dao.vo.financial.user.expendAndIncome.ExpendWithIncome;
+import cn.bunny.services.mapper.financial.BillMapper;
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.ExcelWriter;
+import com.alibaba.excel.write.metadata.WriteSheet;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+
+@SpringBootTest
+class BillServiceImplTest {
+ @Autowired
+ private BillMapper billMapper;
+
+ @Test
+ void exportBill() {
+ // 设置数据库查询时间
+ ExpendWithIncomeDto expendWithIncomeDto = new ExpendWithIncomeDto();
+ expendWithIncomeDto.setUserId(1849444494908125181L);
+ expendWithIncomeDto.setStartDate(LocalDate.of(2024, 11, 1));
+ expendWithIncomeDto.setEndDate(LocalDate.of(2024, 11, 30));
+
+ // 设置日期范围
+ String dateRange = expendWithIncomeDto.getStartDate() + "~" + expendWithIncomeDto.getEndDate();
+
+ // 设置收入和支出的值
+ AtomicReference income = new AtomicReference<>(new BigDecimal(0));
+ AtomicReference expend = new AtomicReference<>(new BigDecimal(0));
+
+ // 查询数据
+ List expendWithIncomeList = billMapper.selectListByExpendWithIncomeDto(expendWithIncomeDto);
+ List excelList = expendWithIncomeList.stream().map(expendWithIncome -> {
+ BillUserExportExcel billUserExportExcel = new BillUserExportExcel();
+ BeanUtils.copyProperties(expendWithIncome, billUserExportExcel);
+
+ // 设置收支类型
+ String type;
+ if (expendWithIncome.getType().equals(Byte.parseByte("1"))) {
+ type = "收入";
+ income.updateAndGet(amount -> amount.add(expendWithIncome.getAmount()));
+ } else {
+ type = "支出";
+ expend.updateAndGet(bigDecimal -> bigDecimal.add(expendWithIncome.getAmount()));
+ }
+ billUserExportExcel.setType(type);
+
+ return billUserExportExcel;
+ }).toList();
+
+ String filenameTemplate = Objects.requireNonNull(getClass().getResource("/static/bill-template.xlsx")).getFile();
+ if (filenameTemplate == null) throw new BunnyException(ResultCodeEnum.MISSING_TEMPLATE_FILES);
+
+ try (ExcelWriter excelWriter = EasyExcel.write("F:\\数据库备份\\" + dateRange + ".xlsx").withTemplate(filenameTemplate).build()) {
+ // 填充数据
+ WriteSheet writeSheet = EasyExcel.writerSheet().build();
+ excelWriter.fill(excelList, writeSheet);
+
+ // 写入模板数据
+ Map map = new HashMap<>();
+ map.put("dateRange", dateRange);
+ map.put("income", income.get());
+ map.put("expend", expend.get());
+ map.put("profit", income.get().subtract(expend.get()));
+ excelWriter.fill(map, writeSheet);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/service/src/test/java/excel/fill/FillTest.java b/service/src/test/java/excel/fill/FillTest.java
new file mode 100644
index 0000000..d3aab4b
--- /dev/null
+++ b/service/src/test/java/excel/fill/FillTest.java
@@ -0,0 +1,30 @@
+package excel.fill;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class FillTest {
+
+ @Test
+ void fillTest1() {
+ // // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替
+ // String filenameTemplate = "F:\\数据库备份\\bill-template.xlsx";
+ //
+ // // 设置数据库查询时间
+ // BillExportDto billExportDto = new BillExportDto();
+ // billExportDto.setUserId(1849444494908125181L);
+ // billExportDto.setStartDate(LocalDate.of(2024, 11, 1));
+ // billExportDto.setEndDate(LocalDate.of(2024, 11, 30));
+ //
+ // EasyExcel.write("F:\\数据库备份\\" + billExportDto.getStartDate() + "~" + billExportDto.getEndDate() + ".xlsx").withTemplate(filenameTemplate).sheet().doFill(fillData);
+
+ // // 方案2 根据Map填充
+ // fileName = TestFileUtil.getPath() + "simpleFill" + System.currentTimeMillis() + ".xlsx";
+ // // 这里 会填充到第一个sheet, 然后文件流会自动关闭
+ // Map map = MapUtils.newHashMap();
+ // map.put("name", "张三");
+ // map.put("number", 5.2);
+ // EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map);
+ }
+}