Java-easyExcel入门教程

文章目录

  • 前言
  • 一、简介
  • 二、使用步骤
    • 1. 引入依赖
    • 2. 前提准备
    • 3. 实现导出
    • 4. 实现导入
  • 三、我所遇到的问题
  • 四、总结


前言

在日常开发中经常会遇到一些 excel 表导入导出的需求,以往会使用 POI 封装成工具类来处理这些导入导出的需求,但是 POI 在导入大文件时非常占用内存,甚至出现 OOM,所以目前很多公司都会使用节省内存的 EasyExcel,虽然说在网上关于 EasyExcel 的教程五花八门的有很多,我从中也学到不少,不过这里我还是将目前我项目中使用的方式总结一下分享出来。


一、简介

官网:https://easyexcel.opensource.alibaba.com/
官方文档:https://easyexcel.opensource.alibaba.com/docs/current/

在这里插入图片描述

EasyExcelalibaba 开源的一个 excel 处理框架,底层是对 POI 的封装,其最大的特点就是 使用简单、节省内存,不同于 POI 的一次性将 excel 文件内容全部读取然后加载到内存中再做处理,EasyExcel 是从磁盘中一行行读取数据,逐个解析,并将解析后的结果以观察者的模式通知处理。

特点:

  • 性能高效:采用了异步导入导出的方式,并且底层使用了 NIO 技术实现,使其在导入导出大量数据时的性能非常高效
  • 易于使用:提供了简单易用的 API ,用户可以通过少量的代码实现导入导出功能
  • 功能强大:除了最基本的导入导出功能,还可以进行合并单元格、数据校验、自定义样式等增强功能
  • 扩展性好:用户可以自定义 Converter 对自定义类型进行转换,或者继承 EasyExcelListener 来自定义监听器实现更加灵活的需求

二、使用步骤

1. 引入依赖

在这里插入图片描述

        <!-- easyExcel 表格依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.3.2</version>
        </dependency>

		<!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

当引入了 easyexcel 的依赖之后,相当于间接的引入了 poipoi-ooxml 的依赖,如果你项目中已经引入了 POI 的话,就可能出现兼容问题,所以我推荐引入较高版本的 easyexcel,这里我是使用了 easyexcel-3.3.2 最新一版的依赖解决了这一冲突的。


2. 前提准备

这里我使用我数据库中的 访问日志 - t_access_log 作为导入和导出的数据,表数据如下:

select * from t_access_log;

在这里插入图片描述

实体类:

package com.mike.bean.inner.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.mike.common.core.domain.web.entity.BaseEntity;
import com.mike.common.core.domain.web.entity.GaeaBaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;

