day02-报表技术POI

news2024/7/4 2:56:52

1、基于模板导出列表数据

1.1、需求

按照以下样式导出excel

在这里插入图片描述

1.2、思路

首先准备一个excel模板,这个模板把复杂的样式和固定的内容先准备好并且放入到项目中,然后读取到模板后向里面放入数据。

1.3、实现

第一步:准备一个excel作为导出的模板,模板内容如下

第一个sheet:

在这里插入图片描述

第二个sheet:

在这里插入图片描述

第二步:把这个模板改一个英文名称比如:userList.xlsx,放入到项目中

在这里插入图片描述

第三步:UserService实现方法

public void downLoadXlsxWithTempalte(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //        获取模板的路径
    File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
    File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userList.xlsx");
    //        读取模板文件产生workbook对象,这个workbook是一个有内容的工作薄
    Workbook workbook  = new XSSFWorkbook(templatePath);
    //        读取工作薄的第一个工作表,向工作表中放数据
    Sheet sheet = workbook.getSheetAt(0);
    //        获取第二个的sheet中那个单元格中的单元格样式
    CellStyle cellStyle = workbook.getSheetAt(1).getRow(0).getCell(0).getCellStyle();
    //        处理内容
    List<User> userList = this.findAll();
    int rowIndex = 2;
    Row row = null;
    Cell cell = null;
    for (User user : userList) {
        row = sheet.createRow(rowIndex);
        row.setHeightInPoints(15); //设置行高

        cell = row.createCell(0);
        cell.setCellValue(user.getId());
        cell.setCellStyle(cellStyle); //设置单元格样式

        cell = row.createCell(1);
        cell.setCellValue(user.getUserName());
        cell.setCellStyle(cellStyle);

        cell = row.createCell(2);
        cell.setCellValue(user.getPhone());
        cell.setCellStyle(cellStyle);

        cell = row.createCell(3);
        cell.setCellValue(simpleDateFormat.format(user.getHireDate()));
        cell.setCellStyle(cellStyle);

        cell = row.createCell(4);
        cell.setCellValue(user.getAddress());
        cell.setCellStyle(cellStyle);

        rowIndex++;
    }
    //            导出的文件名称
    String filename="用户列表数据.xlsx";
    //            设置文件的打开方式和mime类型
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    workbook.write(outputStream);

}

第四步:修改UserController中的方法,导出测试

@GetMapping(value = "/downLoadXlsxByPoi",name = "使用POI下载高版本")
public void downLoadXlsx(HttpServletRequest request,HttpServletResponse response) throws Exception{
    //       userService.downLoadXlsx(response);
    userService.downLoadXlsxWithTempalte(request,response); //下载的excel带样式
}

2、导出用户详细数据

2.1、 需求

如下,点击用户列表中的下载按钮,下载文件内容如下

在这里插入图片描述

2.2、思路

最简单的方式就是先根据案例制作模板,导出时查询用户数据、读取模板,把数据放入到模板中对应的单元格中,其中我们先处理最基本的数据,稍后再处理图片

2.3、实现

第一步:制作一个excel导出模板,如下

在这里插入图片描述

第二步:制作好的模板放入到项目中

在这里插入图片描述

第三步:Controller中添加方法

@GetMapping(value = "/download",name = "导出用户详细信息")
public void downLoadUserInfoWithTempalte(Long id,HttpServletRequest request,HttpServletResponse response) throws Exception{
    userService.downLoadUserInfoWithTempalte(id,request,response);
}

