【SpringBoot整合系列】SpirngBoot整合EasyExcel

news2024/11/25 3:02:05

目录

  • 背景
    • 需求
    • 发展
  • 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 {
    @ExcelIgnore
    private 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 = "订单编码")   // 列索引为1
    private String billCode;//订单编码
    @ExcelProperty(index = 1,value = "商品名称")   // 列索引为2
    private String productName;//商品名称
    @ExcelProperty(index = 2,value = "商品描述")   // 列索引为3
    private String productDesc;//商品描述
    @ExcelProperty(index = 3,value = "商品单位")   // 列索引为4
    private String productUnit;//商品单位
    @ExcelProperty(index = 4,value = "商品数量")   // 列索引为5
    private String productCount;//商品数量
    @ExcelProperty(index = 5,value = "商品总金额")   // 列索引为6
    private String totalPrice;//商品总金额
    @ExcelProperty(index = 6,value = "支付状态",converter = BillIsPaymentConverter.class)   // 列索引为7
    private int isPayment;//支付状态:是否支付(1:未支付 2:已支付)
    private String creationDate;//创建时间
    @ExcelProperty(index = 7,value = "供应商ID")   // 列索引为10
    private 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> {
    @Override
    public Class<?> supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Integer convertToJavaData(ReadConverterContext<?> context) {
        return IsPaymentEnum.convert(context.getReadCellData().getStringValue()).getValue();
    }

    @Override
    public 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;

    @JsonFormat
    private 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 {
    @Resource
    private 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">
        select
            billCode,
            productName,
            productDesc,
            productUnit,
            productCount,
            totalPrice,
            isPayment,
            userName as createdBy,
            b.creationDate,
            proName as providerName
        from smbms_bill b join smbms_provider p
        on b.providerId = p.id
        join 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">
        select
            p.id,
            billCode,
            productName,
            productDesc,
            productUnit,
            productCount,
            totalPrice,
            isPayment,
            userName as createdBy,
            b.creationDate,
            proName,
            proCode,
            proContact,
            proPhone,
            proAddress,
            proFax
        from smbms_bill b join smbms_provider p
        on b.providerId = p.id
        join 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;
    }

    @Override
    public 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.coloradmin.cn/o/1557759.html

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

相关文章

docker 共享网络的方式实现容器互联

docker 共享网络的方式实现容器互联 本文以nacos连接mysql为例 前提已经在mysql容器中初始化好nacos数据库&#xff0c;库名nacos 创建一个共享网络 docker network create --driver bridge \ --subnt 192.168.0.0/24 \ --gateway 192.168.0.1 mynet此处可以不指定网络模式、…

Python下载bing每日壁纸并实现win11 壁纸自动切换

前言: 爬虫哪家强,当然是python 我是属于啥语言都用,都懂点,不精通,实际工作中能能够顶上就可以。去年写的抓取bing每日的壁纸&#xff0c;保存到本地&#xff0c;并上传到阿里云oss&#xff0c;如果只是本地壁纸切换&#xff0c;存下来就行&#xff0c;一直想做个壁纸站点&…

Java代码基础算法练习-自定义函数之字符串连接-2024.03.30

任务描述&#xff1a; 写一函数&#xff0c;将两个字符串连接起来&#xff0c;然后在主函数中调用该函数实现字符串连接操作。 任务要求&#xff1a; 代码示例&#xff1a; package M0317_0331;import java.util.Scanner;public class m240330 {public static void main(Stri…

【Java】MyBatis快速入门及详解

文章目录 1. MyBatis概述2. MyBatis快速入门2.1 创建项目2.2 添加依赖2.3 数据准备2.4 编写代码2.4.1 编写核心配置文件2.4.2 编写SQL映射文件2.4.3 编写Java代码 3. Mapper代理开发4. MyBatis核心配置文件5. 案例练习5.1 数据准备5.2 查询数据5.2.1 查询所有数据5.2.2 查询单条…

全国青少年软件编程(Python)等级考试三级考试真题2023年12月——持续更新.....

青少年软件编程&#xff08;Python&#xff09;等级考试试卷&#xff08;三级&#xff09; 分数&#xff1a;100 题数&#xff1a;38 一、单选题(共25题&#xff0c;共50分) 1.一个非零的二进制正整数&#xff0c;在其末尾添加两个“0”&#xff0c;则该新数将是原数的&#xf…

Redis从入门到精通(二)Redis的数据类型和常见命令介绍

文章目录 前言第2章 Redis数据类型和常见命令2.1 key结构2.2 Redis通用命令2.3 String类型及其常用命令2.4 Hash类型及其常用命令2.5 List类型2.5 Set类型2.6 SortedSet类型2.7 小结 前言 在上一节【Redis从入门到精通(一)Redis安装与启动、Redis客户端的使用】中&#xff0c;…

【智能算法】猎人猎物算法(HPO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2022年&#xff0c;Naruei等人受到自然界动物猎食过程启发&#xff0c;提出了猎人猎物算法&#xff08;Hunter-Prey Optimization&#xff0c; HPO&#xff09;。 2.算法原理 2.1算法思想 HPO模拟…

国产AI大模型推荐(一)

文心一言 主要功能&#xff1a; 各种类型的问答、各种文本创作、推理与数学计算、写代码、聊天交流、图片生成等。 链接&#xff1a;文心一言 讯飞星火 特点&#xff1a; 内容生成能力&#xff1a;我可以进行多风格多任务长文本生成&#xff0c;例如邮件、文案、公文、作文、对…

剑指Offer题目笔记23(归并排序)

面试题77&#xff1a; 问题&#xff1a; ​ 输入一个链表的头节点&#xff0c;将该链表排序。 解决方案&#xff1a; ​ 使用归并排序。将链表分为两个子链表&#xff0c;在对两个子链表排序后再将它们合并为一个排序的链表。 源代码&#xff1a; /*** Definition for sin…

C语言:动态内存管理(二)

目录 前言 1.3 realloc​编辑 3、常见动态内存管理错误 3.1 对空指针的解引用操作 3.2 对动态开辟的空间进行越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态内存开辟的一部分 3.5 对同一块空间的多次释放 3.6 动态内存开辟之后忘记释放 总结 前…

前端三剑客 —— HTML (下)

目录 HTML 多媒体标签 Img*** a标签*** 第一种用法&#xff1a;超链接 第二种用法&#xff1a;锚点 audio标签 video标签 表格标签 带标题的表格 跨行跨列标签 表格嵌套 列表标签 ul --- 它是无序列表标签 ol --- 它是有序列表 dl --- 它是数据列表 表单标签***…

2024.3.30学习笔记

今日学习韩顺平java0200_韩顺平Java_对象机制练习_哔哩哔哩_bilibili 今日学习p295-p314 super关键字 super代表父类的引用&#xff0c;用于访问父类的属性、方法、构造器 super细节和语法 访问父类的属性&#xff0c;但不能访问父类的private属性 super.属性名 访问父类的…

暴力破解pdf文档密码

首先安装pdfcrack工具包 apt install pdfcrack 默认密码字典存储在/usr/share/wordlists里&#xff0c;是gz文件&#xff0c;将它解压并copy到pdf目录 然后使用pdfcrack破解 密码在最后一行user-password的单引号里

最优算法100例之17- 环形连续子数组的最大和

专栏主页:计算机专业基础知识总结(适用于期末复习考研刷题求职面试)系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 给定一个长度为 nn 的环形整数数组,请你求出该数组的 非空 连续子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开…

Linux重点思考(下)--shell脚本使用以及内核开发

Linux重点思考(下&#xff09;--shell脚本使用和组合拳 shell脚本的基础算法shell脚本写123...n的值&#xff0c;说思路Shell 脚本用于执行服务器性能测试的死循环Shell 脚本备份和定时清理垃圾文件 shell脚本的内核开发正向映射反向映射 shell脚本的基础算法 shell脚本写123……

解决MySQL幻读?可重复读隔离级别背后的工作原理

什么是当前读和快照读 当前读&#xff1a;又称为 "锁定读"&#xff0c;它会读取记录的最新版本&#xff08;也就是最新的提交结果&#xff09;&#xff0c;并对读取到的数据加锁&#xff0c;其它事务不能修改这些数据&#xff0c;直到当前事务提交或回滚。"sele…

linux服务器安装mysql8

1.下载MYSQL 近几天在linux服务器已安装过2次mysql8&#xff0c;亲测有效&#xff0c;没有遇到任何问题&#xff0c;文档已写的很清楚&#xff0c;按步骤来即可。如果按文档有遇到要使用yum命令的话&#xff0c;需要服务器开通外网。 1.1官网下载 进入官网下拉到最后&#x…

【查看显卡信息】如何查看nvidia-smi命令后的显卡信息

【查看显卡信息】如何查看nvidia-smi命令后的显卡信息 【先赞后看养成习惯】求点赞关注收藏&#xff01;&#xff01;&#xff01;&#x1f60a; 一般我们用nvidia-smi进行查看当前电脑或者服务器的显卡信息&#xff0c;出来一大堆内容&#xff0c;很多小白根本看不懂&#xf…

elementui 导航菜单栏和Breadcrumb 面包屑关联

系列文章目录 一、elementui 导航菜单栏和Breadcrumb 面包屑关联 文章目录 系列文章目录前言一、elementui 导航菜单栏和Breadcrumb 面包屑怎么关联&#xff1f;二、实现效果三、实现步骤1.本项目演示布局2.添加面包屑2.实现breadcrumbName方法3.监听方法4.路由指配5.路由配置…

大数据设计为何要分层,行业常规设计会有几层数据

大数据设计通常采用分层结构的原因是为了提高数据管理的效率、降低系统复杂度、增强数据质量和可维护性。这种分层结构能够将数据按照不同的处理和应用需求进行分类和管理&#xff0c;从而更好地满足不同层次的数据处理和分析需求。行业常规设计中&#xff0c;数据通常按照以下…