【SpringBoot整合系列】SpirngBoot整合EasyExcel

目录

  • 背景
    • 需求
    • 发展
  • EasyExcel
    • 官网
    • 介绍
    • 优势
    • 常用注解
  • SpringBoot整合EaxyExcel
    • 1.引入依赖
    • 2.实体类定义
      • 实体类代码示例
      • 注解解释
    • 3.自定义转换器
      • 转换器代码示例
      • 涉及的枚举类型
    • 4.Excel工具类
    • 5.简单导出
      • 接口
      • SQL
    • 6.简单导入
      • 接口
      • SQL
    • 7.复杂的导出(合并行、合并列)
      • 解决思路
      • 自定义注解
      • 定义实体类
      • SQL
      • 自定义单元格合并策略
      • 接口

背景

需求

在当今信息化社会,数据的导入和导出在各种业务场景中变得越来越重要。

发展

  • 我们知道Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
  • easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。
  • 为了满足复杂的导入导出需求,结合Java编程语言、Spring Boot框架以及EasyExcel库,我们可以轻松地构建出强大而灵活的数据处理系统。
  • 当涉及到在Spring Boot 中使用 EasyExcel 实现复杂的导入导出案例时,我们可以结合 Spring Boot 的特性来实现更灵活和集成化的解决方案。

EasyExcel

官网

https://easyexcel.opensource.alibaba.com/
在这里插入图片描述

介绍

EasyExcel 是一款基于 Java 的开源库,专门用于处理 Excel 文件的导入和导出操作。它提供了简单易用的 API,使开发人员能够轻松地实现 Excel 数据的读取和写入,同时还支持大数据量的处理,具有较高的性能和灵活性。

优势

EasyExcel 可以在数据迁移、报表生成、数据分析等多个领域发挥作用,尤其适用于需要频繁处理 Excel 数据的场景。无论是个人开发者还是企业开发团队,都可以通过 EasyExcel 更轻松地实现数据导入导出功能,提高开发效率和用户体验。

  1. 简单易用: EasyExcel 提供了简洁的 API 接口,让开发人员能够快速上手。无论是初学者还是有经验的开发者,都能轻松地实现 Excel 文件的导入导出功能。
  2. 支持多种数据格式: EasyExcel 支持导入导出多种数据格式,包括基本的文本、数字、日期等,以及复杂的对象、集合、嵌套结构等数据类型。
  3. 高性能: EasyExcel 在处理大数据量时表现出色,采用了基于流的方式,有效地降低了内存消耗,提升了性能和效率。
  4. 自定义样式: 开发人员可以灵活地自定义单元格样式,包括字体、颜色、对齐方式等,使导出的 Excel 数据更加美观和易读。
  5. 数据转换: EasyExcel 支持自定义数据转换器,可以将原始数据转换为目标格式,满足业务需求。
  6. 异常处理: EasyExcel 提供了丰富的异常处理机制,能够捕获和处理导入导出过程中的异常情况,保障数据的完整性和一致性。
  7. 多平台支持: EasyExcel 可以在各种 Java 开发环境中使用,包括传统的 Java 应用程序、Web 应用程序,甚至是移动应用开发中。
  8. 开源社区: EasyExcel 是一个开源项目,拥有活跃的社区支持,开发人员可以从社区中获取帮助、贡献代码以及分享经验

常用注解

注解作用
@ExcelProperty用于标识Excel中的字段,可以指定字段在Excel中的列索引或列名。例如:@ExcelProperty(“姓名”),@ExcelProperty(index = 0)。
@ExcelIgnore用于标识不需要导入或导出的字段。
@ExcelIgnoreUnannotated用于标识未被 @ExcelProperty 注解标识的字段是否被忽略。
@ColumnWidth用于设置 Excel 列的宽度。

这些注解可以根据实际需求进行组合使用,以便在 Excel 读写过程中更灵活地控制字段的行为和样式。

SpringBoot整合EaxyExcel

1.引入依赖

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.3</version></dependency>

2.实体类定义

使用@ExcelProperty 注解标记需要在 Excel 中读写的字段,可以指定字段在 Excel 中的列索引或列名。

实体类代码示例