第四步:在UserService中添加方法

    public void downLoadUserInfoWithTempalte(Long id, HttpServletRequest request, HttpServletResponse response) throws Exception  {
        //        获取模板的路径
        File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
        File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userInfo.xlsx");
//        读取模板文件产生workbook对象,这个workbook是一个有内容的工作薄
        Workbook workbook  = new XSSFWorkbook(templatePath);
//        读取工作薄的第一个工作表,向工作表中放数据
        Sheet sheet = workbook.getSheetAt(0);
//        处理内容
        User user = userMapper.selectByPrimaryKey(id);
//        接下来向模板中单元格中放数据
//        用户名   第2行第2列
        sheet.getRow(1).getCell(1).setCellValue(user.getUserName());
//        手机号   第3行第2列
        sheet.getRow(2).getCell(1).setCellValue(user.getPhone());
//        生日     第4行第2列  日期转成字符串
        sheet.getRow(3).getCell(1).setCellValue
            (simpleDateFormat.format(user.getBirthday()));
//        工资 第5行第2列
        sheet.getRow(4).getCell(1).setCellValue(user.getSalary());
//        工资 第6行第2列
        sheet.getRow(5).getCell(1).setCellValue
            (simpleDateFormat.format(user.getHireDate()));
//        省份     第7行第2列
        sheet.getRow(6).getCell(1).setCellValue(user.getProvince());
//        现住址   第8行第2列
        sheet.getRow(7).getCell(1).setCellValue(user.getAddress());
//        司龄     第6行第4列暂时先不考虑
          
//        城市     第7行第4列
        sheet.getRow(6).getCell(3).setCellValue(user.getCity());

//            导出的文件名称
        String filename="用户详细信息数据.xlsx";
//            设置文件的打开方式和mime类型
        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        workbook.write(outputStream);
    }

点击页面上的下载按钮,效果如下:

在这里插入图片描述

接下来处理一下头像照片和司龄

3、导出数据带图片、公式

3.1、导出图片

个人信息的导出中包含了头像照片,需要用到POI的导出图片功能,那么POI主要提供了两个类来处理照片,这两个类是Patriarch和ClientAnchor前者负责在表中创建图片,后者负责设置图片的大小位置。

在UserService的方法中添加以下代码

// 先创建一个字节输出流
ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
// BufferedImage是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中
BufferedImage bufferImg = ImageIO.read(new File(rootPath + user.getPhoto()));
// 把读取到图像放入到输出流中
ImageIO.write(bufferImg, "jpg", byteArrayOut);
// 创建一个绘图控制类,负责画图
Drawing patriarch = sheet.createDrawingPatriarch();
// 指定把图片放到哪个位置
ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 2, 1, 4, 5);
// 开始把图片写入到sheet指定的位置
patriarch.createPicture(anchor, workbook.addPicture(
    byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG));

关于XSSFClientAnchor的8个参数说明:

dx1 - the x coordinate within the first cell.//定义了图片在第一个cell内的偏移x坐标,既左上角所在cell的偏移x坐标,一般可设0
dy1 - the y coordinate within the first cell.//定义了图片在第一个cell的偏移y坐标,既左上角所在cell的偏移y坐标,一般可设0
dx2 - the x coordinate within the second cell.//定义了图片在第二个cell的偏移x坐标,既右下角所在cell的偏移x坐标,一般可设0
dy2 - the y coordinate within the second cell.//定义了图片在第二个cell的偏移y坐标,既右下角所在cell的偏移y坐标,一般可设0

col1 - the column (0 based) of the first cell.//第一个cell所在列,既图片左上角所在列
row1 - the row (0 based) of the first cell.//图片左上角所在行
col2 - the column (0 based) of the second cell.//图片右下角所在列
row2 - the row (0 based) of the second cell.//图片右下角所在行

3.2、导出公式

应用场景说明,在导出用户详细数据时有一个司龄的显示,这里的司龄就是截止到现在入职到本公司的时间,为了学习POI对公式的操作,我们这里使用POI的公式来做。

计算截止到现在入职到本公司的时间应该用到两个日期相差的函数:DATEDIF函数,这个函数需要3个参数

P1: 一个日期 P2:截止日期 P3: 时间单位 举例:

1、DATEDIF(“2015-10-01”,“2020-10-01”,“y”) 结果是5

