POI Excel读取图片对应位置和顺序生成图片方法

本文介绍使用Apache POI库实现Excel文件中图片的读取与写入操作,涵盖不同Excel版本的兼容处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

POI EXCEL 03 07 版本图片读取 和写入 操作

        <!-- maven poi 引用包-->
       <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
package rainJob.com.exercise;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;
import org.junit.jupiter.api.Test;

import java.io.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @auth xiaoyu
 * @desciption 利用poi  读取 写出图片操作。
 * @Date 13:13 2018/5/25
 */
public class PoiExercise {

    @Test
    public void mergerData() throws IOException, InvalidFormatException {
        //读取文件地址
        File file = new File("C:\\Users\\lenovo\\Desktop\\test.xls");
        //最终返回值
        LinkedList<LinkedHashMap<String, Object>> linkedHashMaps = new LinkedList<>();
        //为了给03版本赋值
        InputStream inputStream = new FileInputStream(file);
        Workbook workbook = null;
        if (file.getName().matches(".xlsx")) {
            //获取工作簿
            workbook = new XSSFWorkbook(file);
        } else {
            workbook = new HSSFWorkbook(inputStream);
        }
        //这里可以写成fori形式,因为我是测试的demo 所以下标就为0了
        Sheet sheetAt = workbook.getSheetAt(0);
        //一行可能有多组图片。picture方法获取指定行 列 和图片二进制数组。
        Map<Integer, Map<Integer, byte[]>> picture = picture(sheetAt);
        //获取文本行。我觉得就只是CellTypeEnum 枚举里的这些才会读到
        int physicalNumberOfRows = sheetAt.getLastRowNum();
        //记录第一行为表头
        LinkedList<String> fieldName = new LinkedList<>();
        //获取第一行信息
        Row row1 = sheetAt.getRow(0);
        int lastCellNum = row1.getPhysicalNumberOfCells();
        for (int i = 0; i < lastCellNum; i++) {
            fieldName.add(i, row1.getCell(i).getStringCellValue());
        }
        //从第二行开始,获取信息
        for (int i = 1; i <= physicalNumberOfRows; i++) {
            Row row = sheetAt.getRow(i);
            //只能获取CellTypeEnum 枚举里的这些才会读到
            int lastCell = row.getPhysicalNumberOfCells();
            //记录一行的value值
            LinkedHashMap<String, Object> rowValue = new LinkedHashMap<>();
            for (int j = 0; j < lastCell; j++) {
                String name = fieldName.get(j);
                Cell cell = row.getCell(j);
                if (cell == null) continue;
                //进行拿到结果值
                Object cellValue = getObject(cell);
                rowValue.put(name, cellValue);
            }
            linkedHashMaps.add(rowValue);
        }
        //为了防止文本行没有数据 光有图片的情况
        if (!picture.isEmpty()) {
            picture.forEach((k, v) -> {
                LinkedHashMap<String, Object> stringObjectLinkedHashMap = null;
                //如果我这个行有文本对应就为true 没有就是false
                boolean fal = false;
                if ((k - 1) >= linkedHashMaps.size()) {
                    stringObjectLinkedHashMap = new LinkedHashMap<>();
                } else {
                    fal = true;
                    stringObjectLinkedHashMap = linkedHashMaps.get(k - 1);
                }
                LinkedHashMap<String, Object> finalStringObjectLinkedHashMap = stringObjectLinkedHashMap;
                if (!v.isEmpty()) {
                    v.forEach((key, val) -> {
                        String name = fieldName.get(key);
                        int cellLength = finalStringObjectLinkedHashMap.keySet().toArray().length;
                        //对应图片的位置进行赋值。
                        if (key >= cellLength) {
                            for (int i = cellLength; i < key; i++) {
                                finalStringObjectLinkedHashMap.put(fieldName.get(i), null);
                            }
                        }
                        finalStringObjectLinkedHashMap.put(name, val);
                    });
                    if (fal) {
                        linkedHashMaps.remove(k - 1);
                        if ((k - 1) > linkedHashMaps.size()) {
                            linkedHashMaps.add(finalStringObjectLinkedHashMap);
                        } else linkedHashMaps.add((k - 1), finalStringObjectLinkedHashMap);
                    } else {
                        //如果不存在文本行直接后面追加。没生成空行。也可以你们想生成就生成。
                        linkedHashMaps.add(finalStringObjectLinkedHashMap);
                    }
                }
            });
        }
        //进行写出。为了节省造数据格式问题。
        writePicture(fieldName, linkedHashMaps);
    }

    /**
     * 判断cell的枚举 并对应处理成一个Object对象
     *
     * @param cell
     * @return
     */
    private Object getObject(Cell cell) {
        Object cellValue = null;
        switch (cell.getCellTypeEnum()) {
            case _NONE:
                cellValue = null;
                break;
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    if (cell.getNumericCellValue() < 1) {
                    } else {
                        //判断字段类型是时间还是日期
                        SimpleDateFormat sdf = null;
                        String dateValue = DateUtil.getJavaDate(cell.getNumericCellValue()).toString();
                        //判断时间类型还是日期类型。
                        boolean matches = dateValue.matches(".*00:00:00.*");
                        if (matches) {
                            sdf = new SimpleDateFormat("yyyy-MM-dd");
                        } else {
                            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        }
                        cellValue = sdf.format(DateUtil.getJavaDate(cell.getNumericCellValue()));
                    }
                } else {
                    //数字转化
                    cellValue = String.valueOf(cell.getNumericCellValue());
                    cellValue = new BigDecimal(cellValue.toString());
                    BigDecimal bigDecimal = ((BigDecimal) cellValue).stripTrailingZeros();
                    cellValue = bigDecimal.toPlainString();
                }
                break;
            case STRING:
                cellValue = cell.getStringCellValue();
                break;
            case FORMULA:
                break;
            case BLANK:
                break;
            case BOOLEAN:
                break;
            case ERROR:
                break;
        }
        return cellValue;
    }

    /**
     * 读取图片并包装Map -->key  是rowIndex  -->value
     * 是map map-->key -->cellIndex  value->byte[]图片二进制数组
     *
     * @param sheet
     * @return
     */
    private Map<Integer, Map<Integer, byte[]>> picture(Sheet sheet) {
        //map 返回值
        Map<Integer, Map<Integer, byte[]>> map = new LinkedHashMap();
        //sheet.getDrawingPatriarch() 返回工作表现有的图形,如果还没有,则返回null。
        if (sheet.getDrawingPatriarch() != null) {
            //甄别07
            if (sheet instanceof XSSFSheet) {
                XSSFSheet sheetTemp = (XSSFSheet) sheet;
                //此形状组中的形状列表
                for (XSSFShape shape : sheetTemp.getDrawingPatriarch().getShapes()) {
//                    若果形状组是图片 还有自定义图形的情况。
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
//                 获取图片的锚点
                        XSSFAnchor anchor = picture.getAnchor();
                        if (anchor instanceof XSSFClientAnchor) {
                            int row1 = ((XSSFClientAnchor) anchor).getRow1();
                            int cell1 = ((XSSFClientAnchor) anchor).getCol1();
                            setByte(map, row1, cell1, picture.getPictureData().getData());
                            map.put(row1, map.get(row1));
                        }
                    }
                }
            } else {
                //甄别03
                HSSFSheet sheetTemp = (HSSFSheet) sheet;
                //sheet.getDrawingPatriarch() 获取drawingPatriarch的区域。
                Spliterator<HSSFShape> spliterator = sheetTemp.getDrawingPatriarch().spliterator();
                spliterator.forEachRemaining(shape -> {
                    if (shape instanceof HSSFPicture) {
                        HSSFPicture picture = (HSSFPicture) shape;
                        HSSFAnchor anchor = picture.getAnchor();
                        if (anchor instanceof HSSFClientAnchor) {
                            int row1 = ((HSSFClientAnchor) anchor).getRow1();
                            int cell1 = ((HSSFClientAnchor) anchor).getCol1();
                            setByte(map, row1, cell1, picture.getPictureData().getData());
                            map.put(row1, map.get(row1));
                        }
                    }
                });
            }
        }
        return map;
    }

    /**
     * 不管是03 还是07的通用方法,进行判断是否存在那一行的那一列,进行添加数据
     *
     * @param map
     * @param row1
     * @param cell1
     * @param data
     */
    private void setByte(Map<Integer, Map<Integer, byte[]>> map, int row1, int cell1, byte[] data) {
        if (!map.containsKey(row1)) {
            Map<Integer, byte[]> map1 = new LinkedHashMap();
            map1.put(cell1, data);
            map.put(row1, map1);
        } else {
            Map<Integer, byte[]> integerMap = map.get(row1);
            if (!integerMap.containsKey(cell1)) {
                integerMap.put(cell1, data);
            }
        }
    }

    /**
     * poi 写出带有图片的工具类
     * 只是07的03的就是改变下类就行。
     *
     * @param fieldNames
     * @param values
     * @throws InvalidFormatException
     * @throws IOException
     */
    public void writePicture(List<String> fieldNames, LinkedList<LinkedHashMap<String, Object>> values) throws InvalidFormatException, IOException {
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet();
        XSSFDrawing xssfdrawing = sheet.createDrawingPatriarch();
        XSSFRow rowOne = sheet.createRow(0);
        for (int i = 0; i < fieldNames.size(); i++) {
            XSSFCell cell = rowOne.createCell(i);
            cell.setCellValue(fieldNames.get(i));
        }
        for (int i = 0; i < values.size(); i++) {
            LinkedHashMap<String, Object> stringObjectLinkedHashMap = values.get(i);
            XSSFRow row = sheet.createRow((i + 1));
            Object[] keyArray = stringObjectLinkedHashMap.keySet().toArray();
            for (int j = 0; j < keyArray.length; j++) {
                Object cellValue = stringObjectLinkedHashMap.get(keyArray[j].toString());
                if (cellValue instanceof byte[]) {
                    //这块设置的时候一定要col2比col1大要不图片不会出来
                    //dx1 dy1 dx2 dy2 可以随意指定吧。。没弄清楚含义
//                    XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor(0, 0, 0, 0, j, i + 1, j + 1, i + 2);
                    //一开始无参构造不行 最后行了。。
                    XSSFClientAnchor xssfClientAnchor = new XSSFClientAnchor();
                    xssfClientAnchor.setCol1(j);
                    xssfClientAnchor.setCol2(j + 1);
                    xssfClientAnchor.setRow1(i + 1);
                    xssfClientAnchor.setRow2(i + 2);
                    //插入图片
                    xssfdrawing.createPicture(xssfClientAnchor, workbook.addPicture((byte[]) cellValue, XSSFWorkbook.PICTURE_TYPE_PNG));
                } else {
                    XSSFCell cell = row.createCell(j);
                    if (cellValue != null) {
                        cell.setCellValue(cellValue.toString());
                    }
                }
            }
        }
        FileOutputStream fileOutputStream = new FileOutputStream("io.xlsx");
        workbook.write(fileOutputStream);
        workbook.close();
        fileOutputStream.close();
    }
}

