JAVA实现EasyExcel导出excel

news2024/11/15 17:42:49

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。快速、简洁、解决大文件内存溢出的java处理Excel工具

  • 快速:快速的读取excel中的数据。
  • 简洁:映射excel和实体类,让代码变的更加简洁。
  • 大文件:在读写大文件的时候使用磁盘做缓存,更加的节约内存。

当项目中同时使用easypoi和easyExcel时,easypoi依赖放在easyExcel的前面

导出常用注解

注解类型描述
ExcelProperty导出index 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字,多个value可以参照快速开始中的复杂头
ExcelIgnore导出默认所有字段都会写入excel,这个注解会忽略这个字段
DateTimeFormat导出日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat
NumberFormat导出数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat
ExcelIgnoreUnannotated导出默认不加ExcelProperty 的注解的都会参与读写,加了不会参与

导出方法参数:WriteWorkbook,WriteSheet ,WriteTable都会有的参数,如果为空,默认使用上级。

  • converter 转换器,默认加载了很多转换器。也可以自定义。
  • writeHandler 写的处理器。可以实现WorkbookWriteHandler,SheetWriteHandler,RowWriteHandler,CellWriteHandler,在写入excel的不同阶段会调用
  • relativeHeadRowIndex 距离多少行后开始。也就是开头空几行
  • needHead 是否导出头
  • headclazz二选一。写入文件的头列表,建议使用class。
  • clazzhead二选一。写入文件的头对应的class,也可以使用注解。
  • autoTrim 字符串、表头等数据自动trim

WriteWorkbook(理解成excel对象)参数

  • excelType 当前excel的类型 默认xlsx
  • outputStreamfile二选一。写入文件的流
  • fileoutputStream二选一。写入的文件
  • templateInputStream 模板的文件流
  • templateFile 模板文件
  • autoCloseStream 自动关闭流。
  • password 写的时候是否需要使用密码
  • useDefaultStyle 写的时候是否是使用默认头

WriteSheet(就是excel的一个Sheet)参数

  • sheetNo 需要写入的编码。默认0
  • sheetName 需要些的Sheet名称,默认同sheetNo

WriteTable(就把excel的一个Sheet,一块区域看一个table)参数

  • tableNo 需要写入的编码。默认0

样式注解

  • @ExcelProperty
  • @ColumnWith 列宽
  • @ContentFontStyle 文本字体样式
  • @ContentLoopMerge 文本合并
  • @ContentRowHeight 文本行高度
  • @ContentStyle 文本样式
  • @HeadFontStyle 标题字体样式
  • @HeadRowHeight 标题高度
  • @HeadStyle 标题样式
  • @ExcelIgnore 忽略项
  • @ExcelIgnoreUnannotated 忽略未注解

@ExcelProperty
必要的一个注解,注解中有三个参数value,index分别代表列明,列序号value和index只能二选一,通常不用设置converter

  • value 通过标题文本对应
  • index 通过文本行号对应

文件后缀

文件后缀MIME TYPE
.docapplication/msword
.dotapplication/msword
.docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
.dotxapplication/vnd.openxmlformats-officedocument.wordprocessingml.template
.docmapplication/vnd.ms-word.document.macroEnabled.12
.dotmapplication/vnd.ms-word.template.macroEnabled.12
.xlsapplication/vnd.ms-excel
.xltapplication/vnd.ms-excel
.xlaapplication/vnd.ms-excel
.xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.xltxapplication/vnd.openxmlformats-officedocument.spreadsheetml.template
.xlsmapplication/vnd.ms-excel.sheet.macroEnabled.12
.xltmapplication/vnd.ms-excel.template.macroEnabled.12
.xlamapplication/vnd.ms-excel.addin.macroEnabled.12
.xlsbapplication/vnd.ms-excel.sheet.binary.macroEnabled.12
.pdfapplication/pdf
.pptapplication/vnd.ms-powerpoint
.potapplication/vnd.ms-powerpoint
.ppsapplication/vnd.ms-powerpoint
.ppaapplication/vnd.ms-powerpoint
.pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
.potxapplication/vnd.openxmlformats-officedocument.presentationml.template
.ppsxapplication/vnd.openxmlformats-officedocument.presentationml.slideshow
.ppamapplication/vnd.ms-powerpoint.addin.macroEnabled.12
.pptmapplication/vnd.ms-powerpoint.presentation.macroEnabled.12
.potmapplication/vnd.ms-powerpoint.presentation.macroEnabled.12
.ppsmapplication/vnd.ms-powerpoint.slideshow.macroEnabled.12
.zipapplication/zip
.tarapplication/x-tar
.gifimage/gif
.pngimage/png
.htmltext/html
.txttext/plain

添加pom依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

<!--工具类-->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.1</version>
</dependency>

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.21</version>
</dependency>

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

第一种:普通导出

实体类