2、CONCATENATE(DATEDIF(“2015-10-01”,“2020-10-01”,“y”)),“年”,DATEDIF(“2015-10-01”,“2020-10-01”,“ym”),“个月”) 结果是5年0个月

放到这个用户导出时,第一个参数就是放到相应单元格上数据,第二个参数就是当天时间,

如果直接在excel中操作,如下:

在这里插入图片描述

在使用POI导出时使用setCellFormula方法来设置公式:

在这里插入图片描述

关于POI支持公式详见官网: https://poi.apache.org/components/spreadsheet/eval-devguide.html

ps:其实在正常开发时应该在模板中直接设置好公式,这样打开直接导出的excel文档时公式会直接运行出我们想要的结果

4、自定义导出详细数据的引擎

4.1、说明

看我们刚才导出时写的代码,必须要提前知道要导出数据在哪一行哪一个单元格,但是如果模板一旦发生调整,那么我们的java代码必须要修改,我们可以自定义个导出的引擎,有了这个引擎即使模板修改了我们的java代码也不用修改

在这里插入图片描述

4.2、思路

在制作模板时,在需要插入数据的位置我们坐上标记,在导出时,对象的属性要和标记做对应,如果对应匹配一样,就把值赋值到相应的位置。

4.3、实现

第一步:制作模板,命名 userInfo2.xlsx

在这里插入图片描述

第二步:添加到项目中

在这里插入图片描述

第三步:实现导出的引擎代码

package com.itheima.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import org.springframework.util.ResourceUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class ExcelExportEngine {

    private static SimpleDateFormat  sdf = new SimpleDateFormat("yyyy-MM-dd");

    public  static Workbook writeToExcel(Object object, Workbook workbook,String photoPath) throws Exception{
      //先把bean转成map
        Map<String, Object> map = EntityUtils.entityToMap(object);
        //循环遍历每一对数据,把日期型的转成字符串,方便导出
        for (String key : map.keySet()) {
            Object vlaue = map.get(key);
            if(vlaue instanceof Date){
                System.out.println(sdf.format(vlaue));
                map.put(key,sdf.format(vlaue));
            }
        }
        //获取第一个sheet,整体的思路是循环100个行的100个单元格
        Sheet sheet = workbook.getSheetAt(0);
        Cell cell =null;
        Row row = null;
        for (int i = 0; i < 100; i++) {
            row = sheet.getRow(i); //获取到空行为止
            if(row==null){
                break;
            }else{
                for (int j = 0; j < 100; j++) {
                    cell = row.getCell(j);//获取到空单元格不处理
                    if(cell!=null){
                        writeCell(cell,map); //开始向单元格中写内容
                    }
                }
            }
        }

        if(StringUtils.isNotBlank(photoPath)){
            File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
            ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
//        BufferedImage是一个带缓冲区图像类,主要作用是将一幅图片加载到内存中
            BufferedImage bufferImg = ImageIO
                    .read(new File(rootPath + photoPath));
            ImageIO.write(bufferImg, "jpg", byteArrayOut);
            Drawing patriarch = sheet.createDrawingPatriarch();

            Sheet sheet2 = workbook.getSheetAt(1);
            row = sheet2.getRow(0);
            int col1 = ((Double) row.getCell(0).getNumericCellValue()).intValue();
            int row1 = ((Double) row.getCell(1).getNumericCellValue()).intValue();
            int col2 = ((Double) row.getCell(2).getNumericCellValue()).intValue();
            int row2 = ((Double) row.getCell(3).getNumericCellValue()).intValue();
//            锚点,固定点
            ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0,  col1, row1, col2, row2);
            patriarch.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG));
            workbook.removeSheetAt(1);
        }

        return workbook;
    }

    private static void writeCell(Cell cell, Map<String, Object> map) {
        CellType cellType = cell.getCellType();
        switch (cellType){
            case FORMULA:{  //如果是公式就直接放行了
                break;
            }default:{
                String cellValue = cell.getStringCellValue();
                //就是判断一下获取到单元格中的值是否和map中的key保持一致
                if(StringUtils.isNotBlank(cellValue)){
                    for (String key : map.keySet()) {
                        if(key.equals(cellValue)){
                            cell.setCellValue(map.get(key).toString());
                        }
                    }
                }
            }
        }
    }
}

