easyExcel 导入、导出Excel 封装公共的方法

文档包含三部分功能

1、easyExcel 公共导出list<对象>方法
2、easyExcel 导入逻辑
3、easyExcel 自定义导出 list<map> 、 list<对象> (可优化)

1、easyExcel 公共导出方法

1)依赖:

<!-- hutool -->
<!-- 阿里开源的excel处理包 -->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>3.3.3</version>
</dependency>
<!-- poi -->
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>5.0.0</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>5.0.0</version>
</dependency>

 2)封装的公共导出方法:

# 其中 templateBool 代表第一行是否为标题行
# 其中 firstRowContent 代码第一行写入的内容
FileUtil.exportExcel(response, "导出应用表列表", "sheet1", App.class, appList, templateBool,firstRowContent);

其中 App.class 实体类属性添加 @ExcelIgnore 忽略导出,@ExcelProperty("*excel列明") 指出导出列表

@ExcelIgnore
@ExcelProperty("*excel列明")

导出代码参考 

easyExcel自定义导入头实现icon-default.png?t=N7T8https://www.cnblogs.com/Dog1363786601/p/17352096.html

3)实现easyExcel 导入导出依赖公共文件方法

import cn.hutool.core.codec.Base64;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;

import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.util.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 项目名称:base
 *
 * <p>功能: 功能描述。</p>
 *
 * @author:yht
 * @version:V1.0 2023/5/30
 */
@Slf4j
public class FileUtil {
    

    /**
     * 设置导出为excel 的 Response 中的描述
     *
     * @param response    响应结果对象
     * @param rawFileName 文件名
     */
    public static void setExcelResponse(HttpServletResponse response, String rawFileName) {
        //设置响应格式
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8"); // 设置字符编码
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = Base64.encode(rawFileName, Charset.defaultCharset());
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
    }

    /**
     * MultipartFile对象转成File对象
     *
     * @param multipartFile
     * @return
     */
    public static File transferToFile(MultipartFile multipartFile) {
//        选择用缓冲区来实现这个转换即使用java 创建的临时文件 使用 MultipartFile.transferto()方法 。
        File file = null;
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String[] filename = originalFilename.split("\\.");
            file = File.createTempFile(filename[0], filename[1] + ".");
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 断面数据导出Excel
     * <a href="https://www.cnblogs.com/Dog1363786601/p/17352096.html">EasyExcelSheetWriteHandler 参考:包含map导出样例</a>
     *
     * @param response:response
     * @param fileName:文件名
     * @param sheetName:sheet              页签名称
     * @param targetClass:目标对象Class
     * @param dateList:对象数据
     * @param firstRowDocBool:第一行是不是填写文档说明
     * @param firstRowContent:第一行的内容
     */
    public static void exportExcel(HttpServletResponse response, String fileName, String sheetName,
                                   Class<?> targetClass, List<?> dateList, Boolean firstRowDocBool, String firstRowContent) throws IOException {
        if (StrUtil.isBlank(fileName)) {
            //当前日期
            fileName = DateUtil.format(new DateTime(), DatePattern.CHINESE_DATE_TIME_FORMATTER);
        }

        setExcelResponse(response, fileName);

        // 设置表头字体样式
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12); // 设置字体大小为16
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex());

        // 设置表头 和内容样式
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, (List<WriteCellStyle>) null);

        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), targetClass)
                .registerWriteHandler(new EasyExcelSheetWriteHandler(firstRowDocBool, firstRowContent))
                .registerWriteHandler(horizontalCellStyleStrategy)
                .relativeHeadRowIndex(1)
                .excelType(ExcelTypeEnum.XLSX)
                .build();

        WriteSheet writeSheet = EasyExcel.writerSheet(0, sheetName).build();

        excelWriter.write(dateList, writeSheet);
        excelWriter.finish();
    }
}

 4)其中自定导入第一行 导入内容依赖类

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.CellRangeAddress;

public class EasyExcelSheetWriteHandler implements SheetWriteHandler {

    /**
     * 首行是否为文档
     */
    private final Boolean firstRowDocBool;

    /**
     * 填写文件说明
     */
    private final String firstRowContent;

    public EasyExcelSheetWriteHandler(Boolean firstRowDocBool, String firstRowContent) {
        this.firstRowDocBool = firstRowDocBool;
        this.firstRowContent = firstRowContent;
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        //Sheet sheet = workbook.getSheetAt(0);
        Sheet sheet = workbook.getSheet(writeSheetHolder.getSheetName());

        Row row1 = sheet.getRow(0);
        if (row1 == null) {
            row1 = sheet.createRow(0);
        }
        row1.setHeight((short) 500);//25*20   实际行高*20
        Cell cell1 = row1.getCell(0);
        if (cell1 == null) {
            cell1 = row1.createCell(0);
        }
        cell1.setCellValue(firstRowContent);

        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM);
        cellStyle.setFillBackgroundColor(IndexedColors.WHITE.getIndex());
        cellStyle.setBorderTop(BorderStyle.NONE);
        cellStyle.setBorderBottom(BorderStyle.NONE);
        cellStyle.setBorderLeft(BorderStyle.NONE);
        cellStyle.setBorderRight(BorderStyle.NONE);