/**
 * <p>
 * 访问记录表
 * </p>
 *
 * @author mike
 * @since 2023-05-30
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("t_access_log")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value="AccessLog对象", description="访问记录表")
public class AccessLog extends BaseEntity {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "自增主键")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "登录名")
    private String loginName;

    @ApiModelProperty(value = "访问路径")
    private String accessPath;

    @ApiModelProperty(value = "访问IP")
    private String accessIp;

	@ApiModelProperty(value = "创建时间")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    @JsonFormat(pattern = DateFormatConstant.NORMAL)
    private Date createTime;

    @ApiModelProperty(value = "访问状态:0已拦截;1已放行")
    private Boolean state;

}


3. 实现导出

easyExcel 实现导出功能还是比较简单的,几行代码就能解决,就是需要定义一个输出的对象,如果我要导出我的访问记录表数据,那么我的输出对象可以这么写:

package com.mike.server.system.domain.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.FillPatternTypeEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
// 头背景设置
@HeadStyle(fillPatternType = FillPatternTypeEnum.SOLID_FOREGROUND, horizontalAlignment = HorizontalAlignmentEnum.CENTER, borderLeft = BorderStyleEnum.THIN, borderTop = BorderStyleEnum.THIN, borderRight = BorderStyleEnum.THIN, borderBottom = BorderStyleEnum.THIN)
//标题高度
@HeadRowHeight(40)
//内容高度
@ContentRowHeight(30)
//内容居中,左、上、右、下的边框显示
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER, borderLeft = BorderStyleEnum.THIN, borderTop = BorderStyleEnum.THIN, borderRight = BorderStyleEnum.THIN, borderBottom = BorderStyleEnum.THIN)
public class AccessLogEasyVo {

    @ApiModelProperty(value = "自增主键")
    @ExcelProperty("自增主键")
    // 格子宽度
    @ColumnWidth(15)
    private Integer id;

    @ApiModelProperty(value = "登录名")
    @ExcelProperty("登录名")
    @ColumnWidth(15)
    private String loginName;

    @ApiModelProperty(value = "访问路径")
    @ExcelProperty("访问路径")
    @ColumnWidth(15)
    private String accessPath;

    @ApiModelProperty(value = "访问IP")
    @ExcelProperty("访问IP")
    @ColumnWidth(15)
    private String accessIp;

	@ApiModelProperty(value = "创建时间")
    @ExcelProperty("创建时间")
    @DateTimeFormat("yyyy-MM-dd HH:mm:ss")
    @ColumnWidth(15)
    private Date createTime;

    @ApiModelProperty(value = "访问状态:0已拦截;1已放行")
    @ExcelProperty("访问状态")
    @ColumnWidth(15)
    private Boolean state;

}

表头信息用注解 @ExcelProperty("表头名称") 表示,其它注解就不一一说明了,可查阅官方文档

代码编写:

TestController.java

    @GetMapping("/export/easy")
    @ApiOperation(value = "示例:导出", produces = "application/octet-stream")
    public ResponseBean<String> easyExport(HttpServletResponse response) {
        testService.easyExport(response);
        return ResponseBean.success();
    }

TestService.java

    void easyExport(HttpServletResponse response);

TestServiceImpl.java

    @Override
    public void easyExport(HttpServletResponse response) {
        /*
         * 以导出 access-log 中的数据为例
         *
         * 使用 阿里 的 easyExcel 框架进行导出
         */
         // 设置响应体
        String finalFileName = "文件名称" + "_(截止"+ StringUtils.getNowTimeStr(DateFormatConstant.Y0M0D)+")";
        // 设置content—type 响应类型
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
        	// 这里URLEncoder.encode可以防止中文乱码
            finalFileName = URLEncoder.encode(finalFileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-disposition", "attachment;filename=" + finalFileName + ".xlsx");
        // 先将需要导出的数据查出来
        List<AccessLog> accessLogs = accessLogMapper.selectAll();
        // 封装 vo 对象,vo 对象中的字段上添加了 @ExcelProperty,与 excel 表头相对应
        List<AccessLogEasyVo> accessLogEasyVos = CopyUtils.copyList(accessLogs, AccessLogEasyVo.class);
        try {
            EasyExcel.write(response.getOutputStream(), AccessLogEasyVo.class)
                    .sheet("Sheet1").doWrite(accessLogEasyVos);
        } catch (IOException e) {
            log.error("export excel error:",e);
            throw new CommonException(ExceptionEnum.EXPORT_EXCEL_ERROR);
        }
    }

因为设置响应体这段代码基本上是固定格式的,所以可以抽出来

package com.mike.common.core.utils.excel;