第四步:修改UserService的方法

public void downLoadUserInfoWithTempalte2(Long id, HttpServletRequest request, HttpServletResponse response) throws Exception  {
    //        获取模板的路径
    File rootPath = new File(ResourceUtils.getURL("classpath:").getPath()); //SpringBoot项目获取根目录的方式
    File templatePath = new File(rootPath.getAbsolutePath(),"/excel_template/userInfo2.xlsx");
    //        读取模板文件产生workbook对象,这个workbook是一个有内容的工作薄
    Workbook workbook  = new XSSFWorkbook(templatePath);
    // 查询用户信息
    User user = userMapper.selectByPrimaryKey(id);
   // 这里使用引擎直接导出
    workbook = ExcelExportEngine.writeToExcel(user,workbook,user.getPhoto());
    //            导出的文件名称
    String filename="用户详细信息数据.xlsx";
    //            设置文件的打开方式和mime类型
    ServletOutputStream outputStream = response.getOutputStream();
    response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    workbook.write(outputStream);
}

5、百万数据导出

5.1、概述

​ 我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下:
​ Excel 2003:在POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量。这时对于百万级别数据,Excel肯定容纳不了。
​ Excel 2007:当POI升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近百万条数据。但实际运行时还可能存在问题,原因是执行POI报表所产生的行对象,单元格对象,字体对象,他们都不会销毁,这就导致OOM的风险。

5.2、解决方案分析

​ 对于百万数据量的Excel导入导出,只讨论基于Excel2007的解决方法。在ApachePoi 官方提供了对操作大数据量的导入导出的工具和解决办法,操作Excel2007使用XSSF对象,可以分为三种模式:

java代码解析xml

dom4j:一次性加载xml文件再解析

SAX:逐行加载,逐行解析

**用户模式:**用户模式有许多封装好的方法操作简单,但创建太多的对象,非常耗内存(之前使用的方法)

**事件模式:**基于SAX方式解析XML,SAX全称Simple API for XML,它是一个接口,也是一个软件包。它是一种XML解析的替代方法,不同于DOM解析XML文档时把所有内容一次性加载到内存中的方式,它逐行扫描文档,一边扫描,一边解析。

SXSSF对象:是用来生成海量excel数据文件,主要原理是借助临时存储空间生成excel

在这里插入图片描述

5.3、原理分析

在实例化SXSSFWorkBook这个对象时,可以指定在内存中所产生的POI导出相关对象的数量(默认100),一旦内存中的对象的个数达到这个指定值时,就将内存中的这些对象的内容写入到磁盘中(XML的文件格式),就可以将这些对象从内存中销毁,以后只要达到这个值,就会以类似的处理方式处理,直至Excel导出完成。

5.4、百万数据的导出

5.4.1、模拟数据

第一步、创建表