package com.zjl.model;import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.zjl.coverter.BillIsPaymentConverter;
import lombok.Data;/*** @author: zjl* @datetime: 2024/3/29* @desc: 订单实体类*/
@Data
public class BillDO {@ExcelIgnoreprivate Long id;@ExcelProperty(index = 0, value = "订单编码")   // 列索引为1@ColumnWidth(15)private String billCode;//订单编码@ExcelProperty(index = 1,value = "商品名称")   // 列索引为2@ColumnWidth(30)private String productName;//商品名称@ExcelProperty(index = 2,value = "商品描述")   // 列索引为3@ColumnWidth(30)private String productDesc;//商品描述@ExcelProperty(index = 3,value = "商品单位")   // 列索引为4@ColumnWidth(15)private String productUnit;//商品单位@ExcelProperty(index = 4,value = "商品数量")   // 列索引为5@ColumnWidth(15)private String productCount;//商品数量@ExcelProperty(index = 5,value = "商品总金额")   // 列索引为6@ColumnWidth(15)private String totalPrice;//商品总金额@ExcelProperty(index = 6,value = "支付状态",converter = BillIsPaymentConverter.class)   // 列索引为7@ColumnWidth(15)private int isPayment;//支付状态:是否支付(1:未支付 2:已支付)@ExcelProperty(index = 7,value = "创建人")   // 列索引为8@ColumnWidth(15)private String createdBy;//创建人@ExcelProperty(index = 8,value = "创建时间")   // 列索引为9@ColumnWidth(25)@DateTimeFormat("yyyy-MM-dd")private String creationDate;//创建时间@ExcelProperty(index = 9,value = "供应商名称")   // 列索引为10@ColumnWidth(30)private String providerName;//供应商名称
}
package com.zjl.model;import com.alibaba.excel.annotation.ExcelProperty;
import com.zjl.coverter.BillIsPaymentConverter;
import lombok.Data;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Data
public class BillImportBO {@ExcelProperty(index = 0, value = "订单编码")   // 列索引为1private String billCode;//订单编码@ExcelProperty(index = 1,value = "商品名称")   // 列索引为2private String productName;//商品名称@ExcelProperty(index = 2,value = "商品描述")   // 列索引为3private String productDesc;//商品描述@ExcelProperty(index = 3,value = "商品单位")   // 列索引为4private String productUnit;//商品单位@ExcelProperty(index = 4,value = "商品数量")   // 列索引为5private String productCount;//商品数量@ExcelProperty(index = 5,value = "商品总金额")   // 列索引为6private String totalPrice;//商品总金额@ExcelProperty(index = 6,value = "支付状态",converter = BillIsPaymentConverter.class)   // 列索引为7private int isPayment;//支付状态:是否支付(1:未支付 2:已支付)private String creationDate;//创建时间@ExcelProperty(index = 7,value = "供应商ID")   // 列索引为10private String providerId;//供应商名称
}

注解解释

  • @ExcelProperty:核心注解,value属性可用来设置表头名称,converter属性可以用来设置类型转换器;
  • @ColumnWidth:用于设置表格列的宽度;
  • @DateTimeFormat:用于设置日期转换格式;
  • @NumberFormat:用于设置数字转换格式。

3.自定义转换器

在EasyExcel中,如果想实现枚举类型到字符串类型转换(例如isPayment属性:1 -> 未支付,2 -> 已支付),需实现Converter接口来自定义转换器,下面为自定义BillIsPaymentConverter支付状态转换器代码实现:

转换器代码示例

package com.zjl.coverter;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.converters.ReadConverterContext;
import com.alibaba.excel.converters.WriteConverterContext;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.zjl.enums.IsPaymentEnum;/*** @author: zjl* @datetime: 2024/3/29* @desc:*/
public class BillIsPaymentConverter implements Converter<Integer> {@Overridepublic Class<?> supportJavaTypeKey() {return Integer.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic Integer convertToJavaData(ReadConverterContext<?> context) {return IsPaymentEnum.convert(context.getReadCellData().getStringValue()).getValue();}@Overridepublic WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) {return new WriteCellData<>(IsPaymentEnum.convert(context.getValue()).getDescription());}
}

涉及的枚举类型

package com.zjl.enums;import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;import java.util.stream.Stream;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Getter
@AllArgsConstructor
public enum IsPaymentEnum {UNKNOWN(0,"其他"),ISNOTPAY(1, "未支付"),ISPAY(2, "已支付");private final Integer value;@JsonFormatprivate final String description;public static IsPaymentEnum convert(Integer value) {return Stream.of(values()).filter(bean -> bean.value.equals(value)).findAny().orElse(UNKNOWN);}public static IsPaymentEnum convert(String description) {return Stream.of(values()).filter(bean -> bean.description.equals(description)).findAny().orElse(UNKNOWN);}
}