<think>好的,我现在要解决用户的问题:在Java中如何导入一个Excel文件,其中前面的列是数据,最后一列是嵌入单元格的图片,并且如果有多张照片需要依次往后嵌入单元格内。用户希望了解如何实现这个功能。 首先,我需要确定用户的需求。用户希望将数据写入Excel,前面的列是普通数据,最后一列可能包含多张图片,这些图片需要嵌入到单元格中,并且如果有多个图片,应该依次排列在后面的单元格中。例如,如果最后一列是第5列,而某个单元格需要插入三张图片,那么这些图片应该分别放在第5、6、7列的对应行中。 接下来,我需要考虑使用哪些Java库来处理Excel文件。常见的库有Apache POIJExcelAPI,但JExcelAPI对Excel 2007+的支持有限,所以Apache POI可能是更好的选择,尤其是XSSF用于处理.xlsx格式的文件。 然后,我需要了解如何在Apache POI中插入图片到单元格。Apache POI允许在工作簿中创建图片,然后将图片锚定到特定的单元格位置。每个图片需要被添加到工作簿,并通过ClientAnchor指定位置。 但是,用户提到的是“嵌入单元格的图片”,这可能意味着图片需要嵌入到单元格内,而不是浮动在单元格上方。不过,在Excel中,图片通常是作为浮动对象添加到工作表,但可以调整锚点使其固定在某个单元格的位置,并随单元格移动。因此,可能需要设置ClientAnchor的锚点参数,使图片固定在目标单元格的位置。 接下来,我需要考虑如何处理多张图片依次往后嵌入的情况。例如,如果某个数据行在最后一列有多个图片,那么这些图片需要依次放入同一行的后续列中。例如,最后一列是E列,那么第一张图在E2,第二张在F2,第三张在G2,依此类推。 为了实现这一点,需要动态确定图片应该插入的列位置。例如,对于每一行数据,在处理图片时,需要根据图片的数量,逐个插入到对应的列中,起始列是最后一列数据列之后的列。例如,假设数据列有5列(A到E),那么图片从F列开始插入。 具体步骤可能如下: 1. 创建工作簿工作表对象。 2. 定义数据列的数量,例如5列,那么图片从第6列(索引5,因为从0开始)开始。 3. 遍历数据行,每行处理数据列图片列。 4. 对于每行的图片列表,逐个插入到对应的单元格中,列索引依次递增。 5. 插入图片时,使用ClientAnchor设置图片位置,可能需要调整锚点的坐标,确保图片适合单元格的大小。 但需要处理图片的尺寸问题,可能需要调整图片的大小以适应单元格。这可以通过在添加图片时缩放图片,或者设置单元格的尺寸来适应图片。 可能的挑战包括: - 如何正确计算每个图片位置,使其位于对应的单元格内。 - 如何处理多个图片在同一行不同列的插入。 - 如何调整图片大小以适应单元格,或者调整单元格大小以适应图片。 现在,我需要验证这些思路是否正确。查阅Apache POI的文档,发现图片是通过ClientAnchor来定位的,例如: ```java CreationHelper helper = workbook.getCreationHelper(); Drawing<?> drawing = sheet.createDrawingPatriarch(); ClientAnchor anchor = helper.createClientAnchor(); anchor.setCol1(targetCol); anchor.setRow1(targetRow); anchor.setCol2(targetCol + 1); // 可能跨列 anchor.setRow2(targetRow + 1); // 可能跨行 drawing.createPicture(anchor, pictureIndex); ``` 这里,anchor的setCol1setRow1指定左上角的单元格,setCol2setRow2指定右下角的单元格,从而确定图片位置大小。如果希望图片完全嵌入到单元格内,可能需要将col2row2设置为col1+1row1+1,这样图片占据一个单元格的位置。但实际效果可能取决于图片的尺寸单元格的大小。 另一个问题是,单元格默认不会自动调整大小来适应图片。因此,可能需要手动调整列宽行高,或者在插入图片时缩放图片以适应单元格。 例如,将图片缩放到单元格的尺寸: - 获取图片的原始尺寸。 - 计算单元格的宽度高度(以像素或点数)。 - 按比例缩放图片,使其适应单元格的尺寸。 但Excel中的单位转换比较复杂,可能需要使用工具类来计算。 此外,多张图片插入到同一行的后续列时,需要为每个图片创建不同的ClientAnchor,指定不同的列位置。 例如,数据列有5列(0到4),图片从第5列开始: for (int i = 0; i < images.size(); i++) { int targetCol = 4 + i + 1; // 数据列到第4索引(第5列),所以图片从第5列开始 ClientAnchor anchor = helper.createClientAnchor(); anchor.setCol1(targetCol); anchor.setRow1(rowNum); anchor.setCol2(targetCol + 1); anchor.setRow2(rowNum + 1); // 添加图片 } 但需要考虑,如果图片数量超过工作表的最大列数,但通常这由用户的数据决定,假设用户会处理。 接下来,如何处理图片的输入?用户可能需要将图片文件读入字节数组,然后添加到工作簿中。 例如: InputStream is = new FileInputStream("image.jpg"); byte[] bytes = IOUtils.toByteArray(is); int pictureIndex = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG); is.close(); 然后使用drawing.createPicture(anchor, pictureIndex)插入。 现在,将这些步骤整合成一个完整的示例代码: 1. 创建WorkbookSheet。 2. 定义数据列的数量,比如5列,图片从第6列开始。 3. 遍历数据行,每行的数据包括前5列的数据图片列表。 4. 对于每行,先写入前5列的数据。 5. 然后遍历图片列表,依次插入到第6列及之后的列中。 6. 调整列宽行高以适应图片(可选)。 示例代码可能如下: ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.util.IOUtils; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; public class ExcelWithImages { public static void main(String[] args) throws IOException { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); // 假设每行数据包含5列数据一个图片列表 List<List<Object>> dataRows = ...; // 数据行,每个列表包含前5列的数据图片路径列表 int dataColumnCount = 5; // 数据列数 for (int rowNum = 0; rowNum < dataRows.size(); rowNum++) { List<Object> rowData = dataRows.get(rowNum); Row row = sheet.createRow(rowNum); // 写入数据列 for (int col = 0; col < dataColumnCount; col++) { Cell cell = row.createCell(col); cell.setCellValue(rowData.get(col).toString()); // 假设数据为字符串 } // 获取图片路径列表 List<String> imagePaths = (List<String>) rowData.get(dataColumnCount); // 插入图片到后续列 for (int i = 0; i < imagePaths.size(); i++) { String imagePath = imagePaths.get(i); int targetCol = dataColumnCount + i; // 从第5列开始(索引5,即第6列) // 加载图片 FileInputStream imageStream = new FileInputStream(imagePath); byte[] imageBytes = IOUtils.toByteArray(imageStream); imageStream.close(); // 添加图片到工作簿 int pictureIndex = workbook.addPicture(imageBytes, Workbook.PICTURE_TYPE_JPEG); // 创建绘图对象 Drawing<?> drawing = sheet.createDrawingPatriarch(); CreationHelper helper = workbook.getCreationHelper(); ClientAnchor anchor = helper.createClientAnchor(); // 设置图片位置 anchor.setCol1(targetCol); anchor.setRow1(rowNum); anchor.setCol2(targetCol + 1); // 占据一列 anchor.setRow2(rowNum + 1); // 占据一行 // 插入图片 Picture picture = drawing.createPicture(anchor, pictureIndex); // 可选:调整图片尺寸以适应单元格 // 可能需要计算缩放比例,这里简化处理 // 或者调整单元格宽度行高 sheet.setColumnWidth(targetCol, 30 * 256); // 30字符宽 row.setHeightInPoints(100); // 行高100点 } } // 写入文件 FileOutputStream fileOut = new FileOutputStream("output.xlsx"); workbook.write(fileOut); fileOut.close(); workbook.close(); } } ``` 需要注意的问题: - 图片类型:根据实际图片类型设置Workbook.PICTURE_TYPE_JPEG、PNG等。 - 异常处理:需要处理IO异常,关闭流等。 - 性能问题:如果图片很多,需要考虑内存消耗,可能需要使用SXSSFWorkbook来处理大文件。 - 单元格调整:可能需要根据图片尺寸动态调整列宽行高,但计算较复杂。 - 图片覆盖:如果多个图片插入到相邻单元格,可能需要注意不要重叠,但代码中每个图片插入到不同的列,应该没问题。 用户可能需要将数据行组织成一个包含数据图片路径的结构,例如每行的最后一个元素是图片路径列表。此外,需要处理不同类型的图片,并确保文件路径正确。 总结步骤: 1. 使用Apache POI创建XSSFWorkbook。 2. 定义数据列数图片起始列。 3. 遍历每行数据,写入数据部分。 4. 遍历每行的图片列表,逐个插入到后续列。 5. 调整单元格尺寸以适应图片(可选)。 6. 保存工作簿到文件。 可能还需要处理的问题: - 图片跨多列或多行:调整ClientAnchor的col2row2。 - 图片位置缩放:使用不同的锚点参数或缩放图片。</think>在Java中实现Excel文件的数据与图片嵌入功能,可以使用Apache POI库。以下是分步解决方案: $$注意:$$ 需要添加Maven依赖: ```xml <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> ``` ### 一、核心实现步骤 1. **创建工作簿对象** ```java Workbook workbook = new XSSFWorkbook(); // 创建.xlsx文件 Sheet sheet = workbook.createSheet("数据表"); ``` 2. **定义列参数** ```java int DATA_COLUMNS = 5; // 前5列为数据列 int IMG_START_COL = DATA_COLUMNS; // 图片从第6列开始 ``` 3. **数据行遍历逻辑** ```java for (int rowIndex = 0; rowIndex < dataList.size(); rowIndex++) { DataModel data = dataList.get(rowIndex); // 自定义数据对象 Row row = sheet.createRow(rowIndex); // 填充数据列 for (int col = 0; col < DATA_COLUMNS; col++) { row.createCell(col).setCellValue(data.getField(col)); } // 插入图片列 int imgColOffset = 0; for (String imgPath : data.getImages()) { insertImage(workbook, sheet, rowIndex, IMG_START_COL + imgColOffset, imgPath); imgColOffset++; } } ``` 4. **图片插入方法** ```java private static void insertImage(Workbook workbook, Sheet sheet, int rowNum, int colNum, String imgPath) throws IOException { // 加载图片字节 byte[] imgBytes = Files.readAllBytes(Paths.get(imgPath)); // 添加图片到工作簿 int pictureIdx = workbook.addPicture( imgBytes, getImageType(imgPath) ); // 创建定位锚点 CreationHelper helper = workbook.getCreationHelper(); ClientAnchor anchor = helper.createClientAnchor(); anchor.setCol1(colNum); anchor.setRow1(rowNum); anchor.setCol2(colNum + 1); // 跨1列 anchor.setRow2(rowNum + 1); // 跨1行 // 插入图片并自动调整列宽 Drawing<?> drawing = sheet.createDrawingPatriarch(); drawing.createPicture(anchor, pictureIdx); sheet.setColumnWidth(colNum, 30*256); // 设置列宽为30字符 } ``` 5. **图片类型判断方法** ```java private static int getImageType(String filename) { String ext = filename.substring(filename.lastIndexOf(".")+1) .toLowerCase(); switch (ext) { case "png": return Workbook.PICTURE_TYPE_PNG; case "jpg": case "jpeg": return Workbook.PICTURE_TYPE_JPEG; case "emf": return Workbook.PICTURE_TYPE_EMF; default: throw new IllegalArgumentException("不支持的图片格式"); } } ``` ### 二、关键优化技巧 1. **动态行高调整** ```java row.setHeightInPoints(100); // 设置固定行高 // 或根据图片高度自动计算 ``` 2. **批量写入优化** ```java // 使用SXSSFWorkbook处理大数据量 Workbook workbook = new SXSSFWorkbook(100); // 保留100行在内存 ``` 3. **图片尺寸控制** ```java // 创建时指定缩放比例 Picture pict = drawing.createPicture(anchor, pictureIdx); pict.resize(0.5); // 缩小到50% ``` ### 三、执行输出 ```java try (FileOutputStream fos = new FileOutputStream("output.xlsx")) { workbook.write(fos); } ``` ### 四、效果说明 最终生成Excel: - 前5列为常规文本数据 - 从第6列开始按顺序插入图片 - 每张图片完整嵌入单个单元格 - 自动调整列宽适应图片显示 $$注意事项:$$ 1. 图片路径需使用绝对路径或正确相对路径 2. 建议限制单行图片数量避免列数溢出 3. 大尺寸图片建议先压缩再插入
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值