CREATE TABLE `tb_user2` (
  `id` bigint(20) NOT NULL  COMMENT '用户ID',
  `user_name` varchar(100) DEFAULT NULL COMMENT '姓名',
  `phone` varchar(15) DEFAULT NULL COMMENT '手机号',
  `province` varchar(50) DEFAULT NULL COMMENT '省份',
  `city` varchar(50) DEFAULT NULL COMMENT '城市',
  `salary` int(10) DEFAULT NULL,
  `hire_date` datetime DEFAULT NULL COMMENT '入职日期',
  `dept_id` bigint(20) DEFAULT NULL COMMENT '部门编号',
  `birthday` datetime DEFAULT NULL COMMENT '出生日期',
  `photo` varchar(200) DEFAULT NULL COMMENT '照片路径',
  `address` varchar(300) DEFAULT NULL COMMENT '现在住址' 
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、创建存储过程

DELIMITER $$    -- 重新定义“;”分号
DROP PROCEDURE IF EXISTS test_insert $$   -- 如果有test_insert这个存储过程就删除
CREATE PROCEDURE test_insert()			  -- 创建存储过程

BEGIN
   DECLARE n int DEFAULT 1;				    -- 定义变量n=1
   SET AUTOCOMMIT=0;						    -- 取消自动提交
   
   	while n <= 5000000 do					
   		INSERT INTO `tb_user2` VALUES ( n, CONCAT('测试', n), '13800000001', '北京市', '北京市', '11000', '2001-03-01 21:18:29', '1', '1981-03-02 00:00:00', '\\static\\user_photos\\1.jpg', '北京市西城区宣武大街1号院');
   		SET n=n+1;
   	END while;
   	COMMIT;
END $$

3、开始执行

CALL test_insert();

插入500W数据大概需要200至300秒左右

5.4.2、思路分析

导出时使用的是SXSSFWorkBook这个类,一个工作表sheet最多只能放1048576行数据, 当我们的业务数据已超过100万了,一个sheet就不够用了,必须拆分到多个工作表。

导出百万数据时有两个弊端:

1、不能使用模板

2、不能使用太多的样式

也就是说导出的数据太多时必须要放弃一些。

5.4.3、代码实现

UserController代码

@GetMapping(value = "/downLoadMillion",name = "导出用户百万数据的导出")
public void downLoadMillion(Long id,HttpServletRequest request,HttpServletResponse response) throws Exception{
    userService.downLoadMillion(request,response);
}

UserService代码

public void downLoadMillion(HttpServletRequest request, HttpServletResponse response) throws Exception {
//        创建一个空的工作薄
        Workbook workbook = new SXSSFWorkbook();
        int page = 1;
        int pageSize=200000;
        int rowIndex = 1; //每一个工作页的行数
        int num = 0; //总数据量
        Row row = null;
        Cell cell = null;
        Sheet sheet = null;
        while (true){  //不停地查询
             List<User> userList = this.findPage(page,pageSize);
             if(CollectionUtils.isEmpty(userList)){  //如果查询不到就不再查询了
                 break;
             }
            if(num%1000000==0){  //每100W个就重新创建新的sheet和标题
                rowIndex = 1;
                 //        在工作薄中创建一个工作表
                 sheet = workbook.createSheet("第"+((num/1000000)+1)+"个工作表");
//        设置列宽
                 sheet.setColumnWidth(0,8*256);
                 sheet.setColumnWidth(1,12*256);
                 sheet.setColumnWidth(2,15*256);
                 sheet.setColumnWidth(3,15*256);
                 sheet.setColumnWidth(4,30*256);
                 //            处理标题
                 String[] titles = new String[]{"编号","姓名","手机号","入职日期","现住址"};
                //        创建标题行
                Row titleRow = sheet.createRow(0);

                for (int i = 0; i < titles.length; i++) {
                    cell = titleRow.createCell(i);
                    cell.setCellValue(titles[i]);
                }
             }

//        处理内容

        for (User user : userList) {
            row = sheet.createRow(rowIndex);
            cell = row.createCell(0);
            cell.setCellValue(user.getId());

            cell = row.createCell(1);
            cell.setCellValue(user.getUserName());

            cell = row.createCell(2);
            cell.setCellValue(user.getPhone());

            cell = row.createCell(3);
            cell.setCellValue(simpleDateFormat.format(user.getHireDate()));

            cell = row.createCell(4);
            cell.setCellValue(user.getAddress());
            rowIndex++;
            num++;
        }
          page++;// 继续查询下一页
        }
//            导出的文件名称
        String filename="百万数据.xlsx";
//            设置文件的打开方式和mime类型
        ServletOutputStream outputStream = response.getOutputStream();
        response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        workbook.write(outputStream);
    }

5.4.4、测试结果

导出的这个文档大概需要3-5分钟的时间,有105 MB,内容如下

在这里插入图片描述

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

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

相关文章

ShuffleNet V1+V2(pytorch)

V1 V1根本思想&#xff1a; 1.GConv替换resnet的普通1*1Conv 2.GConv后加channel shuffle模块 对GConv的不同组进行重新组合。channel_shuffle a是resnet模块&#xff0c;b&#xff0c;c是ShuffleNetV1的block&#xff0c;在V1版中&#xff0c;两模块branch2的第一个1*1卷积…

i春秋云镜之Tsclient

首先拿到目标:39.99.137.155 首先通过Fscan扫描目标: 可以看到扫描出来了一个SqlServer的弱口令。 账号是sa&#xff0c;密码是1qaz!QAZ。 这里就不使用navicat进行连接了&#xff0c;这里使用impacket-mssqlclient进行连接。 impacket-mssqlclient sa:1qaz!QAZ39.99.137.…

Electron框架:构建跨平台桌面应用的终极解决方案

文章目录 一、Electron框架简介二、Electron框架的优势1. 开发效率高2. 跨平台性能好3. 易于维护4. 强大的原生能力 三、如何使用Electron框架快速开发跨平台桌面应用1. 安装Electron2. 创建项目文件夹3. 编写主进程代码4. 编写界面代码5. 运行应用 《Electron入门与实战》编辑…

Chromadb词向量数据库总结

简介 Chroma 词向量数据库是一个用于自然语言处理&#xff08;NLP&#xff09;和机器学习的工具&#xff0c;它主要用于词嵌入&#xff08;word embeddings&#xff09;。词向量是将单词转换为向量表示的技术&#xff0c;可以捕获单词之间的语义和语法关系&#xff0c;使得计算…

linux日志管理_日志轮转logrotate

10.2 日志轮转logrotate 10.2.1 简介 日志&#xff1a;记录了程序运行时各种信息。通过日志可以分析用户行为&#xff0c;记录运行轨迹&#xff0c;查找程序问题。 ​ 但由于磁盘的空间是有限的&#xff0c;日志轮转就像飞机里的黑匣子&#xff0c;记录的信息再重要也只能记录…

漏刻有时百度地图API实战开发(12)(切片工具的使用、添加自定义图层TileLayer)

TileLayer向地图中添加自定义图层 var tileLayer new BMap.TileLayer();tileLayer.getTilesUrl function (tileCoord, zoom) {var x tileCoord.x;var y tileCoord.y;return images/tiles/ zoom /tile- x _ y .png;}var lockMap new BMap.MapType(lock_map, tileLaye…

[ 8 种有效方法] 如何在没有备份的情况下恢复 Android 上永久删除的照片?

我们生命中最重要的时刻&#xff0c;但这样做有缺点&#xff0c;其中之一就是数据丢失的风险。您可能倾向于定期删除无意义的照片&#xff0c;同时保存可爱的照片&#xff0c;从而使您的 Android 设备井井有条。然而&#xff0c;有些人在删除自己珍视的图像时不小心犯了错误。您…

安卓跳转页面闪屏,方法里需要传View 参数

/*** 跳转到首页的公共方法* */public void ToIndexpage(View v){//设置跳转的页面Intent intent new Intent(this, MainActivity.class);//实行跳转startActivity(intent);}

【PHP入门】1.1-PHP初步语法

-PHP语法初步- PHP是一种运行在服务器端的脚本语言&#xff0c;可以嵌入到HTML中。 1.1.1PHP代码标记 在PHP历史发展中&#xff0c;可以使用多种标记来区分PHP脚本 ASP标记&#xff1a; <% php代码 %>短标记&#xff1a; <? Php代码 ?>&#xff0c;以上两种…

解锁数据探索新时代,JetBrains DataGrip 2023 Mac/win中文版下载

JetBrains DataGrip 2023 Mac/win&#xff0c;作为一款全新的数据库管理和开发工具&#xff0c;为数据工程师、分析师和开发人员提供了强大的功能和工具&#xff0c;帮助他们更高效地处理和分析数据。无论你是使用Mac还是Windows系统&#xff0c;都能够通过这款软件轻松驾驭数据…

Spring MVC 中的常用注解和用法

目录 一、什么是 Spring MVC 二、MVC定义 三、简述 SpringMVC 起到的作用有哪些? 四、注解 五、请求转发或请求重定向 一、什么是 Spring MVC Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web…

css 使用flex 完成瀑布流布局

瀑布流布局在商城类、文章类 app、网页中都是常用的&#xff0c;使用这样的形式&#xff0c;能过让整个页面更加的活波&#xff0c;也能让图片根据实际的大小来显示&#xff0c;更好的展示图片内容。那么代码如何实现呢 实现的效果 代码 <template><view class"…

【Python节日系列】慢慢画一棵粉红色的圣诞树(完整代码)

写在前面 本期内容:慢慢画一棵粉红色的圣诞树,圣诞节快乐吖! 目录 目录 写在前面 目录 环境需求 粉红色圣诞树

谈谈spring中AOP

概述 在软件业&#xff0c;AOP为Aspect Oriented Programming的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续&#xff0c;是软件开发中的一个热点&#xff0c;也是Spring框架中…

尚硅谷JavaWeb电子书城项目(Java+Mysql+Tomcat+Jsp)

自己写的在线电子书城项目&#xff0c;可改写&#xff0c;添加功能&#xff0c;如打折&#xff0c;分类&#xff0c;用户管理&#xff0c;评论等功能。 使用方法&#xff1a; 1.使用idea导入项目。 2.数据库要用项目resource文件里的book.sql文件建立。 3.修改jdbc.properi…

Text2SQL学习整理(一) 综述

数据库由一张或多张表格构成&#xff0c;表格之间的关系通过共同的列&#xff08;外键&#xff09;关联&#xff0c;人们使用数据库来方便的记录和存储信息。SQL是广泛应用的关系型数据库查询语言&#xff0c;但是对于普通用户而言&#xff0c;编写SQL语句有一定的难度。 Text…

时序分解 | Matlab实现SSA-ICEEMDAN麻雀算法优化ICEEMDAN时间序列信号分解

时序分解 | Matlab实现SSA-ICEEMDAN麻雀算法优化ICEEMDAN时间序列信号分解 目录 时序分解 | Matlab实现SSA-ICEEMDAN麻雀算法优化ICEEMDAN时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现SSA-ICEEMDAN麻雀算法优化ICEEMDAN时间序列信号分解 可…

【Linux】键盘高级操作技巧

命令行最为珍视的目标之一就是懒惰&#xff1a;用最少的击键次数来完成最多的工作。另一个目标是你的手指永 远不必离开键盘&#xff0c;永不触摸鼠标。因此&#xff0c;我们有必要了解一些键盘操作&#xff0c;使我们用起来更加的迅速和高效。 移动光标 在前面介绍过上下左右…

【Spring】之Ioc和Aop快速了解

这里写目录标题 1.Spring框架是什么&#xff1f;简介&#xff1a;总结&#xff1a;Spring框架&#xff0c;可以理解为是一个管理者&#xff1a;管理整个分层架构&#xff08;MVC&#xff09;中的每一个对象&#xff1b;&#xff08;每一个对象称之为bean&#xff09; 2.Spring框…

Kubernetes技术与架构-调度 1

Kubernetes技术与架构集群对Pod的资源调度策略分为三个部分&#xff0c;其中包括匹配调度、优先调度以及终止调度&#xff0c;匹配调度是指将Pod匹配到适合、指定的Node服务器节点中运行&#xff0c;优先调度是指终止优先级低的Pod而优先匹配优先级高的Pod到适合的Node服务器节…