package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class GoodsExportExcel {

    @ExcelProperty(value = {"商品信息","商品名称"},index = 0)
    public String goodsName;

    @ExcelProperty(value = {"商品信息","商品价格"},index = 1)
    public BigDecimal price;

    @ExcelProperty(value = {"商品信息","商品数量"},index = 2)
    public Integer num;

    public GoodsExportExcel(String goodsName, BigDecimal price, Integer num) {
        this.goodsName = goodsName;
        this.price = price;
        this.num = num;
    }
}

执行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.example.mybatismysql8demo.excel.GoodsExportExcel;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@RestController
public class EasyExcelController {

    @RequestMapping(value = "easyExcelExport", method = RequestMethod.GET)
    public void easyExcelExport(HttpServletResponse response) {
        //数据
        List<GoodsExportExcel> data = new ArrayList<>();
        data.add(new GoodsExportExcel("苹果",new BigDecimal(10),100));
        data.add(new GoodsExportExcel("香蕉",new BigDecimal(8),200));
        try {
            //设置返回类型及编码类型
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //可以防止中文乱码,和easyExcel没有关系
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(System.currentTimeMillis() + ".xls" , StandardCharsets.UTF_8));
            //浏览器下载
            EasyExcel.write(response.getOutputStream(), GoodsExportExcel.class)
                    //文件类型
                    .excelType(ExcelTypeEnum.XLS)
                    //是否自动关闭流
                    .autoCloseStream(Boolean.TRUE)
                    //自动列宽(不太精确)
                    .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                    .sheet("商品信息")
                    .doWrite(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 本地下载
     * @param args
     */
    public static void main(String[] args) {
        // 存放路径
        String path = "D:/";
        // 文件名称
        String fileName = path + System.currentTimeMillis() + ".xls";
        //数据
        List<GoodsExportExcel> data = new ArrayList<>();
        data.add(new GoodsExportExcel("苹果",new BigDecimal(10),100));
        data.add(new GoodsExportExcel("香蕉",new BigDecimal(8),200));
        EasyExcel.write(fileName, GoodsExportExcel.class).sheet("商品信息").doWrite(data);
    }
}

在这里插入图片描述

第二种:复杂导出(合并、批注、自定义拦截、一级下拉框)

实体类

package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.math.BigDecimal;

@Data
public class GoodsExportExcel {

    @ExcelProperty(value = {"商品信息","商品名称"},index = 0)
    public String goodsName;

    @ExcelProperty(value = {"商品信息","商品价格"},index = 1)
    public BigDecimal price;

    @ExcelProperty(value = {"商品信息","商品数量"},index = 2)
    public Integer num;

    @ExcelProperty(value = {"商品信息","是否进口"},index = 3)
    public String inward;

    public GoodsExportExcel(String goodsName, BigDecimal price, Integer num) {
        this.goodsName = goodsName;
        this.price = price;
        this.num = num;
    }
}

合并规则

package com.example.mybatismysql8demo.handler;

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.RowWriteHandler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;

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

/**
 * excel导出数据内容单元格合并规则
 * @author Administrator
 */
@Slf4j
public class ExcelFileCellMergeStrategy implements CellWriteHandler, RowWriteHandler, SheetWriteHandler {
    /**
     * 合并列的范围索引
     */
    private int[] mergeColumnIndex;

    /**
     * 合并起始行索引
     */
    private int mergeRowIndex;

    /**
     * 合并校验列值
     */
    private int colIndex;

    /**下拉框数据*/
    private Map<Integer, String[]> mapDropDown;


    public ExcelFileCellMergeStrategy(int[] mergeColumnIndex, int mergeRowIndex, int colIndex, Map<Integer, String[]> mapDropDown) {
        this.mergeColumnIndex = mergeColumnIndex;
        this.mergeRowIndex = mergeRowIndex;
        this.colIndex = colIndex;
        this.mapDropDown = mapDropDown;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }


    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
        System.out.println("----------合并开始-----------");
        //当前行
        int curRowIndex = cell.getRowIndex();
        //当前列
        int curColIndex = cell.getColumnIndex();
        //某行开始合并
        if (curRowIndex > mergeRowIndex) {
            //判断每行的第一列是否相同,相同时进行合并
            if (isSame(cell, curRowIndex)) {
                for (int columnIndex : mergeColumnIndex) {
                    //对应的列进行合并
                    if (curColIndex == columnIndex) {
                        mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
                        break;
                    }
                }
            }
        }
        System.out.println("----------合并结束-----------");

        System.out.println("----------自定义拦截开始-----------");
        // 这里可以对cell进行任何操作
        log.info("第{}行,第{}列写入完成", cell.getRowIndex(), cell.getColumnIndex());
        if (aBoolean && cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) {
            CreationHelper createHelper = writeSheetHolder.getSheet().getWorkbook().getCreationHelper();
            Hyperlink hyperlink = createHelper.createHyperlink(HyperlinkType.URL);
            hyperlink.setAddress("https://github.com/alibaba/easyexcel");
            cell.setHyperlink(hyperlink);
        }
        System.out.println("----------自定义拦截结束-----------");
    }

    private Boolean isSame(Cell cell, int curRowIndex){
        //获取当前行的某列的数据
        Cell curCell = cell.getSheet().getRow(curRowIndex).getCell(colIndex);
        //当前行某列值
        Object curData = curCell.getCellTypeEnum() == CellType.STRING ? curCell.getStringCellValue() : curCell.getNumericCellValue();
        //获取当前行的上一行数据
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(colIndex);
        //上一行某列值
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        // 比较当前行的某列的单元格与上一行是否相同,相同合并当前单元格与上一行
        return curData.equals(preData);
    }


    /**
     * 当前单元格向上合并
     * @param writeSheetHolder
     * @param cell
     * @param curRowIndex
     * @param curColIndex
     */
    private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
        //获取当前行的当前列的数据和上一行的当前列数据,通过上一行数据是否相同进行合并
        Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
        Cell preCell = cell.getSheet().getRow(curRowIndex - 1 ).getCell(curColIndex);
        Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
        //比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
        if (curData.equals(preData)){
            Sheet sheet = writeSheetHolder.getSheet();
            List<CellRangeAddress> mergedRegions = sheet.getMergedRegions();
            boolean isMerged = false;
            for (int i = 0; i < mergedRegions.size() && !isMerged; i++) {
                CellRangeAddress cellAddresses = mergedRegions.get(i);
                //若上 一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                if (cellAddresses.isInRange(curRowIndex - 1 , curColIndex)){
                    sheet.removeMergedRegion(i);
                    cellAddresses.setLastRow(curRowIndex);
                    sheet.addMergedRegion(cellAddresses);
                    isMerged = true;
                }
            }
            //若上一个单元格未被合并,则新增合并单元
            if (!isMerged){
                CellRangeAddress cellAddresses = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
                sheet.addMergedRegion(cellAddresses);
            }
        }
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {
        //integer表示行数,给第二行添加批注
        if (BooleanUtils.isTrue(aBoolean) && integer == 1) {
            Sheet sheet = writeSheetHolder.getSheet();
            Drawing<?> drawingPatriarch = sheet.createDrawingPatriarch();
            ClientAnchor anchor = new HSSFClientAnchor();
            anchor.setCol1(1);
            anchor.setCol2(2);
            anchor.setRow1(0);
            anchor.setRow2(2);
            anchor.setDx1(0);
            anchor.setDy1(0);
            anchor.setDx2(0);
            anchor.setDy2(0);
            // 在第二行的第二列创建一个批注
            Comment comment = drawingPatriarch.createCellComment(anchor);
            // 输入批注信息
            comment.setString(new HSSFRichTextString("创建批注!"));
            // 将批注添加到第一行第一列单元格对象中
            sheet.getRow(0).getCell(0).setCellComment(comment);
        }
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        System.out.println("----下拉框---");
        Sheet sheet = writeSheetHolder.getSheet();
        ///开始设置下拉框
        DataValidationHelper helper = sheet.getDataValidationHelper();
        for (Map.Entry<Integer, String[]> entry : mapDropDown.entrySet()) {
            /*起始行、终止行、起始列、终止列**/
            CellRangeAddressList addressList = new CellRangeAddressList(2, 1000, entry.getKey(), entry.getKey());
            /*设置下拉框数据**/
            DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
            DataValidation dataValidation = helper.createValidation(constraint, addressList);
            sheet.addValidationData(dataValidation);
        }
        System.out.println("----下拉框结束---");
    }
}


执行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.example.mybatismysql8demo.excel.GoodsExportExcel;
import com.example.mybatismysql8demo.handler.ExcelFileCellMergeStrategy;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@RestController
public class EasyExcelController {

    @RequestMapping(value = "easyExcelExport", method = RequestMethod.GET)
    public void easyExcelExport(HttpServletResponse response) {
        //数据
        List<GoodsExportExcel> data = new ArrayList<>();
        data.add(new GoodsExportExcel("苹果",new BigDecimal(10),100));
        data.add(new GoodsExportExcel("苹果",new BigDecimal(9),50));
        data.add(new GoodsExportExcel("香蕉",new BigDecimal(8),200));
        try {
            //设置返回类型及编码类型
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //可以防止中文乱码,和easyExcel没有关系
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(System.currentTimeMillis() + ".xls" , StandardCharsets.UTF_8));
            //需要合并的索引列(列从0开始)
            int[] mergeColIndex = {0};
            //需要从第二行开始,列头第一行
            int mergeRowIndex = 2;
            //设置当某列值相同才合并(列从0开始)
            int colIndex = 0;
            //下拉框值设置(实际运用在模版下载)
            String[] yesOrNo = new String[]{"是", "否"};
            Map<Integer, String[]> mapDropDown = new HashMap<>(1);
            //3表示实体类中的index值对应
            mapDropDown.put(3, yesOrNo);
            //浏览器下载
            EasyExcel.write(response.getOutputStream(), GoodsExportExcel.class)
                        //文件类型
                        .excelType(ExcelTypeEnum.XLS)
                        //是否自动关闭流
                        .autoCloseStream(Boolean.TRUE)
                        //设置批注
                        .inMemory(Boolean.TRUE)
                        //合并策略
                        .registerWriteHandler(new ExcelFileCellMergeStrategy(mergeColIndex, mergeRowIndex,colIndex,mapDropDown))
                        //自动列宽(不太精确)
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .sheet("商品信息")
                        .doWrite(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

在这里插入图片描述

第三种:样式导出

  • 忽视无注解的字段:@ExcelIgnoreUnannotated
  • 表头行高:@HeadRowHeight(35)
  • 数据列宽:@ColumnWidth(20)
  • 数据行高:@ContentRowHeight(30)
  • 头背景设置成红色 IndexedColors.RED.getIndex():@HeadStyle(fillPatternType =
    FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
  • 头字体设置成20:@HeadFontStyle(fontHeightInPoints = 20)
  • 内容的背景设置成绿色 IndexedColors.GREEN.getIndex():@ContentStyle(fillPatternType =
    FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)
  • 内容字体设置成20:@ContentFontStyle(fontHeightInPoints = 20)
  • 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex():@HeadStyle(fillPatternType =
    FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)
  • 字符串的头字体设置成20:@HeadFontStyle(fontHeightInPoints = 30)
  • 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex():@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)
  • 字符串的内容字体设置成20:@ContentFontStyle(fontHeightInPoints = 30)
    在这里插入图片描述
    实体类
package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import lombok.Data;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;

import java.math.BigDecimal;

@Data
//忽视无注解的字段
@ExcelIgnoreUnannotated
/*表头行高*/
@HeadRowHeight(35)
/*数据列宽*/
@ColumnWidth(20)
/*数据行高*/
@ContentRowHeight(30)
// 头字体设置成20
@HeadFontStyle(fontHeightInPoints = 20)
// 头背景设置成黄色 IndexedColors.YELLOW.getIndex()
@HeadStyle(fillForegroundColor = 27, horizontalAlignment= HorizontalAlignment.CENTER)
// 内容的背景设置成粉色 IndexedColors.PINK.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND,fillForegroundColor = 14, horizontalAlignment= HorizontalAlignment.CENTER,borderBottom = BorderStyle.THIN,borderLeft = BorderStyle.THIN)
// 内容字体设置成16
@ContentFontStyle(fontHeightInPoints = 16)
public class GoodsExportExcel {

    @ExcelProperty(value = {"商品信息","商品名称"},index = 0)
    public String goodsName;

    @ExcelProperty(value = {"商品信息","商品价格"},index = 1)
    public BigDecimal price;

    @ExcelProperty(value = {"商品信息","商品数量"},index = 2)
    public Integer num;

    @ExcelProperty(value = {"商品信息","是否进口"},index = 3)
    public String inward;

    /**列标题样式*/
    @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
    /**字体样式*/
    @ContentFontStyle(fontHeightInPoints = 11,color = 10)
    @ColumnWidth(30)
    @ExcelProperty(value = {"商品信息","错误信息"},index = 4)
    private String errorMsg;

    private String ignore;

    public GoodsExportExcel(String goodsName, BigDecimal price, Integer num) {
        this.goodsName = goodsName;
        this.price = price;
        this.num = num;
    }
}

执行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.example.mybatismysql8demo.excel.GoodsExportExcel;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@RestController
public class EasyExcelController {

    @RequestMapping(value = "easyExcelExport", method = RequestMethod.GET)
    public void easyExcelExport(HttpServletResponse response) {
        //数据
        List<GoodsExportExcel> data = new ArrayList<>();
        data.add(new GoodsExportExcel("苹果",new BigDecimal(10),100));
        data.add(new GoodsExportExcel("苹果",new BigDecimal(9),50));
        data.add(new GoodsExportExcel("香蕉",new BigDecimal(8),200));
        try {
            //设置返回类型及编码类型
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //可以防止中文乱码,和easyExcel没有关系
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(System.currentTimeMillis() + ".xls" , StandardCharsets.UTF_8));
            //表头样式
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置表头居中对齐
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            //内容样式
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置内容靠左对齐
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
            //浏览器下载
            EasyExcel.write(response.getOutputStream(), GoodsExportExcel.class)
                        //文件类型
                        .excelType(ExcelTypeEnum.XLS)
                        //是否自动关闭流
                        .autoCloseStream(Boolean.TRUE)
                        //自动列宽(不太精确)
                        .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        //设置样式
                        .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle))
                        .sheet("商品信息")
                        .doWrite(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

在这里插入图片描述

第四种:多级下拉框导出

实体类

package com.example.mybatismysql8demo.excel;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
public class CityInfo {

    @ExcelProperty(value = "名称",index = 0)
    private String name;

    @ExcelProperty(value = "省",index = 1)
    private String province;

    @ExcelProperty(value = "市",index = 2)
    private String city;

    @ExcelProperty(value = "区",index = 3)
    private String area;

}

多级下拉框配置

package com.example.mybatismysql8demo.config;

import cn.hutool.core.collection.CollectionUtil;
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 org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;

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

public class SpinnerWriteHandler implements SheetWriteHandler {

    /**
     * 多级分类值
     */
    private Map<Integer, Object> dropDown;

    /**
     * 一级分类值
     */
    private Map<Integer, String[]> oneDropDown;

    /**
     * 一级分类名称
     */
    private List<String> firstLevel;

    /**
     * 父级分类名称:一级与二级分类名称
     */
    private List<String> secondLevel;

    /**
     * 父级对应的子类
     */
    private Map<String, List<String>> thirdLevel;

    /**
     * 开始行填充下拉框值
     */
    private Integer rowIndex;


    public SpinnerWriteHandler(Map<Integer, Object> dropDown, Map<Integer, String[]> oneDropDown,Integer rowIndex) {
        this.dropDown = dropDown;
        this.oneDropDown = oneDropDown;
        this.rowIndex = rowIndex;
    }

    public SpinnerWriteHandler(Map<Integer, Object> dropDown,Integer rowIndex) {
        this.dropDown = dropDown;
        this.rowIndex = rowIndex;
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        //多级下拉框
        if (dropDown != null) {
            Sheet sheet = writeSheetHolder.getSheet();
            ///开始设置下拉框
            DataValidationHelper helper = sheet.getDataValidationHelper();
            //设置数据有效性和添加名称管理器
            Workbook workbook = writeWorkbookHolder.getWorkbook();
            for (Map.Entry<Integer, Object> entry : dropDown.entrySet()) {
                //多级分类
                Map<String, Object> values = (Map<String, Object>) entry.getValue();
                firstLevel = (List<String>) values.get("firstLevel");
                secondLevel = (List<String>) values.get("secondLevel");
                thirdLevel = (Map<String, List<String>>) values.get("thirdLevel");
                twoDownList(workbook, helper, sheet, entry.getKey());
            }
        }
        //一级分类
        if (oneDropDown != null) {
            oneDownList(writeSheetHolder);
        }
    }


    public void twoDownList(Workbook workbook, DataValidationHelper helper, Sheet sheet, Integer index) {
        Sheet hideSheet = workbook.createSheet("category");
        int rowId = 0;
        //一级数据填充
        Row provinceRow = hideSheet.createRow(rowId++);
        provinceRow.createCell(0).setCellValue("省列表");
        for (int i = 0; i < firstLevel.size(); i++) {
            //设置列
            Cell provinceCell = provinceRow.createCell(i + 1);
            //列对应的值
            provinceCell.setCellValue(firstLevel.get(i));
        }
        // 二级数据填充,将具体的数据写入到每一行中,行开头为父级区域,后面是子区域。二级与三级分类
        for (String key : secondLevel) {
            List<String> son = thirdLevel.get(key);
            //判空
            if (CollectionUtil.isNotEmpty(son)){
                Row row = hideSheet.createRow(rowId++);
                row.createCell(0).setCellValue(key);
                for (int j = 0; j < son.size(); j++) {
                    Cell cell = row.createCell(j + 1);
                    cell.setCellValue(son.get(j));
                }
                // 添加名称管理器
                String range = getRange(1, rowId, son.size());
                Name name = workbook.createName();
                //key不可重复
                //判断key是否包含特殊符号
                name.setNameName(key);
                String formula = "category!" + range;
                name.setRefersToFormula(formula);
            }
        }
        //起始行、终止行、起始列、终止列
        CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, 1000, index, index);
        //设置下拉框数据
        DataValidationConstraint constraint = helper.createExplicitListConstraint(firstLevel.toArray(new String[]{}));
        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        //处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        sheet.addValidationData(dataValidation);
        //对1000行设置有效性:i表示从第几行开始下标为1开始计算
        for (int i = rowIndex; i < Integer.sum(1000,rowIndex); i++) {
            //offset表示一级关联对应的坐标值,colNum表示当前级的子级列值,下标从1开始算
            //setDataValidation("C" ,sheetPro,i,4);
            setDataValidation(indexToColumn(index + 1), (SXSSFSheet) sheet, i, index + 2);
            //offset表示二级关联对应的坐标值,colNum表示当前级的子级列值,下标从1开始算
            //setDataValidation("D" ,sheetPro,i,5);
            setDataValidation(indexToColumn(index + 2), (SXSSFSheet) sheet, i, index + 3);
        }
    }


    /**
     * 将excel表格中列索引转成列号字母,从A对应1开始
     */
    private static String indexToColumn(int index) {
        if (index <= 0) {
            try {
                throw new Exception("Invalid parameter");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        index--;
        StringBuilder column = new StringBuilder();
        do {
            if (column.length() > 0) {
                index--;
            }
            column.insert(0, ((char) (index % 26 + (int) 'A')));
            index = (int) ((index - index % 26) / 26);
        } while (index > 0);

        return column.toString();
    }


    //一级下拉框
    public void oneDownList(WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        ///开始设置下拉框
        DataValidationHelper helper = sheet.getDataValidationHelper();
        for (Map.Entry<Integer, String[]> entry : oneDropDown.entrySet()) {
            /*起始行、终止行、起始列、终止列**/
            CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, 1000, entry.getKey(), entry.getKey());
            /*设置下拉框数据**/
            DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
            DataValidation dataValidation = helper.createValidation(constraint, addressList);
            /*处理Excel兼容性问题**/
            if (dataValidation instanceof XSSFDataValidation) {
                dataValidation.setSuppressDropDownArrow(true);
                dataValidation.setShowErrorBox(true);
            } else {
                dataValidation.setSuppressDropDownArrow(false);
            }
            sheet.addValidationData(dataValidation);
        }

    }


    /**
     * 设置有效性
     *
     * @param offset 主影响单元格所在列,即此单元格由哪个单元格影响联动
     * @param sheet
     * @param rowNum 行数
     * @param colNum 列数
     */
    public static void setDataValidation(String offset, SXSSFSheet sheet, int rowNum, int colNum) {
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidation dataValidationList;
        dataValidationList = getDataValidationByFormula("INDIRECT($" + offset + (rowNum) + ")", rowNum, colNum, (XSSFDataValidationHelper) helper);
        sheet.addValidationData(dataValidationList);
    }


    /**
     * 加载下拉列表内容
     *
     * @param formulaString
     * @param naturalRowIndex
     * @param naturalColumnIndex
     * @param dvHelper
     * @return
     */
    private static DataValidation getDataValidationByFormula(String formulaString, int naturalRowIndex, int naturalColumnIndex, XSSFDataValidationHelper dvHelper) {
        /*   加载下拉列表内容
         *   举例:若formulaString = "INDIRECT($A$2)" 表示规则数据会从名称管理器中获取key与单元格 A2 值相同的数据,
         *   如果A2是江苏省,那么此处就是江苏省下的市信息。
         */
        DataValidationConstraint dvConstraint = dvHelper.createFormulaListConstraint(formulaString);
        // 设置数据有效性加载在哪个单元格上。四个参数分别是:起始行、终止行、起始列、终止列
        int firstRow = naturalRowIndex - 1;
        int lastRow = naturalRowIndex - 1;
        int firstCol = naturalColumnIndex - 1;
        int lastCol = naturalColumnIndex - 1;
        CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
        // 数据有效性对象
        XSSFDataValidation dataValidationList = (XSSFDataValidation) dvHelper.createValidation(dvConstraint, regions);
        dataValidationList.setEmptyCellAllowed(false);
        // 设置输入信息提示信息
        dataValidationList.createPromptBox("下拉选择提示", "请使用下拉方式选择合适的值!");
        // 设置输入错误提示信息
        dataValidationList.createErrorBox("选择错误提示", "你输入的值未在备选列表中,请下拉选择合适的值!");
        return dataValidationList;
    }


    /**
     * 计算formula
     * @param offset   偏移量,如果给0,表示从A列开始,1,就是从B列
     * @param rowId    第几行
     * @param colCount 一共多少列
     * @return 如果给入参 1,1,10. 表示从B1-K1。最终返回 $B$1:$K$1
     */
    private static String getRange(int offset, int rowId, int colCount) {
        char start = (char) ('A' + offset);
        if (colCount <= 25) {
            char end = (char) (start + colCount - 1);
            return "$" + start + "$" + rowId + ":$" + end + "$" + rowId;
        } else {
            char endPrefix = 'A';
            char endSuffix = 'A';
            // 26-51之间,包括边界(仅两次字母表计算)
            if ((colCount - 25) / 26 == 0 || colCount == 51) {
                // 边界值
                if ((colCount - 25) % 26 == 0) {
                    endSuffix = (char) ('A' + 25);
                } else {
                    endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);
                }
            } else {// 51以上
                if ((colCount - 25) % 26 == 0) {
                    endSuffix = (char) ('A' + 25);
                    endPrefix = (char) (endPrefix + (colCount - 25) / 26 - 1);
                } else {
                    endSuffix = (char) ('A' + (colCount - 25) % 26 - 1);
                    endPrefix = (char) (endPrefix + (colCount - 25) / 26);
                }
            }
            return "$" + start + "$" + rowId + ":$" + endPrefix + endSuffix + "$" + rowId;
        }
    }

}

执行方法

package com.example.mybatismysql8demo.controller;

import com.alibaba.excel.EasyExcel;
import com.example.mybatismysql8demo.config.SpinnerWriteHandler;
import com.example.mybatismysql8demo.excel.CityInfo;
import com.example.mybatismysql8demo.excel.GoodsExportExcel;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;

@RestController
public class EasyExcelController {

    @RequestMapping(value = "easyExcelExport", method = RequestMethod.GET)
    public void easyExcelExport(HttpServletResponse response) {
        try {
            //一级下拉框
            Map<Integer, String[]> mapDropDown = new HashMap<>(1);
            mapDropDown.put(0, new String[]{"小明","小红"});
            //多级下拉框
            Map<Integer,Object> mapAll = new LinkedHashMap<>();
            //一级数据
            List<String> firstLevel = Arrays.asList("江西省", "河南省");
            //一、二级数据名称
            List<String> secondLevel = Arrays.asList("江西省", "南昌市", "抚州市", "河南省", "周口市");
            //父级对应的子级数据
            Map<String,List<String>> thirdLevel = new LinkedHashMap<>();
            //依次列出各省的市、各市的县(对应级下的子级数据)
            thirdLevel.put("江西省", Arrays.asList("南昌市", "抚州市"));
            thirdLevel.put("河南省",Collections.singletonList("周口市"));
            thirdLevel.put("南昌市",Arrays.asList("东湖区","西湖区"));
            thirdLevel.put("抚州市",Arrays.asList("临川区","崇仁区"));
            thirdLevel.put("周口市",Arrays.asList("川汇区","扶沟县"));
            Map<String,Object> categoryMap = new HashMap<String,Object>(4);
            categoryMap.put("firstLevel",firstLevel);
            categoryMap.put("secondLevel",secondLevel);
            categoryMap.put("thirdLevel",thirdLevel);
            //1表示一级分类字段下标(1-3都是联动的)
            mapAll.put(1,categoryMap);
            //告诉浏览器数据格式,将头和数据传到前台
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" +  URLEncoder.encode("地区信息表.xls", "UTF-8"));
            EasyExcel.write(response.getOutputStream(), CityInfo.class)
                    .autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(new SpinnerWriteHandler(mapAll,mapDropDown,1))
                    .sheet("地区信息")
                    .doWrite(Collections.EMPTY_LIST);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

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

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

相关文章

(二十一)C++自制植物大战僵尸游戏僵尸游戏关卡结束数据处理

植物大战僵尸游戏开发教程专栏地址http://t.csdnimg.cn/8UFMs 文件位置 代码实现的文件在Class\Scenes\GameScene文件夹中,如下图所示。 GameEndLayer.h class GSGameEndLayer :public LayerColor { public:CREATE_FUNC(GSGameEndLayer);void successfullEntry();void brea…

我的博客系统自动化测试设计

我的博客系统测试设计 一、项目描述二、项目功能描述三、测试计划1、功能测试1.1 测试用例1.2 测试步骤 一、项目描述 1、采用前后端分离的来实现我的博客系统&#xff0c;使用MySQL 数据库存储用户和博客信息。   2、前端页面包含用户注册、登录、我的博客列表页、博客主页面…

Linux(文件系统和日志分析)

1.inode & block 1.1 inode的内容 stat 文件名&#xff1a; 查看文件的元信息 df -i&#xff1a;查看每个分区的inode数量 [rootlocalhost ~]# df -i 文件系统 Inode 已用(I) 可用(I) 已用(I)% 挂载点 devtmpfs 478387 382 4…

03-JAVA设计模式-策略模式

策略模式 什么是策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是行为设计模式之一&#xff0c;它使你能在运行时改变对象的行为。在策略模式中&#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。 在策略模式中&#xff0c;…

C# winfrom 超详细UI创建过程 实现双色球选号器UI界面设计过程

一、 效果展示 1. 无点击效果展示&#xff1a;不选中——双色球为灰色&#xff0c;字体也为灰色 2.点击双色器效果展示&#xff1a;选中——双色球为红或者蓝&#xff0c;字体为白色 二、 使用控件标注说明 三、界面特点介绍 双色球代码控制生成---------由于红色33个球&…

Linux内核广泛采用的侵入式数据结构设计

Linux内核广泛采用的侵入式数据结构设计恐怕很难应用到一般程序开发中。基本上是个高维十字链表&#xff0c;一个节点(struct)可以同时位于多个hash/list/tree中。我分享下我的经历&#xff0c;我刚入行时遇到一个好公司和师父&#xff0c;给了我机会&#xff0c;一年时间从3k薪…

【网络原理】IP协议的地址管理和路由选择

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

Arthas:阿里出品,线上问题快速搞定!

前面我们通过JVM线程分析及内存分析来让大家从服务器资源异常情况下排查代码问题&#xff0c;类似这种的解决方式&#xff0c;更多的是在服务器资源占用已经异常显现&#xff0c;我们就可以按照这种方式去排查和解决。 但实际工作中&#xff0c;可能会出现&#xff1a;接口的TP…

什么是网络安全CTF?

什么是网络安全CTF? CTF 的意义&#xff1a; 如何入门 CTF&#xff1a; 推荐的在线 CTF 平台&#xff1a; 什么是网络安全CTF? CTF (Capture The Flag) 是一种网络安全竞赛&#xff0c;参赛者需要解决各种安全挑战&#xff0c;例如破解密码、利用漏洞、分析恶意软件等&am…

二极管钳位型光伏逆变并网建模simulink仿真

整理了二极管钳位型光伏逆变并网建模simulink仿真&#xff0c;效果明显&#xff0c;附赠仿真报告。适合小白 二极管钳位型光伏逆变并网是将光伏发电系统中的直流电能转换为交流电能&#xff0c;并与电网连接。在此仿真中使用最大功率点追踪&#xff08;MPPT&#xff09;技术&a…

【C语言】编译与链接

1.翻译环境与运行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 1.翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令&#xff08;二进制指令&#xff09; 2.执行环境&#xff0c;它用于实际执行代码 2.翻译环境 那么翻译环境是怎么将源代码…

【Docker】docker部署lnmp和wordpress网站

环境准备 docker&#xff1a;192.168.67.30 虚拟机&#xff1a;4核4G systemctl stop firewalld systemctl disable firewalld setenforce 0 安装docker #安装依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 #设置阿里云镜像 yum-config-manager --add…

vue3学习笔记-快速上手

创建第一个vue3的应用 之前看书学习vue,书籍对应的版本是vue2,今天群里看小伙伴聊天&#xff0c;觉得他们说得对 &#xff0c;反正是从零开始学&#xff0c;而且vue2都不维护了&#xff0c;那为什么不直接学习vue3呢&#xff0c;于是乎&#xff0c;又开启了从0学vue3之路。 参考…

Linux之进程间通信(二)

system V system V共享内存是内核中专门设计的通信的方式, 粗粒度划分操作系统分为进程管理, 内存管理, 文件系统, 驱动管理.., 粒度更细地分还有 进程间通信模块. 对于操作系统, 通信的场景有很多, 有以传送数据, 快速传送数据, 传送特定数据块, 进程间协同与控制以目的, 它…

一键设置jdk环境脚本

自动化脚本 一、使用方法 创建一个txt文本&#xff0c;放在和jdk存放的同一目录下&#xff0c;复制粘贴进我的代码&#xff0c;利用全局替换&#xff0c;将jdk1.8,改成你自己的jdk包名字&#xff0c;再重新把这个文件保存为.vbs文件。然后运行就行了 MsgBox "Runing s…

线上社交app的搭建,圈子社交系统,小程序+app+H5三端,源码交付,支持二开!

在科技飞速发展的大背景下&#xff0c;年轻人社交不再局限于面对面&#xff0c;线上社交app已深入各大年轻人的手机中。相比于传统交友方式&#xff0c;线上社交app为用户提供了更加新奇的交友体验。同时&#xff0c;它还可以吸引更多的朋友&#xff0c;提高用户的整体交友体验…

第4篇:创建Nios II工程之Hello_World<三>

Q&#xff1a;接着我们再来完成Nios II软件工程设计部分。 A&#xff1a;从Quartus Tools选择Nios II Software Build Tools for Eclipse&#xff0c;打开Nios II SBT软件&#xff0c;Workspace指定到hello_world工程的software文件夹路径&#xff1b;再从File-->New-->…

Java学习13

目录 一.内部类: 1.概念&#xff1a; 2.内部类的分类&#xff1a; &#xff08;1&#xff09;定义在外部类的局部位置上&#xff08;通常在方法体中&#xff09;&#xff1a; 1. 局部内部类&#xff08;有类名&#xff09; 2.匿名内部类&#xff08;无类名-重点&#xff01;…

Linux 基础命令使用创建用户

浏览网站的时候图片&#xff0c;看到一个小练习。创建用户分别位于不同的用户组。 解答下面的题目 2、建立用户使用 useradd&#xff0c;设置密码使用passwd的命令。大概不会使用命令可以借助man来解答。 先建立用户组&#xff1a; groupadd group1 # group1 不存在先建立&…

Redis底层数据结构之ZSkipList

目录 一、概述二、ZSkipList结构三、和平衡树和哈希表的对比 redis底层数据结构已完结&#x1f44f;&#x1f44f;&#x1f44f;&#xff1a; ☑️redis底层数据结构之SDS☑️redis底层数据结构之ziplist☑️redis底层数据结构之quicklist☑️redis底层数据结构之Dict☑️redis…