day01-报表技术POI

前言

报表[forms for reporting to the higher organizations],就是向上级报告情况的表格。简单的说:报表就是用表格、图表等格式来动态显示数据,可以用公式表示为:“报表 = 多样的格式 + 动态的数据”。

1、开发环境搭建

功能说明:整个案例我们操作用户表,做一个企业员工(用户)数据的导入导出。

我们使用SpringBoot+通用mapper+vue方式搭建开发环境

第一步:准备数据库,把资料文件夹下中的sql脚本直接执行

《report_manager_db.sql》

/*
Navicat MySQL Data Transfer

Source Server         : 127.0.0.1
Source Server Version : 50727
Source Host           : 127.0.0.1:3306
Source Database       : report_manager_db

Target Server Type    : MYSQL
Target Server Version : 50727
File Encoding         : 65001

Date: 2020-03-21 22:06:35
*/

CREATE DATABASE /*!32312 IF NOT EXISTS*/`report_manager_db` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `report_manager_db`;


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for tb_dept
-- ----------------------------
DROP TABLE IF EXISTS `tb_dept`;
CREATE TABLE `tb_dept` (
  `id` bigint(20) DEFAULT NULL COMMENT '部门编号',
  `dept_name` varchar(100) DEFAULT NULL COMMENT '部门编号'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tb_dept
-- ----------------------------
INSERT INTO `tb_dept` VALUES ('5', '资产管理部');
INSERT INTO `tb_dept` VALUES ('6', '质量监察部');
INSERT INTO `tb_dept` VALUES ('7', '营销部');
INSERT INTO `tb_dept` VALUES ('1', '销售部');
INSERT INTO `tb_dept` VALUES ('2', '人事部');
INSERT INTO `tb_dept` VALUES ('3', '财务部');
INSERT INTO `tb_dept` VALUES ('4', '技术部');

-- ----------------------------
-- Table structure for tb_province
-- ----------------------------
DROP TABLE IF EXISTS `tb_province`;
CREATE TABLE `tb_province` (
  `id` bigint(50) NOT NULL,
  `name` varchar(100) DEFAULT NULL COMMENT '省份或直辖市或特别行政区名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tb_province
-- ----------------------------
INSERT INTO `tb_province` VALUES ('1', '北京市');
INSERT INTO `tb_province` VALUES ('2', '天津市');
INSERT INTO `tb_province` VALUES ('3', '上海市');
INSERT INTO `tb_province` VALUES ('4', '重庆市');
INSERT INTO `tb_province` VALUES ('5', '河北省');
INSERT INTO `tb_province` VALUES ('6', '山西省');
INSERT INTO `tb_province` VALUES ('7', '辽宁省');
INSERT INTO `tb_province` VALUES ('8', '吉林省');
INSERT INTO `tb_province` VALUES ('9', '黑龙江省');
INSERT INTO `tb_province` VALUES ('10', '江苏省');
INSERT INTO `tb_province` VALUES ('11', '浙江省');
INSERT INTO `tb_province` VALUES ('12', '安徽省');
INSERT INTO `tb_province` VALUES ('13', '福建省');
INSERT INTO `tb_province` VALUES ('14', '江西省');
INSERT INTO `tb_province` VALUES ('15', '山东省');
INSERT INTO `tb_province` VALUES ('16', '河南省');
INSERT INTO `tb_province` VALUES ('17', '湖北省');
INSERT INTO `tb_province` VALUES ('18', '湖南省');
INSERT INTO `tb_province` VALUES ('19', '广东省');
INSERT INTO `tb_province` VALUES ('20', '海南省');
INSERT INTO `tb_province` VALUES ('21', '四川省');
INSERT INTO `tb_province` VALUES ('22', '贵州省');
INSERT INTO `tb_province` VALUES ('23', '云南省');
INSERT INTO `tb_province` VALUES ('24', '陕西省');
INSERT INTO `tb_province` VALUES ('25', '甘肃省');
INSERT INTO `tb_province` VALUES ('26', '青海省');
INSERT INTO `tb_province` VALUES ('27', '台湾省');
INSERT INTO `tb_province` VALUES ('28', '内蒙古自治区');
INSERT INTO `tb_province` VALUES ('29', '广西壮族自治区');
INSERT INTO `tb_province` VALUES ('30', '西藏自治区');
INSERT INTO `tb_province` VALUES ('31', '宁夏回族自治区');
INSERT INTO `tb_province` VALUES ('32', '新疆维吾尔自治区');
INSERT INTO `tb_province` VALUES ('33', '香港特别行政区');
INSERT INTO `tb_province` VALUES ('34', '澳门特别行政区');

-- ----------------------------
-- Table structure for tb_resource
-- ----------------------------
DROP TABLE IF EXISTS `tb_resource`;
CREATE TABLE `tb_resource` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `price` double(10,1) DEFAULT NULL,
  `user_id` bigint(20) DEFAULT NULL,
  `need_return` tinyint(1) DEFAULT NULL COMMENT '是否需要归还',
  `photo` varchar(200) DEFAULT NULL COMMENT '照片',
  PRIMARY KEY (`id`),
  KEY `fk_user_id` (`user_id`),
  CONSTRAINT `fk_user_id` FOREIGN KEY (`user_id`) REFERENCES `tb_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tb_resource
-- ----------------------------
INSERT INTO `tb_resource` VALUES ('1', '记录本', '2.0', '3', '0', '\\resource_photos\\3\\1.jpg');
INSERT INTO `tb_resource` VALUES ('2', '笔记本电脑', '7000.0', '3', '1', '\\resource_photos\\3\\2.jpg');
INSERT INTO `tb_resource` VALUES ('3', '办公桌', '1000.0', '3', '1', '\\resource_photos\\3\\3.jpg');
INSERT INTO `tb_resource` VALUES ('4', '订书机', '50.0', '4', '1', '\\resource_photos\\4\\1.jpg');
INSERT INTO `tb_resource` VALUES ('5', '双面胶带', '5.0', '4', '0', '\\resource_photos\\4\\2.jpg');
INSERT INTO `tb_resource` VALUES ('6', '资料文件夹', '10.0', '4', '0', '\\resource_photos\\4\\3.jpg');
INSERT INTO `tb_resource` VALUES ('7', '打印机', '1200.0', '4', '1', '\\resource_photos\\4\\4.jpg');

-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT 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 '现在住址',
  PRIMARY KEY (`id`),
  KEY `fk_dept` (`dept_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES ('1', '大一', '13800000001', '北京市', '北京市', '11000', '2001-01-01 21:18:29', '1', '1981-03-02 00:00:00', '\\static\\user_photos\\1.jpg', '北京市西城区宣武大街1号院');
INSERT INTO `tb_user` VALUES ('2', '不二', '13800000002', '河北省', '石家庄市', '12000', '2002-01-02 21:18:29', '2', '1982-03-02 00:00:00', '\\static\\user_photos\\2.jpg', '北京市西城区宣武大街2号院');
INSERT INTO `tb_user` VALUES ('3', '张三', '13800000003', '河北省', '石家庄市', '13000', '2003-03-03 21:18:29', '3', '1983-03-02 00:00:00', '\\static\\user_photos\\3.jpg', '北京市西城区宣武大街3号院');
INSERT INTO `tb_user` VALUES ('4', '李四', '13800000004', '河北省', '石家庄市', '14000', '2004-02-04 21:18:29', '4', '1984-03-02 00:00:00', '\\static\\user_photos\\4.jpg', '北京市西城区宣武大街4号院');
INSERT INTO `tb_user` VALUES ('5', '王五', '13800000005', '河北省', '唐山市', '15000', '2005-03-05 21:18:29', '5', '1985-03-02 00:00:00', '\\static\\user_photos\\5.jpg', '北京市西城区宣武大街5号院');
INSERT INTO `tb_user` VALUES ('6', '赵六', '13800000006', '河北省', '承德市省', '16000', '2006-04-06 21:18:29', '6', '1986-03-02 00:00:00', '\\static\\user_photos\\6.jpg', '北京市西城区宣武大街6号院');
INSERT INTO `tb_user` VALUES ('7', '沈七', '13800000007', '河北省', '秦皇岛市', '17000', '2007-06-07 21:18:29', '7', '1987-03-02 00:00:00', '\\static\\user_photos\\7.jpg', '北京市西城区宣武大街7号院');
INSERT INTO `tb_user` VALUES ('8', '酒八', '13800000008', '河北省', '秦皇岛市', '18000', '2008-07-08 21:18:29', '6', '1988-03-02 00:00:00', '\\static\\user_photos\\8.jpg', '北京市西城区宣武大街8号院');
INSERT INTO `tb_user` VALUES ('9', '第九', '13800000009', '山东省', '德州市', '19000', '2009-03-09 21:18:29', '1', '1989-03-02 00:00:00', '\\static\\user_photos\\9.jpg', '北京市西城区宣武大街9号院');
INSERT INTO `tb_user` VALUES ('10', '石十', '13800000010', '山东省', '青岛市', '20000', '2010-07-10 21:18:29', '4', '1990-03-02 00:00:00', '\\static\\user_photos\\10.jpg', '北京市西城区宣武大街10号院');
INSERT INTO `tb_user` VALUES ('11', '肖十一', '13800000011', '山东省', '青岛市', '21000', '2011-12-11 21:18:29', '4', '1991-03-02 00:00:00', '\\static\\user_photos\\11.jpg', '北京市西城区宣武大街11号院');
INSERT INTO `tb_user` VALUES ('12', '星十二', '13800000012', '山东省', '青岛市', '22000', '2012-05-12 21:18:29', '4', '1992-03-02 00:00:00', '\\static\\user_photos\\12.jpg', '北京市西城区宣武大街12号院');
INSERT INTO `tb_user` VALUES ('13', '钗十三', '13800000013', '山东省', '济南市', '23000', '2013-06-13 21:18:29', '3', '1993-03-02 00:00:00', '\\static\\user_photos\\13.jpg', '北京市西城区宣武大街13号院');
INSERT INTO `tb_user` VALUES ('14', '贾十四', '13800000014', '山东省', '威海市', '24000', '2014-06-14 21:18:29', '2', '1994-03-02 00:00:00', '\\static\\user_photos\\14.jpg', '北京市西城区宣武大街14号院');
INSERT INTO `tb_user` VALUES ('15', '甄世武', '13800000015', '山东省', '济南市', '25000', '2015-06-15 21:18:29', '4', '1995-03-02 00:00:00', '\\static\\user_photos\\15.jpg', '北京市西城区宣武大街15号院');


-- ----------------------------
-- Table structure for tb_month
-- ----------------------------
DROP TABLE IF EXISTS `tb_month`;
CREATE TABLE `tb_month` (
  `name` varchar(2) DEFAULT NULL COMMENT '月份'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of tb_month
-- ----------------------------
INSERT INTO `tb_month` VALUES ('01');
INSERT INTO `tb_month` VALUES ('02');
INSERT INTO `tb_month` VALUES ('03');
INSERT INTO `tb_month` VALUES ('04');
INSERT INTO `tb_month` VALUES ('05');
INSERT INTO `tb_month` VALUES ('06');
INSERT INTO `tb_month` VALUES ('07');
INSERT INTO `tb_month` VALUES ('08');
INSERT INTO `tb_month` VALUES ('09');
INSERT INTO `tb_month` VALUES ('10');
INSERT INTO `tb_month` VALUES ('11');
INSERT INTO `tb_month` VALUES ('12');

2、Excel说明

在企业级应用开发中,Excel报表是一种最常见的报表需求。Excel报表开发一般分为两种形式:
1、为了方便操作,基于Excel的报表批量上传数据,也就是把Excel中的数据导入到系统中。
2、通过java代码生成Excel报表。也就是把系统中的数据导出到Excel中,方便查阅。

2.1 Excel的两种版本

目前世面上的Excel分为两个大的版本Excel2003和Excel2007及以上两个版本;
两者之间的区别如下:

在这里插入图片描述

Excel2003 是一个特有的二进制格式,其核心结构是复合文档类型的结构,存储数据量较小;

Excel2007 的核心结构是 XML 类型的结构,采用的是基于 XML 的压缩方式,使其占用的空间更小,

​ 操作效率更高

2.2 常见的Excel操作工具

Java中常见的用来操作Excel的方式一般有2种:JXL和POI。

2.2.1 JXL

JXL只能对Excel进行操作,属于比较老的框架,它只支持到Excel 95-2000的版本。现在已经停止更新和
维护,所以本课程中只时简单地演示一下jxl的代码,不会把它作为重点,

2.2.2 POI

POI是apache的项目,可对微软的Word,Excel,PPT进行操作,包括office2003和2007,Excle2003和2007。
poi现在一直有更新。所以现在主流使用POI。

Apache POI是Apache软件基金会的开源项目,由Java编写的免费开源的跨平台的 Java API,Apache
POI提供API给Java语言操作Microsoft Office的功能。

API对象介绍
工作簿 : WorkBook (HSSFWordBook : 2003版本,XSSFWorkBook : 2007级以上)
工作表 : Sheet (HSSFSheet : 2003版本,XSSFSheet : 2007级以上)
行 : Row (HSSFRow : 2003版本,XSSFRow : 2007级以上)
单元格 : Cell (HSSFCell : 2003版本,XSSFCell : 2007级以上)

3、使用JXL导出excel

目前Excel的版本有2013、2010、2007,这些都是新版本的excel,新版本的excel已经出现十多年了,使用人群已经比较多了,所以目前做项目大都做的是导出新版本的excel,而jxl只能操作低版本的excel,所以现在使用jxl做项目已经比较少见,那我们在这里使用jxl导出一个简单一些的excel。

3.1 使用jxl导出基本知识点

通过WritableWorkbook,WritableSheet,Label这三个对象我们就可以实现Excel文件的导出工作。

1、 创建可写入的Excel工作薄

WritableWorkbook workbook= Workbook.createWorkbook(输出流);

2、创建工作表

WritableSheet sheet= workbook.createSheet(工作表的名称, 工作表的索引值);

3、创建单元格

添加文本类单元格

Label labelC = new Label(列索引值, 行索引值, "单元格中的内容");

sheet.addCell(labelC);

4、写入到文件

workbook.write();// 写入数据

5、释放资源:

workbook.close();// 关闭文件

3.2 代码实现导出用户列表数据

第一步:UserController中添加方法

@GetMapping(value = "/downLoadXlsByJxl",name = "使用jxl下载")
public void downLoadXlsByJxl(HttpServletResponse response){
    userService.downLoadByJxl(response);
}

第二步:UserService中的方法

private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-ss");

public void downLoadXlsByJxl(HttpServletResponse response){
        try {
//            创建一个工作薄
            ServletOutputStream outputStream = response.getOutputStream();
            WritableWorkbook workbook = Workbook.createWorkbook(outputStream);
//            创建一个工作表
            WritableSheet sheet = workbook.createSheet("一个JXL入门", 0);
//            设置列宽
            sheet.setColumnView(0,5);
            sheet.setColumnView(1,8);
            sheet.setColumnView(2,15);
            sheet.setColumnView(3,15);
            sheet.setColumnView(4,30);
//            处理标题
            String[] titles = new String[]{"编号","姓名","手机号","入职日期","现住址"};
            Label label = null;
            for (int i = 0; i < titles.length; i++) {
                label = new Label(i,0,titles[i]);
                sheet.addCell(label);
            }
//            处理导出的内容
            List<User> userList = this.findAll();
            int rowIndex = 1;
            for (User user : userList) {
                label = new Label(0,rowIndex,user.getId().toString());
                sheet.addCell(label);
                label = new Label(1,rowIndex,user.getUserName());
                sheet.addCell(label);
                label = new Label(2,rowIndex,user.getPhone());
                sheet.addCell(label);
                label = new Label(3,rowIndex,simpleDateFormat.format(user.getHireDate()));
                sheet.addCell(label);
                label = new Label(4,rowIndex,user.getAddress());
                sheet.addCell(label);
                rowIndex++;
            }
            
            //            导出的文件名称
            String filename="一个JXL入门.xls";
//            设置文件的打开方式和mime类型
             response.setHeader( "Content-Disposition", "attachment;filename="  + new String(filename.getBytes(),"ISO8859-1"));
            response.setContentType("application/vnd.ms-excel");
//            导出
            workbook.write();
//            关闭资源
            workbook.close();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

导出内容如下:

在这里插入图片描述

4、POI操作excel

添加所需的依赖:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.0.1</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.0.1</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>4.0.1</version>
</dependency>

4.1、POI操作Excel高低版本区别

在POI包中有如下几个主要对象和excel的几个对象对应:

对应excel名称低版本中的类名高版本中的类名
工作簿HSSFWorkbookXSSFWorkbook
工作表HSSFSheetXSSFSheet
HSSFRowXSSFRow
单元格HSSFCellXSSFCell
单元格样式HSSFCellStyleXSSFCellStyle

入门案例代码:创建一个新的工作薄,里面随便写一句话

操作低版本:

package com.itheima.demo;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileOutputStream;
public class POIDemo01 {
    public static void main(String[] args) throws Exception{
        Workbook workbook = new HSSFWorkbook(); //创建了一个全新(里面什么都没有)的工作薄
        Sheet sheet = workbook.createSheet("demo测试");  //创建了一个全新(里面什么都没有)的工作表
        Row row = sheet.createRow(0);  //创建了第一行(空的)
        Cell cell = row.createCell(0);//创建的是第一行的第一个单元格
        cell.setCellValue("这是我第一次玩POI");
//        把工作薄输出到本地磁盘
        workbook.write(new FileOutputStream("d://test.xls"));
    }
}

操作高版本:

package com.itheima.demo;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;
 
public class POIDemo02 {
    public static void main(String[] args) throws Exception{
        Workbook workbook = new XSSFWorkbook(); //创建了一个全新(里面什么都没有)的工作薄
        Sheet sheet = workbook.createSheet("demo测试");  //创建了一个全新(里面什么都没有)的工作表
        Row row = sheet.createRow(0);  //创建了第一行(空的)
        Cell cell = row.createCell(0);//创建的是第一行的第一个单元格
        cell.setCellValue("这是我第一次玩POI");
//        把工作薄输出到本地磁盘
        workbook.write(new FileOutputStream("d://test.xlsx"));
    }
}

比较上面两个代码会发现,在开发中只是类的名称不一样,方法是一样的。

4.2、实现用户数据的导入

4.2.1、需求

把资料中的《用户导入测试数据.xlsx》文档中的数据导入到系统中,

内容如下:

在这里插入图片描述

数据的导入就是读取excel中的内容,转成对象插入到数据库中

4.2.2 、思路

一般来说,即将导入的文件,每个列代表什么意思基本上都是固定的,比如第1列就是用户姓名,最后一列就是用户的现住址,并且在做excel时对每个列的类型都是有要求的,这样就可以给我们开发带来很大的简便。

最终的目标就是读取每一行数据,把数据转成用户的对象,保存到表中

实现的步骤:1、根据上传的文件创建Workbook

​ 2、获取到第一个sheet工作表

​ 3、从第二行开始读取数据

​ 4、读取每一个单元格,把内容放入到用户对象的相关的属性中

4.2.3、代码实现

第一步:在Controller接收文件,具体的实现交给service

@PostMapping(value = "/uploadExcel", name = "上传用户数据")
public void uploadExcel(MultipartFile file)  throws Exception{
   userService.uploadExcel(file);
}

第二步:UserService添加上传用户的方法

public void uploadExcel(MultipartFile file) throws Exception {
    Workbook workbook = new XSSFWorkbook(file.getInputStream()); //根据上传的输入流创建workbook
    Sheet sheet = workbook.getSheetAt(0); //获取工作薄中的第一个工作表
    int lastRowIndex = sheet.getLastRowNum(); //获取这个sheet中最后一行数据,为了循环遍历

    //        以下三个为了节省栈内存,所以提到循环的外面
    User user = null;
    Row row = null;
    Cell cell = null;

    //开始循环每行,获取每行的单元格中的值,放入到user属性中
    for (int i = 1; i <= lastRowIndex; i++) {
        row = sheet.getRow(i);
        user = new User();
        //          因为第一个列单元格中是字符串,可以直接使用getStringCellValue方法
        String userName = row.getCell(0).getStringCellValue(); //用户名
        user.setUserName(userName);
        String phone = null; //手机号
        try {
            phone = row.getCell(1).getStringCellValue();
        } catch (IllegalStateException e) {
            phone = row.getCell(1).getNumericCellValue()+"";
        }
        user.setPhone(phone);
        String province = row.getCell(2).getStringCellValue(); //省份
        user.setProvince(province);
        String city = row.getCell(3).getStringCellValue(); //城市
        user.setCity(city);
        //            因为在填写excel中的数据时就可以约定这个列只能填写数值,所以可以直接用getNumericCellValue方法
        Integer salary = ((Double)row.getCell(4).getNumericCellValue()).intValue(); //工资
        user.setSalary(salary);
        String hireDateStr = row.getCell(5).getStringCellValue(); //入职日期
        Date hireDate = simpleDateFormat.parse(hireDateStr);
        user.setHireDate(hireDate);
        String birthdayStr = row.getCell(6).getStringCellValue(); //出生日期
        Date birthday = simpleDateFormat.parse(birthdayStr);
        user.setBirthday(birthday);

        String address = row.getCell(7).getStringCellValue(); //现住地址
        user.setAddress(address);
        userMapper.insert(user);
    }

}

上传成功后直接查询数据库中的数据:

在这里插入图片描述

4.3、实现用户数据的导出

4.3.1、需求

我们先来一个简单的excel的导出,不要求有什么样式。就是和jxl导出的内容一样就可以

在这里插入图片描述

4.3.2、基本思路

1、创建一个全新的工作薄

2、在新的工作薄中创建一个新的工作表

3、在工作表创建第一行作为标题行,标题固定

4、从第二行循环遍历创建,有多少条用户数据就应该创建多少行

5、把每一个user对象的属性放入到相应的单元格中

4.3.3、代码实现

第一步:在Controller添加方法,具体的实现交给service

@GetMapping(value = "/downLoadXlsxByPoi",name = "使用POI下载高版本")
public void downLoadXlsx(HttpServletResponse response) throws Exception{
    userService.downLoadXlsx(response);
}

第二步:UserService中实现

public void downLoadXlsx(HttpServletResponse response) throws Exception {
    //        创建一个空的工作薄
    Workbook workbook = new XSSFWorkbook();
    //        在工作薄中创建一个工作表
    Sheet sheet = workbook.createSheet("测试");
    //        设置列宽
    sheet.setColumnWidth(0,5*256);
    sheet.setColumnWidth(1,8*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);
    Cell cell = null;
    for (int i = 0; i < titles.length; i++) {
        cell = titleRow.createCell(i);
        cell.setCellValue(titles[i]);
    }
    //        处理内容
    List<User> userList = this.findAll();
    int rowIndex = 1;
    Row row = null;
    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++;
    }
    //            导出的文件名称
    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);

}

4.4、导出时样式的设置

如果要求导出的excel如下内容:

在这里插入图片描述

通过上图可以看出有些样式需要我们来设置,来看一下都有哪些知识点:
1.画框线

/**
* 设置框线
*/
HSSFCellStyle contentStyle = book.createCellStyle();
contentStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);//底线
contentStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//顶部线
contentStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左侧线
contentStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右侧线

2.合并单元格

//合并单元格 起始行, 结束行, 起始列, 结束列		
sheet.addMergedRegion(new CellRangeAddress(0,0,0,4));

3.设置行高

/**
设置行高
*/
sheet.getRow(1).setHeight((short)500);

4.设置表格的对齐方式和字体

//*设置对齐方式和字体***/
//内容部分的样式
style_content.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_content.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中

HSSFFont font = book.createFont();//创建字体
font.setFontName("宋体");//设置字体名称
font.setFontHeightInPoints((short)11);//设置字体大小
style_content.setFont(font);//对样式设置字体
        
//标题样式
HSSFCellStyle style_title = book.createCellStyle();//创建标题样式
style_title.setAlignment(HSSFCellStyle.ALIGN_CENTER);//设置水平居中
style_title.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//设置垂直居中
HSSFFont titleFont = book.createFont();//设置标题字体
titleFont.setFontName("黑体");
titleFont.setBold(true);//加粗
titleFont.setFontHeightInPoints((short)18);//字体大小    
style_title.setFont(titleFont);//将标题字体设置到标题样式
sheet.getRow(0).getCell(0).setCellStyle(style_title);//单元格设置标题样式

其实真正要用代码实现我们最终想要的效果的话,难道不大,但是代码写起来非常麻烦,所以明天给大家介绍一种非常简单的方式,并且还带有样式。

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

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

相关文章

【Python动漫系列】哆啦A梦(完整代码)

文章目录 哆啦A梦环境需求完整代码程序分析系列文章哆啦A梦 《哆啦A梦》是由日本漫画家藤子F不二雄创作的一部科幻搞笑漫画,故事中的主角是一只来自未来的机器猫——哆啦A梦。该作品于1969年开始连载,至今已经持续了50多年,成为了日本乃至全球最受欢迎的漫画之一。 故事发…

c++_01_名字空间_复合类型_缺省参数_哑元函数

0 前言 C和C一样&#xff0c;都属于编译型语言 C和C一样&#xff0c;都属于强类型语言 C对C完全兼容&#xff0c;并提供更多面向对象的特性&#xff1a;语言风格更加简洁&#xff0c;类型检查更加严格 1 名字空间 namespace WHY&#xff1f;划分更精细的逻辑单元(逻辑空间)&…

AC843. n皇后问题--60

我们只需要把蓝色的往上移动就行了 if(!col[i][j]&&!dg[ui]&&!udg[])//1y&#xff08;i&#xff09;向下&#xff0c;x&#xff08;u&#xff09;向右为正。yxb的by-x一定>0,y-xb的bxy可能>0,这个不考虑&#xff0c;只看-bxy.

Python-数据分析可视化实例图

Python-数据分析可视化实例图 一&#xff1a;3D纹理图 运行效果图&#xff1a; Python代码&#xff1a; import math from typing import Unionimport pyecharts.options as opts from pyecharts.charts import Surface3Ddef float_range(start: int, end: int, step: Union[…

翻译: 工作使用ChatGPT的例子 Day-to-day usage of web UI LLMs

本周&#xff0c;我们将首先探讨生成型AI在商业中的作用&#xff0c;然后是其对社会的影响&#xff0c;例如对就业的影响。我们将从探讨如何在日常工作中使用网络用户界面访问生成型AI开始&#xff0c;然后再看看如何系统地分析一个企业&#xff0c;以识别使用生成型AI增强或自…

Linux面试题精选:提升你的面试准备

大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&#xff1a;ajax知识点 &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 学习…

商用机器人,不好用是原罪

热潮褪去后&#xff0c;所有的问题都汇总成一个词&#xff0c;不好用。 从炙手可热到“大玩具” 一款产品好用与否&#xff0c;更多时候人们不会关心它先进的技术、工艺、用料&#xff0c;也不会考虑所谓的潮流趋势或前景&#xff0c;只会用最朴素的直观感受告诉你&#xff0…

LabVIEW开发地铁运行安全监控系统

LabVIEW开发地铁运行安全监控系统 最近昌平线发生的故障事件引起了广泛关注&#xff0c;暴露了现有地铁运行监控系统在应对突发情况方面的不足。为了提高地铁系统的运行安全性&#xff0c;并防止类似事件再次发生&#xff0c;提出了一套全面的地铁运行安全监控系统方案。此方案…

NAT——网络地址转换

目录 一、概念 二、NAT的分类 1.静态NAT 1.1 静态NAT的配置 1.2 利用eNSP小实验加强对静态NAT的理解 2、动态NAT 三、NAPT——端口映射 四、Easy IP 使用一个公网地址可以让所有人都上公网 一、概念 随着Internet的发展和网络应用的增多&#xff0c;IPv4地址枯竭已经成为…

【C语言(十)】

字符函数和字符串函数 一、字符分类函数 C语言中有⼀系列的函数是专门做字符分类的&#xff0c;也就是⼀个字符是属于什么类型的字符的。这些函数的使用都需要包含⼀个头文件是 ctype.h 这些函数的使用方法非常类似&#xff0c;我们就讲解⼀个函数的事情&#xff0c;其他的非…

鸿蒙4.0开发 - DevEco Studio如何使用Previewer窗口预览器报错

DevEco Studio预览器概况在HarmonyOS应用开发过程中&#xff0c;通过使用预览器&#xff0c;可以查看应用的UI效果&#xff0c;方便开发者实时查看应用的运行效果&#xff0c;随时调整代码。 1.正常启动 打开预览器的位置在DevEco Studio编辑界面的右上角部分&#xff0c;竖排…

MySQL低版本中:字符串中的数字、英文字符、汉字提取

我们如何提醒一个字段中的汉字和数字呢 高版本指mysql8.0以上 使用sql语句 SELECT REGEXP_REPLACE(column_name, [^\\p{Han}], ) AS chinese_characters FROM table_name;其中 column_name指名称列&#xff0c;table_name是表名 2.低版本使用 需要新建函数 DELIMITER $$DR…

ChatGPT4 Excel 高级复杂函数案例实践

案例需求: 需求中需要判断多个条件进行操作。 可以让ChatGPT来实现这样的操作。 Prompt:有一个表格B2单元格为入职日期,C2单元格为员工等级(A,B,C),D2单元格为满意度分数(1,2,3,4,5)请给入职一年以上,员工等级为A级并且满意度在3分以上的人发4000元奖金,给入…

《打造第二大脑》—如何构建高效的笔记系统

最近看了一本书&#xff0c;因为我也用Obsidian来记笔记&#xff0c;&#xff08;Obsidian之前有介绍过Obsidian使用教程&#xff08;如何构建你的个人知识库&#xff0c;第二大脑&#xff09;&#xff09;看完这本书后发现里面给的方法跟Obsidian很契合&#xff0c;所以就整理…

Vue3报错: ‘defineProps‘ is not defined,解决方法

问题出现: 今天在使用 <script setup>组合式 API 的语法糖的时候&#xff0c;定义defineProps时候报错&#xff1a; ‘defineProps’ is not defined 查了一下资料&#xff0c;这是因为eslint的语法校验导致的问题。 解决方法1&#xff1a; 在项目根目录的文件.eslin…

基于Springboot的任务发布平台设计与实现(源码齐全+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…

QT作业3

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和密码不匹配&#xf…

鸿蒙小车之多任务调度实验

说到鸿蒙我们都会想到华为mate60&#xff1a;遥遥领先&#xff01;我们一直领先&#xff01; 我们这个小车也是采用的是鸿蒙操作系统&#xff0c;学习鸿蒙小车&#xff0c;让你遥遥领先于你的同学。 文章目录 前言一、什么是任务&#xff1f;为什么要有任务二、任务的状态三、任…

​报名参加openGauss训练营,开启数据库之旅!

一直以来,数据库被誉为基础软件“皇冠上的明珠”、技术的“大动脉”。也许我们对它的名字略感陌生,但我们生活的方方面面却都无法离不开它,无论是抢票、网购还是线上点餐等,几乎都得益于数据库的支持,它是支撑各类应用软件运行的基础。 openGauss是一款开源关系型数据库管理系…

Duplicate keys detected: This may cause an update error.【Vue遍历渲染报错的解决】

今天在写项目时&#xff0c;写到一个嵌套评论的遍历时&#xff0c;控制台出现了一个报错信息&#xff0c;但是并不影响页面的渲染&#xff0c;然后一看这个错的原因是 key值重复&#xff0c;那么问题的解决方式就很简单了。&#xff08;vue for循环读取key值时&#xff0c; key…