4.Excel工具类

设置相应结果

package com.zjl.utils;import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
public class ExcelUtil {/*** 设置响应结果*/public static void setExcelResponseProp(HttpServletResponse response, String rawFileName) throws UnsupportedEncodingException {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode(rawFileName, "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");}}

5.简单导出

接口

package com.zjl.controller;import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.zjl.model.BillDO;
import com.zjl.service.BillService;
import com.zjl.utils.ExcelUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@RestController
@RequestMapping("bill")
public class BillController {@Resourceprivate BillService billService;/*** 导出* @param response*/@GetMapping("/export")public void exportExcel(HttpServletResponse response) {try {ExcelUtil.setExcelResponseProp(response, "订单列表");List<BillDO> billList = billService.getBillList();EasyExcel.write(response.getOutputStream()).head(BillDO.class).excelType(ExcelTypeEnum.XLSX).sheet("订单列表").doWrite(billList);} catch (IOException e) {throw new RuntimeException(e);}}
}

…省略service、mapper方法定义和实现,没有复杂业务,就返回一个数据集

SQL

<select id="selectBillList" resultType="com.zjl.model.BillDO">selectbillCode,productName,productDesc,productUnit,productCount,totalPrice,isPayment,userName as createdBy,b.creationDate,proName as providerNamefrom smbms_bill b join smbms_provider pon b.providerId = p.idjoin smbms_user u on b.createdBy = u.id</select>

在这里插入图片描述

6.简单导入

接口

@PostMapping("/import")public String importExcel(@RequestPart(value = "file") MultipartFile file) {try {List<BillImportBO> billImportBOList = EasyExcel.read(file.getInputStream()).head(BillImportBO.class).sheet().doReadSync();return billService.saveBillBath(billImportBOList);} catch (IOException e) {return "导入失败!";}}

省略service层

SQL

