基于EasyExcel的数据导入导出

前言:
代码复制粘贴即可用,主要包含的功能有Excel模板下载、基于Excel数据导入、Excel数据导出。

根据实际情况修改一些细节即可,最后有结果展示,可以先看下结果,是否是您想要的。

台上一分钟,台下60秒,不喜勿喷。

觉得有用,麻烦点个赞和关注。

新建SpringBoot项目,引入下面的依赖
注:这个依赖已经整合了 poi 和poi-ooxm,无需单独引入。

 <!-- EasyExcel -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.7</version>
        </dependency>

数据导入导出执行原理和思路:
用户端逻辑:

  1. 数据导入

     用户先下载模板,根据模板填入数据,然后点击上传;
    
  2. 数据导出

     用户在界面选择需要导出的数据(导出条件),点击导出。
    

后台开发逻辑:

  1. 模板下载

     利用easyExcel生成文件,然后将文件放进响应流中,同时设置响应头为文件下载,浏览器收到响应之后,回去解析流中的内容,然后进行下载。
    
  2. 文件上传

     用在填写好Excel内容之后,会以文件上传的形式,将文件上传到服务端,此时,我们只需要利用EasyExcel将文件流中的数据读出来即可。
    
  3. 数据导出

     后台在接收到用户的数据导出请求之后,会根据请求中的筛选条件,查询对应数据,再将对应的数据填充进对应的导出模板中,以流的形式响应给浏览器。其实和模板下载的差不错,只是模板下载没有数据,数据导出有数据而已。
    

代码实现
说明:以下代码,是我根据具体业务编写之后整理出来的,会有不足的地方,欢迎指教!

下拉框策略
如果没有此需求,可以不要此类。

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
 
import java.util.Map;
import java.util.TreeMap;
 
/**
 * 这个类的作用主要是给列增加下拉框
 * 主要是为了方便用户填写数据
 */
public class CustomSheetWriteHandler implements SheetWriteHandler {
 
    /**
     * 存放下拉内容的集合
     * key为列的下标, value为下拉内容数组
     */
    private final Map<Integer, String[]> map = new TreeMap<>();
 
    /**
     * 工作簿下标,从0开始
     */
    private int index = 0;
 
    /**
     * 给多少行添加下拉框,这里默认给2000行
     */
    private final int batchSize = 2000;
 
 
 
    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
 
    }
 
    /**
     * 宝藏在此:如果下拉框内容总的长度超过255,会导致Cell有下拉框,但是下拉内容显示不了,
     * 这时我们可以新建一个sheet,将其隐藏,然后将里面的内容引用到我们的下拉框列就可以。
     * 值得细品
     * @param writeWorkbookHolder
     * @param writeSheetHolder
     */
    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        // excel下标从0开始,这里第二列的下拉选择内容
        map.put(1, new String[]{"下拉内容一", "下拉内容二"});
        // excel下标从0开始,这里第三列的下拉选择内容
        map.put(3, new String[]{"北京市", "上海市", "重庆市", "天津市"});
 
        DataValidationHelper helper = writeSheetHolder.getSheet().getDataValidationHelper();
        map.forEach((k, v) -> {
            // 创建sheet,突破下拉框255的限制
            // 获取一个workbook
            Workbook workbook = writeWorkbookHolder.getWorkbook();
            // 定义sheet的名称
            String sheetName = "sheet" + k;
            // 1.创建一个隐藏的sheet 名称为 proviceSheet
            Sheet proviceSheet = workbook.createSheet(sheetName);
            // 从第二个工作簿开始隐藏
            this.index++;
            // 设置隐藏
            workbook.setSheetHidden(this.index, true);
            // 2.循环赋值(为了防止下拉框的行数与隐藏域的行数相对应,将隐藏域加到结束行之后)
            for (int i = 0, length = v.length; i < length; i++) {
                // i:表示你开始的行数 0表示你开始的列数
                proviceSheet.createRow(i).createCell(0).setCellValue(v[i]);
            }
            Name category1Name = workbook.createName();
            category1Name.setNameName(sheetName);
            // 4 $A$1:$A$N代表 以A列1行开始获取N行下拉数据
            category1Name.setRefersToFormula(sheetName + "!$A$1:$A$" + (v.length));
            // 5 将刚才设置的sheet引用到你的下拉列表中,1表示从行的序号1开始(开始行,通常行的序号为0的行是表头),50表示行的序号50(结束行),表示从行的序号1到50,k表示开始列序号和结束列序号
            CellRangeAddressList addressList = new CellRangeAddressList(1, batchSize, k, k);
            DataValidationConstraint constraint8 = helper.createFormulaListConstraint(sheetName);
            DataValidation dataValidation3 = helper.createValidation(constraint8, addressList);
 
            // 阻止输入非下拉选项的值
            dataValidation3.setErrorStyle(DataValidation.ErrorStyle.STOP);
            dataValidation3.setShowErrorBox(true);
            dataValidation3.setSuppressDropDownArrow(true);
            dataValidation3.createErrorBox("提示", "此值与单元格定义格式不一致");
            // validation.createPromptBox("填写说明:","填写内容只能为下拉数据集中的单位,其他单位将会导致无法入仓");
            writeSheetHolder.getSheet().addValidationData(dataValidation3);
        });
    }
}