import com.mike.common.core.constant.DateFormatConstant;
import com.mike.common.core.utils.StringUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class EasyExcelUtil {

    /**
     * 初始化响应体
     * @param response 请求头
     * @param fileName 导出名称
     */
    public static void initResponse(HttpServletResponse response, String fileName) {
    	// 最终文件名:文件名_(截止yyyy-MM-dd)  --> 这块地方得根据你们自己项目做更改了
        String finalFileName = fileName + "_(截止"+ StringUtils.getNowTimeStr(DateFormatConstant.Y0M0D)+")";
        // 设置content—type 响应类型
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        try {
            // 这里URLEncoder.encode可以防止中文乱码
            finalFileName = URLEncoder.encode(finalFileName, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setHeader("Content-disposition", "attachment;filename=" + finalFileName + ".xlsx");
    }
}

TestService.java 简化为:

    @Override
    public void easyExport(String loginName) {
    	// 设置响应体
        EasyExcelUtil.initResponse(response, "文件名称");
        // 先将需要导出的数据查出来
        List<AccessLog> accessLogs = accessLogMapper.selectAll();
        // 封装 vo 对象,vo 对象中的字段上添加了 @ExcelProperty,与 excel 表头相对应
        List<AccessLogEasyVo> accessLogEasyVos = CopyUtils.copyList(accessLogs, AccessLogEasyVo.class);
        try {
            EasyExcel.write(response.getOutputStream(), AccessLogEasyVo.class)
                    .sheet("Sheet1").doWrite(accessLogEasyVos);
        } catch (IOException e) {
            log.error("export excel error:",e);
            throw new CommonException(ExceptionEnum.EXPORT_EXCEL_ERROR);
        }
    }

基本套路就是:① 设置下导出文件响应体信息;② 查询数据;③ 转换成 easyExcel 的输出对象;④ 使用 EasyExcel 导出

相关工具类:CopyUtils.java

package com.mike.common.core.utils;

import com.mike.common.core.utils.bean.BeanUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;

public class CopyUtils {

    /**
     * 复制集合
     */
    public static <T,K> List<T> copyList(List<K> sourceList, Class<T> clazz) {
        if (CollectionUtils.isEmpty(sourceList)) {
            return null;
        }

        ArrayList<T> target = new ArrayList<>();
        sourceList.forEach(k -> target.add(convert(k, clazz)));
        return target;
    }

    /**
     * 复制对象
     */
    public static <T,K> T convert(K source, Class<T> clazz) {
        T t = BeanUtils.instantiateClass(clazz);
        BeanUtils.copyProperties(source, t);
        return t;
    }

}

测试:

在这里插入图片描述

在这里插入图片描述


4. 实现导入

导入的代码相对于导出而已会复杂一点,前面说到 EasyExcel 会一行行的从表格当中读取数据并进行解析,再将解析后的结果以观察者模式通知处理,再官方的文档中是使用到了 ReadListener 这样的一个监听器来处理这些结果数据

在这里插入图片描述

我们可以按照官方文档的方式去实现 ReadListener 类,或者去继承ReadListener 的抽象类 AnalysisEventListener,这里我是采用了继承 AnalysisEventListener 的写法,代码如下:

ExcelDateListener.java

package com.mike.common.core.domain.excel;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class ExcelDateListener<M> extends AnalysisEventListener<M> {

    private final ExcelReaderListenerCallback<M> callback;

    // 每隔50条存储数据库,实际使用中可以3000条,然后清理list,方便内存回收
    private static final int BATCH_COUNT = 50;
    // 表头数据
    Map<Integer,String> headMap=new HashMap<>();
    // 缓存数据
    List<M> cacheList = new ArrayList<>();

    public ExcelDateListener(ExcelReaderListenerCallback<M> callback) {
        this.callback = callback;
    }

    /**
     * 这里会一行行的返回头
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.headMap=headMap;
        log.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
    }


    @Override
    public void invoke(M data, AnalysisContext analysisContext) {
        cacheList.add(data);
        // 在这里可以做一些其他的操作,就靠自己去拓展了
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (cacheList.size() >= BATCH_COUNT) {
            // 这里是存数据库的操作
            callback.convertData(cacheList,headMap);
            // 存储完成清理 list
            cacheList.clear();
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        callback.convertData(cacheList,headMap);
        cacheList.clear();
    }


    /**
     * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        // 如果是某一个单元格的转换异常 能获取到具体行号
        // 如果要获取头的信息 配合invokeHeadMap使用
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            log.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex());
        }
    }

    /**
     * 读取条额外信息:批注、超链接、合并单元格信息等
     */
    @Override
    public void extra(CellExtra extra, AnalysisContext context) {
        log.info("读取到了一条额外信息:{}", JSON.toJSONString(extra));
        switch (extra.getType()) {
            case COMMENT:
                log.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(),
                        extra.getText());
                break;
            case HYPERLINK:
                if ("Sheet1!A1".equals(extra.getText())) {
                    log.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(),
                            extra.getColumnIndex(), extra.getText());
                } else if ("Sheet2!A1".equals(extra.getText())) {
                    log.info(
                            "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{},"
                                    + "内容是:{}",
                            extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                            extra.getLastColumnIndex(), extra.getText());
                } else {
                    log.error("Unknown hyperlink!");
                }
                break;
            case MERGE:
                log.info(
                        "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}",
                        extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(),
                        extra.getLastColumnIndex());
                break;
            default:
        }
    }
}

ExcelReaderListenerCallback.java

package com.mike.common.core.domain.excel;

import java.util.List;
import java.util.Map;

public interface ExcelReaderListenerCallback<T> {

    /**
     * 数据处理
     * @param data 数据
     * @param headMap 表头
     */
    void convertData(List<T> data, Map<Integer,String> headMap);
}

代码编写:

这里我准备了一张表格如下所示:

在这里插入图片描述

现在我要将这张表格数据导入到日志访问记录 t_access_log 表中