        if (Boolean.TRUE.equals(firstRowDocBool)) {
            cellStyle.setAlignment(HorizontalAlignment.LEFT);
        } else {
            cellStyle.setAlignment(HorizontalAlignment.CENTER);
        }

        Font font = workbook.createFont();
        font.setBold(false);
        if (Boolean.TRUE.equals(firstRowDocBool)) {
            font.setFontName("宋体");
            font.setFontHeight((short) 220);//11*20   实际字号(字高)*20

        } else {
            font.setFontHeight((short) 360);//18*20   实际字号(字高)*20
            font.setFontName("黑体");
        }
        cellStyle.setFont(font);

        cell1.setCellStyle(cellStyle);
        sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, 15));
    }
}

2、easyExcel 导入逻辑

1)依赖于 fileutil,将  MultipartFile 转为file

File file = FileUtil.transferToFile(multipartFile);

2)拿到文件以后,导入实现逻辑如下 

EasyExcel.read(file, App.class, new ReadListener<App>() {
                        //临时存储数据对象
                        private final List<App> cachedDataList = ListUtils.newArrayList();

                        @Override
                        public void invoke(App data, AnalysisContext context) {
                            cachedDataList.add(data);
                        }

                        @Transactional
                        @Override
                        public void doAfterAllAnalysed(AnalysisContext context) {
                            StringBuffer errorCheckMsg = new StringBuffer();
                            AtomicBoolean isPass = new AtomicBoolean(true);

                            if (CollUtil.isEmpty(cachedDataList)) {
                                throw new CommonException("导入Excel列表为空");
                            }

                            //数据行是从第三行开始
                            AtomicInteger rowIndex = new AtomicInteger(3);
                            cachedDataList.forEach((app) -> {
                                //spring validator 验证每行数据是否合规
                                BindingResult result = new BeanPropertyBindingResult(app, "app");
                                validator.validate(app, result);
                                if (result.hasErrors()) {
                                    isPass.set(false);
                                    // 处理验证错误,例如返回错误消息
                                    errorCheckMsg.append("第").append(rowIndex).append("行:");
                                    StringBuilder sb = new StringBuilder();
                                    for (ObjectError error : result.getAllErrors()) {
                                        sb.append(error.getDefaultMessage()).append(";");
                                    }
                                    errorCheckMsg.append(sb).append("\n");
                                }
                                rowIndex.getAndIncrement();
                            });

                            if (isPass.get()) {
                                //mybatis 插入数据方法
                                saveBatch(cachedDataList);
                            }

                            if (!StrUtil.isEmpty(errorCheckMsg.toString())) {
                                throw new CommonException(errorCheckMsg.toString());
                            }
                        }
                    }).sheet()
                    .headRowNumber(2)//设置标题行的行号
                    .doRead();

3、easyExcel 自定义 list<map> 导出

1)导出工具类的使用

/**
     * 导出采购订单列表
     */
    @PreAuthorize("@ss.hasPermi('mes:ec:purorder:export')")
    @Log(title = "采购订单", businessType = BusinessType.EXPORT)
    @PostMapping("acsEnvMonitHis/export")
    public void export(BaseEntity baseEntity, HttpServletResponse response) throws IOException {
        String[][] headMap = {{"AA"}, {"BB"}
                , {"CC"}, {"DD"}};
        String[] dataStrMap = {"CC", "EE"};

        int[] witdhMap = {15, 20};
        List<Map<String, Object>> listDatas = 获取数据的service方法
        
        NoModelWriteData nmwDate = new NoModelWriteData();
        nmwDate.setFileName("历史生产数据");
        nmwDate.setHeadMap(headMap);
        nmwDate.setDataStrMap(dataStrMap);
        nmwDate.setWitdhArray(witdhMap);
        nmwDate.setDataList(listDatas);

        EasyExcelUtils.noModleExportExcel(nmwDate, response);
    }

2)依赖工具类:EasyExcelUtils