批注策略
给表头添加批注,没有此需求可以不要

import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
 
/**
 * 自定义拦截器.新增注释,第一行头加批注
 * 这个类的作用主要是给表头添加批注
 */
@Slf4j
public class CommentWriteHandler implements RowWriteHandler {
    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {
 
    }
 
    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
 
    }
 
    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        Sheet sheet = writeSheetHolder.getSheet();
        Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
 
        // 在第一行 第二列创建一个批注
        Comment comment1 =
                drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)0, 0, (short)1, 1));
        // 输入批注信息
        comment1.setString(new XSSFRichTextString("批注1"));
        // 将批注添加到单元格对象中
        sheet.getRow(0).getCell(0).setCellComment(comment1);
 
        Comment comment2 =
                drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)1, 0, (short)2, 1));
        // 输入批注信息
        comment2.setString(new XSSFRichTextString("批注2"));
        // 将批注添加到单元格对象中
        sheet.getRow(0).getCell(1).setCellComment(comment2);
 
        Comment comment3 =
                drawingPatriarch.createCellComment(new XSSFClientAnchor(0, 0, 0, 0, (short)2, 0, (short)3, 1));
        // 输入批注信息
        comment3.setString(new XSSFRichTextString("批注3"));
        // 将批注添加到单元格对象中
        sheet.getRow(0).getCell(2).setCellComment(comment3);
    }
}

数据读取监听
导入数据时,程序解析和读取数据用,必须要!!!

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
 
/**
 * Excel数据解析监听器, 数据解析方法异步执行
 * @param <T>   Excel中数据的类型
 */
@Getter
@Setter
@NoArgsConstructor
public class ExcelListener<T> extends AnalysisEventListener<T> {
    // 加入一个判断标签,判断数据是否已经读取完
    private volatile boolean retryLock = false;
 
    // 解析完成后的数据集合, 监听对象初始化之后,立即初始化集合对象
    private final List<T> dataList = new ArrayList<>();
 
    // 每次最多导入条数
    private final int batchSize = 2000;
 
 
    /**
     * 获取解析后的数据集合, 如果数据还没有被解析完成,会对读取该集合的线程进行阻塞,直到数据读取完成之后,进行解锁。
     * 如果一次导入数据超过batchSize条,则以抛异常的形式阻止导入数据
     * @return  解析后的数据集合
     */
    public List<T> getDataList() {
        while (true){
            if (retryLock){
                if (dataList.size() > batchSize){
                    // 手动清空数据内存数据,减少内存消耗
                    dataList.clear();
                    throw new RuntimeException("一次最多导入"+ batchSize +"条数据");
                } else {
                    return dataList;
                }
            }
        }
    }
 
    /**
     * Excel每解析一行数据,就会调用一次该方法
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     *            analysis context
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        dataList.add(data);
    }
 
    /**
     * 读取表头内容
     * @param headMap   表头部数据
     * @param context   数据解析上下文
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        //System.out.println("表头:" + headMap);
    }
 
    /**
     * 流中的数据解析完成之后,就会调用此方法
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 数据解析完成,解锁
        retryLock = true;
    }
 
    /**
     * 解析过程如果发生异常,会调用此方法
     * @param exception
     * @param context
     */
    @Override
    public void onException(Exception exception, AnalysisContext context){
        throw new RuntimeException("Excel数据异常,请检查或联系管理员!");
    }
}
 