<insert id="insertBillBatch" parameterType="com.zjl.model.BillImportBO">INSERT INTO smbms_bill(billCode,productName, productDesc, productUnit,productCount,totalPrice, isPayment, createdBy,creationDate, providerId)VALUES<foreach collection="list" item="bill" separator=",">(#{bill.billCode},#{bill.productName},#{bill.productDesc},#{bill.productUnit},#{bill.productCount},#{bill.totalPrice},#{bill.isPayment},1,now(),#{bill.providerId})</foreach></insert>

在这里插入图片描述

7.复杂的导出(合并行、合并列)

由于 EasyPoi 支持嵌套对象导出,直接使用内置 @ExcelCollection 注解即可实现,遗憾的是 EasyExcel 不支持一对多导出,只能自行实现,通过此issues了解到,项目维护者建议通过自定义合并策略方式来实现一对多导出。

解决思路

只需把订单主键相同的列中需要合并的列给合并了,就可以实现这种一对多嵌套信息的导出

自定义注解

创建一个自定义注解,用于标记哪些属性需要合并单元格,哪个属性是主键,用于判断是否需要合并以及合并的主键

package com.zjl.annotate;import java.lang.annotation.*;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelMerge {/*** 是否合并单元格* @return true || false*/boolean merge() default true;/*** 是否为主键(即该字段相同的行合并)* @return true || false*/boolean isPrimaryKey() default false;
}

定义实体类

在需要合并单元格的属性上设置 @ExcelMerge 注解,二级表头通过设置 @ExcelProperty 注解中 value 值为数组形式来实现该效果:

package com.zjl.model;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.zjl.annotate.ExcelMerge;
import com.zjl.coverter.BillIsPaymentConverter;
import lombok.Data;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
@Data
public class ProviderDO {@ExcelProperty(value = "供应商ID")@ExcelMerge(merge = true, isPrimaryKey = true)@ColumnWidth(15)private String id;@ExcelProperty(value = "供应商编码")@ExcelMerge(merge = true)@ColumnWidth(15)private String proCode;@ExcelProperty(value = "供应商名称")@ExcelMerge(merge = true)@ColumnWidth(30)private String proName;//供应商名称@ExcelProperty(value = "合作联系人")@ExcelMerge(merge = true)@ColumnWidth(20)private String proContact;@ExcelProperty(value = "联系电话")@ExcelMerge(merge = true)@ColumnWidth(25)private String proPhone;@ExcelProperty(value = "供应商地址")@ExcelMerge(merge = true)@ColumnWidth(30)private String proAddress;@ExcelProperty(value = "供应商座机")@ExcelMerge(merge = true)@ColumnWidth(20)private String proFax;@ExcelProperty(value = {"订单信息","订单编码"})@ColumnWidth(15)private String billCode;//订单编码@ExcelProperty(value = {"订单信息","商品名称"})@ColumnWidth(30)private String productName;//商品名称@ExcelProperty(value = {"订单信息","商品描述"})@ColumnWidth(30)private String productDesc;//商品描述@ExcelProperty(value = {"订单信息","商品单位"})@ColumnWidth(15)private String productUnit;//商品单位@ExcelProperty(value = {"订单信息","商品数量"})@ColumnWidth(15)private String productCount;//商品数量@ExcelProperty(value = {"订单信息","商品总金额"})@ColumnWidth(15)private String totalPrice;//商品总金额@ExcelProperty(value = {"订单信息","支付状态"},converter = BillIsPaymentConverter.class)   // 列索引为7@ColumnWidth(15)private int isPayment;//支付状态:是否支付(1:未支付 2:已支付)@ExcelProperty(value = {"订单信息","创建人"})@ColumnWidth(15)private String createdBy;//创建人@ExcelProperty(value = {"订单信息","创建时间"})@ColumnWidth(25)@DateTimeFormat("yyyy-MM-dd")private String creationDate;//创建时间
}

SQL

<select id="selectProviderListAndBill" resultType="com.zjl.model.ProviderDO">selectp.id,billCode,productName,productDesc,productUnit,productCount,totalPrice,isPayment,userName as createdBy,b.creationDate,proName,proCode,proContact,proPhone,proAddress,proFaxfrom smbms_bill b join smbms_provider pon b.providerId = p.idjoin smbms_user u on b.createdBy = u.id</select>

自定义单元格合并策略

package com.zjl.utils;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.zjl.annotate.ExcelMerge;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;/*** @author: zjl* @datetime: 2024/3/30* @desc:*/
public class ExcelMergeStrategy implements RowWriteHandler {/*** 主键下标*/private Integer primaryKeyIndex;/*** 需要合并的列的下标集合*/private final List<Integer> mergeColumnIndexList = new ArrayList<>();/*** 数据类型*/private final Class<?> elementType;public ExcelMergeStrategy(Class<?> elementType) {this.elementType = elementType;}@Overridepublic void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {// 判断是否为标题if (isHead) {return;}// 获取当前工作表Sheet sheet = writeSheetHolder.getSheet();// 初始化主键下标和需要合并字段的下标if (primaryKeyIndex == null) {this.initPrimaryIndexAndMergeIndex(writeSheetHolder);}// 判断是否需要和上一行进行合并// 不能和标题合并,只能数据行之间合并if (row.getRowNum() <= 1) {return;}// 获取上一行数据Row lastRow = sheet.getRow(row.getRowNum() - 1);// 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并if (lastRow.getCell(primaryKeyIndex).getStringCellValue().equalsIgnoreCase(row.getCell(primaryKeyIndex).getStringCellValue())) {for (Integer mergeIndex : mergeColumnIndexList) {CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum() - 1, row.getRowNum(), mergeIndex, mergeIndex);sheet.addMergedRegionUnsafe(cellRangeAddress);}}}/*** 初始化主键下标和需要合并字段的下标** @param writeSheetHolder WriteSheetHolder*/private void initPrimaryIndexAndMergeIndex(WriteSheetHolder writeSheetHolder) {// 获取当前工作表Sheet sheet = writeSheetHolder.getSheet();// 获取标题行Row titleRow = sheet.getRow(0);// 获取所有属性字段Field[] fields = this.elementType.getDeclaredFields();// 遍历所有字段for (Field field : fields) {// 获取@ExcelProperty注解,用于获取该字段对应列的下标ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);// 判断是否为空if (null == excelProperty) {continue;}// 获取自定义注解,用于合并单元格ExcelMerge excelMerge = field.getAnnotation(ExcelMerge.class);// 判断是否需要合并if (null == excelMerge) {continue;}for (int i = 0; i < fields.length; i++) {Cell cell = titleRow.getCell(i);if (null == cell) {continue;}// 将字段和表头匹配上if (excelProperty.value()[0].equalsIgnoreCase(cell.getStringCellValue())) {if (excelMerge.isPrimaryKey()) {primaryKeyIndex = i;}if (excelMerge.merge()) {mergeColumnIndexList.add(i);}}}}// 没有指定主键,则异常if (null == this.primaryKeyIndex) {throw new IllegalStateException("使用@ExcelMerge注解必须指定主键");}}
}

接口

@GetMapping("/mergeExport")public void mergeExport(HttpServletResponse response) {try {ExcelUtil.setExcelResponseProp(response, "供应商列表-合并");List<ProviderDO> providerList = providerService.getProviderList();EasyExcel.write(response.getOutputStream()).head(ProviderDO.class).registerWriteHandler(new ExcelMergeStrategy(ProviderDO.class)).excelType(ExcelTypeEnum.XLSX).sheet("供应商列表").doWrite(providerList);} catch (IOException e) {throw new RuntimeException(e);}}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/787534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 本地电脑服务部署

前提&#xff1a; 下载mysql 新建配置文档 在安装mysql目录新建 my.ini [mysqld] # 设置3306端口 port3306#设置mysql的安装目录 basedirC:\Program Files\MySQL\MySQL Server 8.3 #切记此处一定要用双斜杠\\,单斜杠我这里会出错&#xff0c;不过看别人的教程&#xff0c;有…

Docker容器与虚拟化技术:OpenEuler 部署 Docker UI

目录 一、实验 1.环境 2.OpenEuler 部署 docker-compose-ui 2.OpenEuler 部署 docker ui 3.使用cpolar内网穿透 二、问题 1.docker run -w 的作用 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统架构版本IP备注LinuxopenEuler22.03 LTS SP2 192.168…

动态规划——计数类dp

例题&#xff1a;acwing900整数划分 完全背包解法 #include <iostream> #include <algorithm>using namespace std;const int N 1010, mod 1e9 7;int n; int f[N];int main() {cin >> n;f[0] 1;for (int i 1; i < n; i )for (int j i; j < n; …

Golang 哈希表底层实现原理

1、本文讨论Golang的哈希表 Golang哈希表的实现&#xff0c;底层数据结构是数组单链表&#xff0c;链表节点由8个key、value和键的高八位组成的。为了方便理解&#xff0c;先简单看一个图快速理解。 我们来看一下Golang哈希表的结构体定义 简单介绍一下结构体中几个关键的…

(C语言) fgetc与fputc函数详解

目录 1 fgetc函数详解 1.1 从文件流中读取数据 1.2 从标准输入流中读取数据 2 fputc函数详解 2.1 向文件流中写入数据 2.2 向标准输出流中写入数据 1 fgetc函数详解 头文件&#xff1a;stdio.h 该函数只有一个参数&#xff1a;stream 作用&#xff1a;从输入流中获得一个…

函数调用实现小米汽车智能语音助手

上周小米汽车发布&#xff0c;其中有一个特色功能就是智能语音&#xff0c;小爱同学整合了语音大模型&#xff0c;实现智能座舱体验。 雷老板的PPT也演示了&#xff0c;一些口语化的对话就能触发各种指令&#xff0c;无论是开空调、播放音乐&#xff0c;还是找手机、识别前方汽…

Redis Stack 安装部署

参考&#xff1a;Run Redis Stack on Docker | Redis Redis-stack 初体验_redis stack-CSDN博客 【docker】运行redis_docker run redis-stack-server requirepass-CSDN博客 Redis Stack 是一组软件套件&#xff0c;它主要由三部分组成。 一个是 Redis Stack Server&#x…

艺术点亮新乡村--博罗县“村ART“乡村艺术创作大赛圆满落幕

三月的博罗大地春意盎然,处处洋溢着勃勃生机。在这万物复苏、欣欣向荣的美好时节,一场由农民自编自演、自导自绘的乡村文化盛宴在古朴幽静的徐田村徐徐拉开帷幕。由博罗县委宣传部倾情指导,县文联、文广旅体局、文明办通力合作,泰康保险集团鼎力承办的"村ART"乡村艺术…

多功能知识付费源码下载-实现流量互导多渠道变现(带详细安装教程)

资源变现类产品的许多优势&#xff0c;并剔除了那些无关紧要的元素&#xff0c;使得本产品在运营和变现能力方面实现了质的飞跃。多领域素材资源知识变现营销裂变独立版本。 支持&#xff1a;视频、音频、图文、文档、会员、社群、用户发布、创作分成、任务裂变、流量主、在线…

14种建模语言(UML)图形

前言 UML 中有四种关系&#xff1a;依赖、关联、泛化和实现。这四种关系是 UML 模型中可以包含的基本关系事物。这里介绍14种UML图形:类图&#xff0c;对象图&#xff0c;包图&#xff0c;构件图&#xff0c;组合结构图&#xff0c;部署图&#xff0c;制品图&#xff0c;用例图…

sql之每日五题day02--多表联查/聚合函数/多值判断/函数

sql之每日五题day01--多表联查/聚合函数 where和group by同时出现分别查看&结果不去重--union allunion all细节别名case when多值判断数据处理函数 where和group by同时出现 SQL24 统计每个用户的平均刷题数 仅查看山东大学的用户在不同难度下的每个用户的平均答题题目数…

DNDC模型对所有处理的土壤温度和湿度模拟效果良好,但有时土壤湿度模拟存在偏差

使用 DNDC 模型评估加拿大多样化作物轮作系统对产量和 N2O 排放的影响 原名&#xff1a;Assessing the impacts of diversified crop rotation systems on yields and nitrous oxide emissions in Canada using the DNDC model 译名&#xff1a;使用 DNDC 模型评估加拿大多样…

爬虫逆向实战(39)-某某兔装修网登陆(RSA)

一、数据接口分析 主页地址&#xff1a;某某兔装修网 1、抓包 通过抓包可以发现登陆是表单提交 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块&#xff0c;可以发现有一个val和password的加密参数 请求头是否加密&#xff1f; 无响应是否加密…

vue 实现自定义分页打印 window.print

首先这里是我自定义了打印界面才实现的效果&#xff0c;如果不用自定义界面实现&#xff0c;应该是一样的吧。具体可能需要自己去试试看 我的需求是界面有两个表格&#xff0c;点击全部打印&#xff0c;我需要把第一表格在打印是第1页&#xff0c;第二个表格是第二页 如图&…

SmartChart的部署以及可能遇见的报错解决方案

简介 数据可视化是一种将数据转化为图形的技术&#xff0c;可以帮助人们更好地理解和分析数据。但是&#xff0c;传统的数据可视化开发往往需要编写大量的代码&#xff0c;或者使用复杂的拖拽工具&#xff0c;不仅耗时耗力&#xff0c;而且难以实现个性化的需求。有没有一种更…

号称史上最全的PostgreSQL备份恢复,送给有缘人...

&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61c;&#x1f61c; 中国DBA联盟(ACD…

​慧天[HTWATER]可以与与SWMM模型之间实现转换吗?

​慧天[HTWATER]软件简介 针对城市排水系统基础设施数据管理的需求&#xff0c;以及水文、水力及水质模拟对数据的需求&#xff0c;实现了以数据库方式对相应数据的存储。可以对分流制排水系统及合流制排水系统进行地表水文、管网水力、水质过程的模拟计算。可以对城市低影响开…

SwiftUI Swift 显示隐藏系统顶部状态栏

Show me the code // // TestHideSystemTopBar.swift // pandabill // // Created by 朱洪苇 on 2024/4/1. //import SwiftUIstruct TestHideSystemTopBar: View {State private var isStatusBarHidden falsevar body: some View {Button {withAnimation {self.isStatusBa…

有单片机基础,准备过一遍freertos,之后再学linux

应届生我觉得继续把单片机深入一下比较好。 站在公司的角度思考一下&#xff0c;个人觉得应该有以下结论&#xff1a; 1 大公司具备技术资金等优势&#xff0c;因此喜欢学历好&#xff0c;理论扎实能够攻坚的人。倾向于培养各个领域的专家&#xff0c;共同构建自己产品的竞争…

金三银四求职季,最新面试题分享和解析,建议收藏

随着金三银四招聘旺季的到来&#xff0c;在这个竞争激烈的时刻&#xff0c;了解最新的软件测试面试题&#xff0c;充分准备面试&#xff0c;对求职者来说显得尤为重要。本文将分享一些金三银四期间最新的软件测试面试题&#xff0c;帮助求职者更好地应对面试挑战。 一.登录页面…