package com.hy.common.utils.poi;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.converters.ConverterKeyBuild;
import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.apache.poi.util.IOUtils;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class EasyExcelUtils {

    //不创建对象的导出
    public static void noModleExportExcel(@RequestBody NoModelWriteData data, HttpServletResponse response) throws IOException {

        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        OutputStream out = null;
        try {
            out = response.getOutputStream();
            // 这里需要设置不关闭流
            ExcelWriter excelWriter = EasyExcel.write(out).charset(StandardCharsets.UTF_8).build();

            SqlDateConverter converterSqlDate = new SqlDateConverter();
            excelWriter.writeContext().currentWriteHolder().converterMap().put(ConverterKeyBuild.buildKey(converterSqlDate.supportJavaTypeKey()), converterSqlDate);
            excelWriter.writeContext().currentWriteHolder().converterMap().put(ConverterKeyBuild.buildKey(converterSqlDate.supportJavaTypeKey(), converterSqlDate.supportExcelTypeKey()), converterSqlDate);

            ExcelWriterSheetBuilder writerSheetBuilder = EasyExcel.writerSheet();
            writerSheetBuilder.registerConverter(new SqlDateConverter());
            writerSheetBuilder.registerConverter(new SqlTimeConverter());
            if (ArrayUtil.isNotEmpty(data.getWitdhArray())) {
                writerSheetBuilder.registerWriteHandler(new ColumnWidthStyleStrategy(data.getWitdhArray()));
            }

            WriteSheet writeSheet = writerSheetBuilder.build();
            writeSheet.setHead(head(data.getHeadMap()));
            writeSheet.setSheetName(data.getFileName());

            excelWriter.write(dataList(data.getDataList(), data.getDataStrMap()), writeSheet);
            excelWriter.finish();
        } catch (Exception e) {
            throw e;
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    //创建对象的导出
    public <T> void simpleWrite(@RequestBody SimpleWriteData data, Class<T> clazz, HttpServletResponse response) throws IOException {
        // 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
        //response.setContentType("application/vnd.ms-excel");
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode(data.getFileName(), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), clazz).sheet(data.getFileName()).doWrite(data.getDataList());
    }

    //设置表头
    private static List<List<String>> head(String[][] headMap) {
        List<List<String>> list = new ArrayList<List<String>>();
        for (String[] headArray : headMap) {
            List<String> headList = new ArrayList<String>();
            for (String headStr : headArray) {
                headList.add(headStr);
            }
            list.add(headList);
        }
        return list;
    }

    //设置导出的数据内容
    private static List<List<Object>> dataList(List<Map<String, Object>> dataList, String[] dataStrMap) {
        List<List<Object>> list = new ArrayList<List<Object>>();
        for (Map<String, Object> map : dataList) {
            List<Object> data = new ArrayList<Object>();
            for (int i = 0; i < dataStrMap.length; i++) {
                data.add(map.get(dataStrMap[i]));
            }
            list.add(data);
        }
        return list;
    }
}

3)导出工具类、共依赖5个类,有不同作用,可根据实际情况删减

依赖3个类:2种参数,1个列宽策略

NoModelWriteData :导出数据,类型为List<MAP>
SimpleWriteData:导出数据,类型为List<对象>
ColumnWidthStyleStrategy:导出的列样式宽度策略

其中解决显示异常的数据类型依赖于2个类

SqlDateConverter :sqldate显示异常
SqlTimeConverter:sqltime显示异常
类1:NoModelWriteData :导出的第1种参数
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class NoModelWriteData implements Serializable {
    /** 文件名 **/
    private String fileName;
    /** 表头数组 **/
    private String[][] headMap;
    /** 对应数据字段数组 **/
    private String[] dataStrMap;
    /** 列宽数组 **/
    private int[] witdhArray;

    /** 数据集合 **/
    private List<Map<String, Object>> dataList;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String[][] getHeadMap() {
        return headMap;
    }

    public void setHeadMap(String[][] headMap) {
        this.headMap = headMap;
    }

    public String[] getDataStrMap() {
        return dataStrMap;
    }

    public void setDataStrMap(String[] dataStrMap) {
        this.dataStrMap = dataStrMap;
    }

    public int[] getWitdhArray() {
        return witdhArray;
    }

    public void setWitdhArray(int[] witdhArray) {
        this.witdhArray = witdhArray;
    }

    public List<Map<String, Object>> getDataList() {
        return dataList;
    }

    public void setDataList(List<Map<String, Object>> dataList) {
        this.dataList = dataList;
    }

    @Override
    public String toString() {
        return "NoModelWriteData{" +
                "fileName='" + fileName + '\'' +
                ", headMap=" + Arrays.toString(headMap) +
                ", dataStrMap=" + Arrays.toString(dataStrMap) +
                ", witdhArray=" + Arrays.toString(witdhArray) +
                ", dataList=" + dataList +
                '}';
    }
}
类2:SimpleWriteData,导出的第2种参数
import java.io.Serializable;
import java.util.List;

public class SimpleWriteData implements Serializable {
    /** 文件名 **/
    private String fileName;
    /** 数据列表 **/
    private List<?> dataList;

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public List<?> getDataList() {
        return dataList;
    }

    public void setDataList(List<?> dataList) {
        this.dataList = dataList;
    }