Excel工具类
封装统一的Excel操作入口

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.List;
 
@Slf4j
public class ExcelUtil {
    /**
     * 导出数据为excel文件
     *
     * @param filename       文件名称
     * @param dataResult     集合内的bean对象类型要与clazz参数一致
     * @param clazz          集合内的bean对象类型要与clazz参数一致
     * @param response       HttpServlet响应对象
     */
    public static void export(String filename, List<?> dataResult, Class<?> clazz, HttpServletResponse response) {
        response.setStatus(200);
        OutputStream outputStream = null;
        ExcelWriter excelWriter = null;
        try {
            if (StringUtils.isBlank(filename)) {
                throw new RuntimeException("'filename' 不能为空");
            }
            String fileName = filename.concat(".xlsx");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            outputStream = response.getOutputStream();
 
            // 根据不同的策略生成不同的ExcelWriter对象
            if (dataResult == null){
                excelWriter = getTemplateExcelWriter(outputStream);
            } else {
                excelWriter = getExportExcelWriter(outputStream);
            }
 
            WriteTable writeTable = EasyExcel.writerTable(0).head(clazz).needHead(true).build();
            WriteSheet writeSheet = EasyExcel.writerSheet(fileName).build();
            // 写出数据
            excelWriter.write(dataResult, writeSheet, writeTable);
 
        } catch (Exception e) {
            log.error("导出excel数据异常:", e);
            throw new RuntimeException(e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    log.error("导出数据关闭流异常", e);
                }
            }
        }
    }
 
    /**
     * 根据不同策略生成不同的ExcelWriter对象, 可根据实际情况修改
     * @param outputStream  数据输出流
     * @return  模板下载ExcelWriter对象
     */
    private static ExcelWriter getTemplateExcelWriter(OutputStream outputStream){
        return EasyExcel.write(outputStream)
                .registerWriteHandler(new CommentWriteHandler())        //增加批注策略
                .registerWriteHandler(new CustomSheetWriteHandler())    //增加下拉框策略
                .registerWriteHandler(getStyleStrategy())               //字体居中策略
                .build();
    }
 
    /**
     * 根据不同策略生成不同的ExcelWriter对象, 可根据实际情况修改
     * @param outputStream  数据输出流
     * @return  数据导出ExcelWriter对象
     */
    private static ExcelWriter getExportExcelWriter(OutputStream outputStream){
        return EasyExcel.write(outputStream)
                .registerWriteHandler(getStyleStrategy())   //字体居中策略
                .build();
    }
 
    /**
     *  设置表格内容居中显示策略
     * @return
     */
    private static HorizontalCellStyleStrategy getStyleStrategy(){
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        //设置背景颜色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        //设置头字体
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short)13);
        headWriteFont.setBold(true);
        headWriteCellStyle.setWriteFont(headWriteFont);
        //设置头居中
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
 
        // 内容策略
        WriteCellStyle writeCellStyle = new WriteCellStyle();
        // 设置内容水平居中
        writeCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(headWriteCellStyle, writeCellStyle);
    }
 
    /**
     * 根据Excel模板,批量导入数据
     * @param file  导入的Excel
     * @param clazz 解析的类型
     * @return  解析完成的数据
     */
    public static List<?> importExcel(MultipartFile file, Class<?> clazz){
        if (file == null || file.isEmpty()){
            throw new RuntimeException("没有文件或者文件内容为空!");
        }
        List<Object> dataList = null;
        BufferedInputStream ipt = null;
        try {
            InputStream is = file.getInputStream();
            // 用缓冲流对数据流进行包装
            ipt = new BufferedInputStream(is);
            // 数据解析监听器
            ExcelListener<Object> listener = new ExcelListener<>();
            // 读取数据
            EasyExcel.read(ipt, clazz,listener).sheet().doRead();
            // 获取去读完成之后的数据
            dataList = listener.getDataList();
        } catch (Exception e){
            log.error(String.valueOf(e));
            throw new RuntimeException("数据导入失败!" + e);
        }
        return dataList;
    }
 
}

创建导入数据模板类
可以理解为这个类是我们和客户之间的约定,程序根据这个模板类生成对应的Excel文件,客户根据Excel文件将数据填充进来。然后用户将填充好的Excel文件上传到我们的程序中,我们还得根据这个模板类来解析读取用户填充的数据。