TestController.java

    @ApiOperation(value = "示例:导入")
    @PostMapping("/importDate/easy")
    @ApiImplicitParam(name = "file", value = "文件", dataTypeClass = MultipartFile.class, required = true)
    public ResponseBean<String> easyImportDate(@RequestPart("file") MultipartFile file) {
        testService.easyImportDate(file);
        return ResponseBean.success();
    }

TestService.java

    void easyImportDate(MultipartFile file);

TestServiceImpl.java

    @Override
    public void easyImportDate(MultipartFile file) {
        /*
         * 以导出 access-log 中的数据为例
         *
         * 使用 阿里 的 easyExcel 框架进行导入
         */
        try {
            EasyExcel.read(file.getInputStream(), AccessLogEasyVo.class,
                    new ExcelDateListener<AccessLogEasyVo>(new ExcelReaderListenerCallback<AccessLogEasyVo>() {

                @Override
                public void convertData(List<AccessLogEasyVo> data, Map<Integer, String> headMap) {
                    //导入文件表头:登录名   访问路径   访问IP   创建时间   访问状态
                    ArrayList<AccessLog> accessLogs = new ArrayList<>();
                    for (AccessLogEasyVo o : data) {
                        accessLogs.add(AccessLog.builder()
                                .loginName(o.getLoginName())
                                .accessPath(o.getAccessPath())
                                .accessIp(o.getAccessIp())
                                .state(o.getState())
                                .build());
                    }
                    if (!CollectionUtils.isEmpty(accessLogs)) {
                        int row = accessLogMapper.insertBatchSomeColumn(accessLogs);
                        log.info("insert access-log row: {}", row);
                    }
                }
            }))
                    //.extraRead(CellExtraTypeEnum.COMMENT) // 需要读取批注 默认不读取
                    //.extraRead(CellExtraTypeEnum.HYPERLINK) // 需要读取超链接 默认不读取
                    //.extraRead(CellExtraTypeEnum.MERGE) // 需要读取合并单元格信息 默认不读取
                    .sheet().doRead();
        } catch (IOException e) {
            log.error("import excel error:",e);
            throw new CommonException(ExceptionEnum.IMPORT_EXCEL_ERROR);
        }
    }

这里用到了导出时所封装的输出对象 AccessLogEasyVo 类,我们要自己去编写 convertData() 处理表格数据的逻辑,这里我只是做了一个简单的数据类型转换。

测试:

在这里插入图片描述

从日志的打印信息中就能看到数据已经插入成功了

在这里插入图片描述


三、我所遇到的问题

问题一:EasyExcelPOI 依赖冲突问题

当导入 easyexcel 依赖后,如果你项目中以前也有导入过 poi 相关的依赖就可能会出现这个问题,主要会表现在两个方面,一个是你项目中有些关于 poi 的有些类爆红导入包失败,一个就是你在运行的时候出现报错,例如:

我项目中开始的包如下:

        <!-- easyExcel 表格依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.0.1</version>
        </dependency>

        <!-- excel工具 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>4.1.2</version>
        </dependency>

引入依赖的时候项目没有报错,启动项目也没有,但是执行导入时候就报错了

在这里插入图片描述

然后我将 easyexcel 的版本替换成 3.3.2 就解决了这个问题

如果你还是有冲突的话,不妨看看试试以下方法:

        <!-- easyexcel -->
        <!-- 3+ 版本的 easyexcel,使用 poi 5+ 版本时,需要自己引入 poi 5+ 版本的包,且手动排除:poi-ooxml-schemas -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>poi-ooxml-schemas</artifactId>
                    <groupId>org.apache.poi</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- Excel 97-2003 工作簿 -->
        <!-- 这是遵循二进制文件格式的旧 Excel 文件。该格式的文件扩展名为 .xls -->
        <!-- 为了兼容性,这个依赖项也是要加的 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.2</version>
        </dependency>
        <!-- 用于操作 Excel 2007+ 工作簿 -->
        <!-- 这是 Excel 2007 和更高版本的默认基于 XML 的文件格式。该格式的文件扩展名为 .xlsx -->
        <!-- 它遵循 Office Open XML (OOXML) 格式,这是一种由 Microsoft 开发的基于 XML 的压缩文件格式,用于表示办公文档 -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.2</version>
        </dependency>

问题二:org.springframework.http.converter.HttpMessageNotWritableException: No converter for ...

导出文件时出错,但是文件还是能够正常导出,文件内容也是正常的

在这里插入图片描述

这个问题的原因就是我项目是整合了 swagger,所以在接口上我有添加 produces = "application/octet-stream",表示以流的方式输出

在这里插入图片描述

然后在代码中又设置了一次

在这里插入图片描述

所以才会出现以上问题

我最后将 response.setContentType("application/vnd.ms-excel"); 这段代码注释掉就解决了

在这里插入图片描述


四、总结

以上就是我如何整合 EasyExcel 的全部过程以及基础的使用方法,日后如果工作中遇到关于 EasyExcel 的其它一些问题或者写法我也会分享出来,比如说复杂表头的编写、动态表头的实现、合并单元格和修改单元格样式等等。


参考博客:
EasyExcel 的基本使用:https://www.cnblogs.com/aitiknowledge/archive/2022/02/28/15937517.html
EasyExcel 入门使用教程:https://backend.devrank.cn/traffic-information/7301271005489367077
EasyExcel 的基本使用:https://blog.csdn.net/weixin_42001592/article/details/128402350

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

20231202将RK3399的挖掘机开发板在Andorid12系统下编译ENG模式

20231202将RK3399的挖掘机开发板在Andorid12系统下编译ENG模式 2023/12/2 10:21 百度搜索&#xff1a;RK3399 编译 ENG版本 RK3399 lunch ENG Z:\rk_android12_220722\device\rockchip\rk3399\AndroidProducts.mk # # Copyright 2014 The Android Open-Source Project # # Lice…

element-plus的走马灯carousel图片轮播让图片居中显示

element-plus的走马灯carousel图片轮播怎么让图片居中显示呢&#xff1f;官网里查了一下&#xff0c;没找到。只能自己摸索一下了。盒子模型&#xff0c;要让图片居中&#xff0c;首先要确定盒子的大小&#xff0c;然后确定图片的大小&#xff0c;盒子使用居中样式&#xff0c;…

skywalking 9.0.0开启自监控和配置集群

一、skywalking介绍 SkyWalking是有国内开源爱好者吴晟开源并提交到Apache孵化器的开源项目&#xff0c;2017年12月SkyWalking成为Apache国内首个个人孵化项目&#xff0c;2019年4月17日SkyWalking从Apache基金会的孵化器毕业成为顶级项目&#xff0c;目前SkyWalking支持Java、…

CSS 滚动捕获 scroll-margin

CSS滚动捕获 scroll-margin 非滚动捕获容器语法兼容性 CSS滚动捕获 scroll-margin 设置元素的滚动外边距 非滚动捕获容器 之前在 scroll-padding 中说过如何用 scroll-padding 避免锚点定位时元素贴着容器边缘的问题, 现在我们尝试用 scroll-margin 解决 <body><ma…

连接器信号完整性仿真教程 九

前面几篇博文介绍了用CST Studio Suite做连接器信号完整性仿真的基本操作步骤、方法、技巧。本文介绍用Ansys HFSS做连接器信号完整性仿真的基本操作布置。将以 B to B Connector为实例&#xff0c;Step By Step详细讲解Ansys HFSS连接器信号完整性仿真操作步骤。 打开ANSYS E…

JVM 内存回收算法

文章目录 JVM 内存回收算法有哪些&#xff1a;一、分代收集1.分代收集理论2.垃圾收集 二、垃圾收集算法1. 标记-清除算法2. 复制算法3. 标记-整理算法 JVM就是Java虚拟机&#xff0c;JVM的内回收对其原理的认识也是很有必要的&#xff0c;当底层的系统出现内存溢出或者内存泄漏…

列表插槽使用

{label: 是否展示,prop: isShow,solt: true, }<!--自定义列--><template slot-scope"scope" slot"isShow"><div style"color: red;cursor: pointer" focus"getIsShow(scope.row)" ><el-switch v-model"sco…

httpd软件

目录 一.什么是http 二.访问浏览器的过程 三.http的协议版本 四.http的常见配置 一.什么是http 万维网&#xff1a;是数据库&#xff0c;存放链接关系的&#xff0c;例存放baidu-->jd的链接 URL&#xff1a;描述文件的具体位置&#xff0c;一个资源在服务器的具体位置…

分享82个节日PPT,总有一款适合您

分享82个节日PPT&#xff0c;总有一款适合您 82个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1boDTl3PiHFXLJ890CoUfJA?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。…

docker容器启用ipv6地址方法,用ipv6地址访问容器方法流程、创建一个nginx容器用ipv6地址访问测试流程

文章目录 docker容器启用ipv6地址方法Docker-Compose启用IPv6启用ipv6重启docker生效创建一个ipv6的docker网络创建容器测试v6地址使用ipv6的网络创建容器使用普通网络创建容器测试 创建一个nginx容器用ipv6地址访问测试容器创建ipv4地址验证ipv6地址访问验证修改nginx容器网页…

Java面向对象(高级)-- 类的成员之五:内部类(InnerClass)

文章目录 一、 概述&#xff08;1&#xff09; 介绍1. 什么是内部类2. 为什么要声明内部类3. 内部类使用举例4. 内部类的分类 &#xff08;2&#xff09;举例&#xff08;3&#xff09;重点知识1. 对成员内部类的理解2. 创建成员内部类的实例2.1 静态成员内部类2.2 非静态成员内…

大数据读本:暴雨以数字技术助力传统产业数字化转型

发展数字经济&#xff0c;产业数字化是重要引擎。暴雨作为数字经济的领军企业&#xff0c;近年来积极利用数字技术对传统产业进行全方位、全角度、全链条的改造&#xff0c;提高要素生产率&#xff0c;释放数字对经济发展的放大、叠加、倍增作用。在农业产业化方面&#xff0c;…

【开源】基于Vue和SpringBoot的校园二手交易系统

项目编号&#xff1a; S 009 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S009&#xff0c;文末获取源码。} 项目编号&#xff1a;S009&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手商品档案管理模…

K7系列FPGA多重启动(Multiboot)

Xilinx 家的 FPGA 支持多重启动功能&#xff08;Multiboot&#xff09;&#xff0c;即可以从多个 bin 文件中进行选择性加载&#xff0c;从而实现对系统的动态更新&#xff0c;或系统功能的动态调整。 这一过程可以通过嵌入在 bit 文件里的 IPROG 命令实现上电后的自动加载。而…

房产中介管理信息系统的设计与实现

摘 要 随着房地产业的开发&#xff0c;房产中介行业也随之发展起来&#xff0c;由于房改政策的出台&#xff0c;购房、售房、租房的居民越来越多&#xff0c;这对房产中介部门无疑是一个发展的契机。本文结合目前中国城市房产管理的实际情况和现阶段房屋产业的供求关系对房产中…

用Java写一个王者荣耀游戏

目录 sxt包 Background Bullet Champion ChampionDaji GameFrame GameObject Minion MinionBlue MinionRed Turret TurretBlue TurretRed beast包 Bear Beast Bird BlueBuff RedBuff Wolf Xiyi 打开Eclipse创建图片中的几个包 sxt包 Background package sxt;…

Rust语言项目实战(三) - 创建主循环

回顾 在前面的章节中&#xff0c;我们大致已经完成了如下的工作&#xff1a; 为游戏添加了音频文件为游戏准备了备用屏幕及设置为游戏准备了键盘的即时捕获输入的设置在退出游戏前恢复上述的设置 众所周知&#xff0c;游戏在不手动退出的情况下应该一直运行下去&#xff0c;…

编程好处、系统介绍、app演示

编程视频教学地址&#xff1a; 1、编程好处 1.1、自主开发 类似微信、qq等软件应用&#xff0c;解决人们日常生活问题 例如&#xff1a; 1&#xff09;你可以&#xff0c;自己开发一个网站&#xff0c;管理自己的日常生活照片&#xff0c;防止哪一天手机掉了或丢了&#xff0…

UVA11729 Commando War

UVA11729 Commando War 题面翻译 突击战 你有n个部下&#xff0c;每个部下需要完成一项任务。第i个部下需要你花Bj分钟交代任务&#xff0c;然后他就会立刻独立地、无间断地执行Ji分钟后完成任务。你需要选择交代任务的顺序&#xff0c;使得所有任务尽早执行完毕&#xff08…

高斯混合模型:GMM和期望最大化算法的理论和代码实现

高斯混合模型(gmm)是将数据表示为高斯(正态)分布的混合的统计模型。这些模型可用于识别数据集中的组&#xff0c;并捕获数据分布的复杂、多模态结构。 gmm可用于各种机器学习应用&#xff0c;包括聚类、密度估计和模式识别。 在本文中&#xff0c;将首先探讨混合模型&#xf…