    @Override
    public String toString() {
        return "SimpleWriteData{" +
                "fileName='" + fileName + '\'' +
                ", dataList=" + dataList +
                '}';
    }
}
 类3:ColumnWidthStyleStrategy :列宽度策略设置
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy;

import java.util.HashMap;
import java.util.Map;

public class ColumnWidthStyleStrategy extends AbstractHeadColumnWidthStyleStrategy {

    private Map<Integer,Integer> columnWidth = new HashMap<>();

    public ColumnWidthStyleStrategy() {
    }

    public ColumnWidthStyleStrategy(int[] widthArray) {
        for (int i = 0; i < widthArray.length; i++) {
            columnWidth.put(i,widthArray[i]);
        }
    }

    @Override
    protected Integer columnWidth(Head head, Integer columnIndex) {
        return columnWidth.getOrDefault(columnIndex,25);
    }
}
 类四:SqlDateConverter:为了 sql.date 类型在excel中显示正常
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.math.BigDecimal;
import java.sql.Date;
import java.text.ParseException;

/**
 * Date and string converter
 *
 * @author Jiaju Zhuang
 */
public class SqlDateConverter implements Converter<Date> {
    @Override
    public Class<?> supportJavaTypeKey() {
        return Date.class;
    }

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

    @Override
    public Date convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) throws ParseException {
        switch (cellData.getType()) {
            case NUMBER:
                BigDecimal numberValue = cellData.getNumberValue();
                return new Date(numberValue.longValue());
            case STRING:
                String stringValue = cellData.getStringValue();
                if (StrUtil.isBlank(stringValue) || "NA".equals(stringValue)) {
                    return null;
                }
                try {
                    return new Date(DateUtil.parse(cellData.getStringValue()).getTime());
                } catch (NumberFormatException e) {
                    return null;
                }
            default:
                return null;
        }
    }

    @Override
    public WriteCellData<?> convertToExcelData(Date value, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
            return new WriteCellData<>(DateUtil.formatDate(value));
        } else {
            return new WriteCellData<>(DateUtil.format(value, contentProperty.getDateTimeFormatProperty().getFormat()));
        }
    }
}
类五:SqlTimeConverter :为了 sql.time 类型在excel中显示正常
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.math.BigDecimal;
import java.sql.Time;
import java.text.ParseException;

/**
 * Date and string converter
 *
 * @author Jiaju Zhuang
 */
public class SqlTimeConverter implements Converter<Time> {
    @Override
    public Class<?> supportJavaTypeKey() {
        return Time.class;
    }

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

    @Override
    public Time convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) throws ParseException {
        switch (cellData.getType()) {
            case NUMBER:
                BigDecimal numberValue = cellData.getNumberValue();
                return new Time(numberValue.longValue());
            case STRING:
                String stringValue = cellData.getStringValue();
                if (StrUtil.isBlank(stringValue) || "NA".equals(stringValue)) {
                    return null;
                }
                try {
                    return new Time(DateUtil.parseTime(cellData.getStringValue()).getTime());
                } catch (NumberFormatException e) {
                    return null;
                }
            default:
                return null;
        }
    }

    @Override
    public WriteCellData<?> convertToExcelData(Time value, ExcelContentProperty contentProperty,
        GlobalConfiguration globalConfiguration) {
        if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
            return new WriteCellData<>(DateUtil.formatTime(value));
        } else {
            return new WriteCellData<>(DateUtil.format(value, contentProperty.getDateTimeFormatProperty().getFormat()));
        }
    }
}

相关推荐

  1. Excel 导入导出封装

    2024-03-13 05:30:04       37 阅读
  2. EasyExcel导入导出使用

    2024-03-13 05:30:04       47 阅读
  3. springboot使用EasyExcel实现Excel导入导出

    2024-03-13 05:30:04       37 阅读
  4. 通过easyExcel实现表格导入导出

    2024-03-13 05:30:04       70 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-13 05:30:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-13 05:30:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-13 05:30:04       82 阅读
  4. Python语言-面向对象

    2024-03-13 05:30:04       91 阅读

热门阅读

  1. MongoDB

    MongoDB

    2024-03-13 05:30:04      44 阅读
  2. GITLAB - CI 常用语法小记

    2024-03-13 05:30:04       42 阅读
  3. python中的四大内置容器

    2024-03-13 05:30:04       44 阅读
  4. MongoDB聚合运算符:$documentNumber

    2024-03-13 05:30:04       38 阅读
  5. Apache Tomcat环境搭建

    2024-03-13 05:30:04       44 阅读
  6. docker直接下载太慢,更换国内靠谱镜像源

    2024-03-13 05:30:04       37 阅读
  7. vue双向绑定/小程序双向绑定?

    2024-03-13 05:30:04       43 阅读