根据实际业务调整,上面的工具类会根据提供的模板生成对应的Excel文件。

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
import lombok.experimental.Accessors;
 
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
 
/**
 * 数据导入的Excel模板实体
 */
@Data
public class ImportExcelVo implements Serializable {
    private static final long serialVersionUID = 1L;
 
    @ColumnWidth(20)
    @ExcelProperty(value = "公司名称", index = 0)
    private String name;
 
    @ColumnWidth(20)
    @ExcelProperty(value = "公司联系电话", index = 1)
    private String phone;
 
    @ColumnWidth(28)
    @ExcelProperty(value = "公司统一社会信用代码", index = 2)
    private String creditCode;
 
    @ColumnWidth(15)
    @ExcelProperty(value = "区域", index = 3)
    private String province;
 
    @ColumnWidth(15)
    @ExcelProperty(value = "公司法人", index = 4)
    private String legalPerson;
 
    @ExcelProperty(value = "备注", index = 5)
    private String remark;
}

创建数据导出模板
根据此模板,向用户展示用户可以看到的字段。

根据实际业务调整,上面的工具类会根据提供的模板生成对应的Excel文件。

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import lombok.Data;
import lombok.experimental.Accessors;
 
import java.io.Serializable;
 
/**
 * 资质信息导出实体
 */
@Data   // Lombok注解,用于生成getter setter
@Accessors(chain = true) //Lombok注解,链式赋值使用
public class ExportExcelVo implements Serializable {
    private static final long serialVersionUID = 1L;
 
    @ColumnWidth(25)
    @ExcelProperty(value = "企业名称", index = 0)
    private String name;
 
    @ColumnWidth(25)
    @ExcelProperty(value = "社会统一信用代码", index = 1)
    private String creditCode;
 
    @ColumnWidth(15)
    @ExcelProperty(value = "曾用名", index = 2)
    private String formerName;
 
    @ColumnWidth(15)
    @ExcelProperty(value = "公司法人", index = 3)
    private String legalPerson;
 
    @ExcelProperty(value = "区域", index = 4)
    private String province;
 
    @ExcelProperty(value = "录入时间", index = 5)
    private String createTime;
 
    @ColumnWidth(15)
    @ExcelProperty(value = "公司股东", index = 6)
    private String stockholder;
 
    @ExcelProperty(value = "企业联系方式", index = 7)
    private String contact;
 
}

Web接口

import lombok.extern.slf4j.Slf4j;
import com.xxx.xxx.domain.vo.ExportExcelVo;
import com.xxx.xxx.domain.vo.ImportExcelVo;
import com.xxx.xxx.util.CommonResponse;
import com.xxx.xxx.util.ExcelUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
/**
 * 事件控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/excel")
public class ExcelController {
 
    /**
     * excel模板下载
     */
    @RequestMapping(value = "/template", method = RequestMethod.GET)
    public CommonResponse<String> template(HttpServletResponse response){
        String fileName = "导入模板下载" + System.currentTimeMillis();
        try {
            ExcelUtil.export(fileName, null, ImportExcelVo.class, response);
        } catch (Exception e) {
            return CommonResponse.error("模板下载失败" + e.getMessage());
        }
        return CommonResponse.success("模板下载成功!");
    }
 
    /**
     * Excel批量导入数据
     * @param file 导入文件
     */
    @RequestMapping(value = "/import", method = RequestMethod.POST)
    public CommonResponse<String> importEvents(MultipartFile file){
        try {
            List<?> list = ExcelUtil.importExcel(file, ImportExcelVo.class);
            System.out.println(list);
            return CommonResponse.success("数据导入完成");
        } catch (Exception e) {
            return CommonResponse.error("数据导入失败!" + e.getMessage());
        }
    }
 
 
    /**
     * excel数据导出
     * @param size  导出条数, 也可以是用户需要导出数据的条件
     * @return
     */
    @RequestMapping(value = "/export", method = RequestMethod.GET)
    public CommonResponse<String> export(Long size, HttpServletResponse response){
        // 模拟根据条件在数据库查询数据
        ArrayList<ExportExcelVo> excelVos = new ArrayList<>();
        for (int i = 1; i <= size; i++) {
            ExportExcelVo excelVo = new ExportExcelVo();
            excelVo.setContact(String.valueOf(10000000000L + i));
            excelVo.setName("公司名称" + i);
            excelVo.setCreditCode("社会性用代码" + i);
            excelVo.setProvince("地区" + i);
            excelVo.setLegalPerson("法人" + i);
            excelVo.setFormerName("曾用名" + i);
            excelVo.setStockholder("投资人" + i);
            excelVo.setCreateTime(new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date()));
            excelVos.add(excelVo);
        }
 
        String fileName = "数据导出" + System.currentTimeMillis();
 
        try {
            ExcelUtil.export(fileName, excelVos, ExportExcelVo.class, response);
        } catch (Exception e) {
            return CommonResponse.error("数据导出成功" + e.getMessage());
        }
        return CommonResponse.success("数据导出失败!");
    }
 
 
}

结果展示
模板下载
浏览器访问模板下载接口,然后会根据接口返回的内容进行解析
在这里插入图片描述
在这里插入图片描述
数据导入
填充数据,在下载下来的模板中填入数据
在这里插入图片描述
利用PostMan进行文件上传
在这里插入图片描述
数据导出
浏览器访问数据导出接口
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

OSG中几何体的绘制(二)

5. 几何体操作 在本章的前言中就讲到&#xff0c;场景都是由基本的绘图基元构成的&#xff0c;基本的绘图基元构成简单的几何体,简单的几何体构成复杂的几何体&#xff0c;复杂的几何体最终构造成复杂的场景。当多个几何体组合时&#xff0c;可能存在多种降低场景渲染效率的原因…

SQL进阶理论篇(七):B+树的查询及存储机制

文章目录 简介数据库中的存储结构数据库中的页结构从数据页来看B树的查询过程总结参考文献 简介 我们之前已经了解过数据库的B树索引和Hash索引&#xff0c;这些索引信息以及数据记录都是保存在文件里的&#xff0c;确切的说是存储在页结构中。 本节&#xff0c;从我们将了解…

【LeetCode刷题】-- 161.相隔为1的编辑距离

161.相隔为1的编辑距离 方法&#xff1a;一次遍历 首先&#xff0c;我们要确认字符串的长度不会相差太远。如果长度差了2个或更多字符&#xff0c;那么 s 和 t 就不可能是一次编辑之差的字符串。 接下来&#xff0c;我们假设 s 的长度总是短于或等于 t 的长度。如果不是这样&…

cesium 自定义贴图,shadertoy移植教程。

1.前言 cesium中提供了一些高级的api&#xff0c;可以自己写一些shader来制作炫酷的效果。 ShaderToy 是一个可以在线编写、测试和分享图形渲染着色器的网站。它提供了一个图形化的编辑器&#xff0c;可以让用户编写基于 WebGL 的 GLSL 着色器代码&#xff0c;并实时预览渲染结…

大数据存储技术(3)—— HBase分布式数据库

目录 一、HBase简介 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;特点 &#xff08;三&#xff09;HBase架构 二、HBase原理 &#xff08;一&#xff09;读流程 &#xff08;二&#xff09;写流程 &#xff08;三&#xff09;数据 flush 过程 &#xf…

配置802.1x认证

实验目的&#xff1a; 某公司拥有两个部门&#xff0c;市场部和人事部门&#xff0c;市场部和人事部的IP地址分别为10.1.11.0/24、10.1.21.0/24两个IP网段。市场部属于vlan11&#xff0c;人事部属于vlan21。现在需要在SW2上配置802.1x认证&#xff0c;实现终端用于只有认证成功…

BKP 备份寄存器 RTC 实时时钟-stm32入门

这一章节我们要讲的主要内容是 RTC 实时时钟&#xff0c;对应手册&#xff0c;是第 16 章的位置。 实时时钟这个东西&#xff0c;本质上是一个定时器&#xff0c;但是这个定时器&#xff0c;是专门用来产生年月日时分秒&#xff0c;这种日期和时间信息的。所以学会了 STM32 的…

Flink系列之:SQL提示

Flink系列之&#xff1a;SQL提示 一、动态表选项二、语法三、例子四、查询提示五、句法六、加入提示七、播送八、随机散列九、随机合并十、嵌套循环十一、LOOKUP十二、进一步说明十三、故障排除十四、连接提示中的冲突案例十五、什么是查询块 SQL 提示可以与 SQL 语句一起使用来…

【卡塔尔世界杯数据可视化与新闻展示】

卡塔尔世界杯数据可视化与新闻展示 前言数据获取与处理可视化页面搭建功能实现新闻信息显示详情查看登录注册评论信息管理 创新点结语 前言 随着卡塔尔世界杯的临近&#xff0c;对于足球爱好者来说&#xff0c;对比赛的数据分析和新闻报道将成为关注的焦点。本文将介绍如何使用…

腾讯云优惠全站搜——云服务器配置大全精准

腾讯云推出优惠全站搜页面 https://curl.qcloud.com/PPrF9NFe 在这个页面可以一键查询所需云服务器、轻量应用服务器、数据库、存储、CDN、网络、安全、大数据等云产品优惠活动大全&#xff0c;活动打开如下图&#xff1a; 腾讯云优惠全站搜——优惠合集 如上图&#xff0c;在这…

uniGUI学习之UniTreeview

UniTreeview中能改变一级目录的字体和颜色 function beforeInit(sender, config) { ID"#"config.id; Ext.util.CSS.createStyleSheet( ${ID} .x-tree-node-text{color:green;font-weight:800;} ${ID} .x-tree-elbow-line ~ span{color:black;font-weight:400;} ); }

macbookpro 2024怎么恢复出厂设置

可能你的MacBook曾经是高性能的代表&#xff0c;但是现在它正慢慢地逝去了自己的光芒&#xff1f;随着逐年的使用以及文件的添加和程序的安装&#xff0c;你的MacBook可能会开始变得迟缓卡顿&#xff0c;或者失却了以往的光彩。如果你发现你的Mac开始出现这些严重问题&#xff…

Windows设备管理

1、前言 熟悉Windows系统的都应该使用过设备管理器。设备管理器将操作系统中所有已安装的设备分类展现出来。同时提供了安装、卸载、启用和禁用的功能。 那么&#xff0c;我们应该如何通过C编程的方式实现这种功能呢&#xff1f;答案很简单&#xff0c;那就是使用SetupDi函数族…

GZ015 机器人系统集成应用技术样题4-学生赛

2023年全国职业院校技能大赛 高职组“机器人系统集成应用技术”赛项 竞赛任务书&#xff08;学生赛&#xff09; 样题4 选手须知&#xff1a; 本任务书共 25页&#xff0c;如出现任务书缺页、字迹不清等问题&#xff0c;请及时向裁判示意&#xff0c;并进行任务书的更换。参赛队…

2020 ICPC·小米邀请赛 决赛 J. Rikka with Book(状压dp)

题目 登录—专业IT笔试面试备考平台_牛客网 n(n<20)本书&#xff0c;放在桌子上&#xff0c; 第i本书的可以看成是li(li<1e3)*1*1的物体&#xff0c;其中长为li&#xff0c;宽为1&#xff0c;高为1&#xff0c; 质量均匀分布&#xff0c;且为wi(wi<1e3) 求n本书摞…

前端桌面通知(Desktop Notifications)API

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

msvcrtd.dll下载安装方法,解决msvcrtd.dll找不到的问题

在这篇文章中&#xff0c;我们将详细讨论msvcrtd.dll文件的下载安装方法&#xff0c;并分析出现找不到msvcrtd.dll的情况及解决方法。如果你遇到了与msvcrtd.dll相关的问题&#xff0c;本文将为你提供全面且详细的解决方案。 一.什么是msvcrtd.dll文件 首先&#xff0c;让我们…

JS中的String常用的实例方法

splice():分隔符 把字符串以分隔符的形式拆分为数组 const str pink,red;const arr str.split(,);console.log(arr);//Array[0,"pink";1:"red"]const str1 2022-4-8;const arr1 str1.split(-);console.log(arr1);//Array[0,"2022";1:"…

权重衰减(Weight Decay)

在深度学习中&#xff0c;权重衰减&#xff08;Weight Decay&#xff09;是一种常用的正则化技术&#xff0c;旨在减少模型的过拟合现象。权重衰减通过向损失函数添加一个正则化项&#xff0c;以惩罚模型中较大的权重值。 一、权重衰减 在深度学习中&#xff0c;模型的训练过程…

leetcode移除元素

移除元素 题目分析题解代码:c版本c版本 题目 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺…