前言

在开发应用系统的时候,导出文件是必不可放的功能。

以前用过POI、easyexcel等工具的导入导出功能,但总感觉太麻烦了,代码特别多,感觉并不是很好用。

今天给大家介绍一款新工具,java工具类库Hutool。

Hutool简介

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让使用者更轻松。

Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

使用

首先在POM.xml中加入GAV

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.0.7</version>
</dependency>
<!--解析excel-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.1</version>
</dependency>
<!--处理2007 excel-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>3.17</version>
</dependency>

导出

@RequestMapping("/export")
@ResponseBody
public void export(HttpServletResponse response){
	List<User> list = new ArrayList<>();
	list.add(new User("zhangsan","1231",new Date()));
	list.add(new User("zhangsan1","1232",new Date()));
	list.add(new User("zhangsan2","1233",new Date()));
	list.add(new User("zhangsan3","1234",new Date()));
	list.add(new User("zhangsan4","1235",new Date()));
	list.add(new User("zhangsan5","1236", DateUtil.date(new Date())));
	// 通过工具类创建writer,默认创建xls格式
	ExcelWriter writer = ExcelUtil.getWriter();
	//自定义标题别名
	writer.addHeaderAlias("name", "姓名");
	writer.addHeaderAlias("age", "年龄");
	writer.addHeaderAlias("birthDay", "生日");
	// 合并单元格后的标题行,使用默认标题样式
	writer.merge(2, "申请人员信息");
	// 一次性写出内容,使用默认样式,强制输出标题
	writer.write(list, true);
	//out为OutputStream,需要写出到的目标流
	//response为HttpServletResponse对象
	response.setContentType("application/vnd.ms-excel;charset=utf-8");
	//test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
	String name = StringUtils.toUtf8String("申请学院");
	response.setHeader("Content-Disposition","attachment;filename="+name+".xls");
	ServletOutputStream out= null;
	try {
		out = response.getOutputStream();
		writer.flush(out, true);
	}
	catch (IOException e) {
		e.printStackTrace();
	}
	finally {
		// 关闭writer,释放内存
		writer.close();
	}
	//此处记得关闭输出Servlet流
	IoUtil.close(out);
}

效果

java同包导入类 java导入类库_apache

导入 

java同包导入类 java导入类库_spring_02

数据库

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50724
Source Host           : localhost:3306
Source Database       : ssm

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

Date: 2020-04-27 16:37:43
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `excel`
-- ----------------------------
DROP TABLE IF EXISTS `excel`;
CREATE TABLE `excel` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(20) DEFAULT NULL,
  `height` double(16,2) DEFAULT NULL,
  `weight` double(16,2) DEFAULT NULL,
  `edu` varchar(255) DEFAULT NULL,
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `status` tinyint(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of excel
-- ----------------------------
INSERT INTO `excel` VALUES ('7', '万超2', '20', '187.90', '65.90', '本科', '2020-04-27 16:08:53', '2020-04-27 16:08:53', '1');
INSERT INTO `excel` VALUES ('8', '马汉2', '14', '138.80', '78.24', '硕士', '2020-04-27 16:08:53', '2020-04-27 16:08:53', '2');
INSERT INTO `excel` VALUES ('9', '万超2', '20', '187.90', '65.90', '本科', '2020-04-27 16:12:23', '2020-04-27 16:12:23', '1');
INSERT INTO `excel` VALUES ('10', '马汉2', '14', '138.80', '78.24', '硕士', '2020-04-27 16:12:23', '2020-04-27 16:12:23', '2');
INSERT INTO `excel` VALUES ('11', '万超0', '20', '187.90', '65.90', '本科', '2020-04-27 16:12:37', '2020-04-27 16:12:37', '1');
INSERT INTO `excel` VALUES ('12', '马汉0', '14', '138.80', '78.24', '硕士', '2020-04-27 16:12:37', '2020-04-27 16:12:37', '2');

 mysql中默认当前时间为CURRENT_TIMESTAMP

java同包导入类 java导入类库_spring_03

application.properties

spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
#  com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root

#开启驼峰命名转换
mybatis.configuration.map-underscore-to-camel-case=true
#实体类的别名
#mybatis.type-aliases-package=com.example.springboot.model

#前缀的默认值,是让controller层到templates文件夹寻找xx.html(src/main/resources/templates)
#spring.thymeleaf.prefix=classpath:/templates/

#logging.level.com,后面的路径指的是mybatis对应的方法接口所在的包。并不是mapper.xml所在的包
logging.level.com.example.springbootexcel.mapper=debug

excelImport.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Excel导入</title></head>
<body>
<form enctype="multipart/form-data" method="post" action="/excelImport">
    选择Excel表格:<input type="file" name="file"/><br/>
    <input type="submit" value="上传"/></form>
</body>
</html>

model

@Getter
@Setter
public class Excel {

    private Long id;
    
    private String name;

    private Integer age;

    private Double height;

    private Double weight;

    private String edu;

    private Date createTime;

    private Date updateTime;

    private Integer status;

}

mapper

接口

package com.example.springbootexcel.mapper;

import com.example.springbootexcel.model.Excel;

import java.util.List;

public interface ExcelMapper {

    /**
     * 批量插入
     * @param recordList
     * @return
     */
    int insertList(List<Excel> recordList);
}

ExcelMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.springbootexcel.mapper.ExcelMapper">

  <insert id="insertList" parameterType="com.example.springbootexcel.model.Excel">
    insert into excel (
      name,
      age,
      height,
      weight,
      edu,
      update_time,
      status
    )
    values
    <foreach collection="list" item="item" index="index" separator=",">
      (
        #{item.name,jdbcType=VARCHAR},
        #{item.age,jdbcType=INTEGER},
        #{item.height,jdbcType=DOUBLE},
        #{item.weight,jdbcType=DOUBLE},
        #{item.edu,jdbcType=VARCHAR},
        NOW(),
        #{item.status,jdbcType=INTEGER}
      )
    </foreach>
  </insert>

</mapper>

 

service

import com.example.springbootexcel.mapper.ExcelMapper;
import com.example.springbootexcel.model.Excel;
import com.example.springbootexcel.utils.ExcelUtil;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

@Service
public class ExcelService {


    @Autowired
    private ExcelMapper excelMapper;

    public int addList(List<Excel> list){
        return excelMapper.insertList(list);
    }
}

controller

package com.example.springbootexcel.controller;

import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.example.springbootexcel.model.Excel;
import com.example.springbootexcel.service.ExcelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author guoqiang
 * @date 2020-04-27 10:08
 */
@Controller
public class ExcelController2 {

    @Autowired
    private ExcelService service;

    @GetMapping("/toHtml")
    public String test(HttpServletRequest request) {
        return "excelImport";
    }


    //处理文件上传
    @ResponseBody//返回json数据
    @RequestMapping(value = "/excelImport", method = RequestMethod.POST)
    public String uploadImg(@RequestParam("file") MultipartFile file, HttpServletRequest request) {

        System.out.println(file);

        if (file.isEmpty()) {
            System.out.println( "文件为空!");
            return "excelImport";
        }

        // 1.获取上传文件输入流
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (Exception e) {
            //return ResponseData.fail(ResponseCodeEnum.ERROR_PARAM_INVALID);
            e.printStackTrace();
        }
//        // 2.应用HUtool ExcelUtil获取ExcelReader指定输入流和sheet
//        ExcelReader excelReader = ExcelUtil.getReader(inputStream, "导入材料清单");
//        // 可以加上表头验证
//        // 3.读取第二行到最后一行数据
//        List<List<Object>> read = excelReader.read(2, excelReader.getRowCount());
//        for (List<Object> objects : read) {
//            // objects.get(0),读取某行第一列数据
//            // objects.get(1),读取某行第二列数据
//            System.out.println(objects.get(0));
//        }


        //调用用 hutool 方法读取数据 默认调用第一个sheet
        ExcelReader excelReader = ExcelUtil.getReader(inputStream);
        //从第二行开始获取数据   excelReader.read的结果是一个2纬的list,外层是行,内层是行对应的所有列
        //读取方式1
//        List<List<Object>> read = excelReader.read(1, excelReader.getRowCount());
//        //System.out.println("数据:"+read);
//        List<Excel> excels = new ArrayList<>();
//        //循环获取的数据
//        for (int i = 0; i < read.size(); i++) {
//            List list = read.get(i);
//            Excel excel = new Excel();
//            excel.setName(list.get(0).toString());
//            excel.setAge(Integer.parseInt(list.get(1).toString()));
//            excel.setHeight(Double.parseDouble(list.get(2).toString()));
//            excel.setWeight(Double.parseDouble(list.get(3).toString()));
//            excel.setEdu(list.get(4).toString());
//            excel.setStatus(Integer.parseInt(list.get(5).toString()));
//            excels.add(excel);
//        }
        
        //读取方式2
        //读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值。
        List<Excel> excels = excelReader.readAll(Excel.class);

        service.addList(excels);
        System.out.println("导入成功");
        return "excelImport";

    }


}

采用读取方式1,需要将各列的值赋给model对应的属性

//读取方式1
        List<List<Object>> read = excelReader.read(1, excelReader.getRowCount());
        //System.out.println("数据:"+read);
        List<Excel> excels = new ArrayList<>();
        //循环获取的数据
        for (int i = 0; i < read.size(); i++) {
            List list = read.get(i);
            Excel excel = new Excel();
            excel.setName(list.get(0).toString());
            excel.setAge(Integer.parseInt(list.get(1).toString()));
            excel.setHeight(Double.parseDouble(list.get(2).toString()));
            excel.setWeight(Double.parseDouble(list.get(3).toString()));
            excel.setEdu(list.get(4).toString());
            excel.setStatus(Integer.parseInt(list.get(5).toString()));
            excels.add(excel);
        }

方式2省事些,可以直接赋值给对象

//读取方式2
        //读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值。
        List<Excel> excels = excelReader.readAll(Excel.class);

运行结果

excel03和07都能导入

java同包导入类 java导入类库_spring_04

java同包导入类 java导入类库_apache_05

java同包导入类 java导入类库_java_06

补充知识:ExcelReader

来自:https://www.hutool.cn/docs/#/poi/Excel%E8%AF%BB%E5%8F%96-ExcelReader

介绍

读取Excel内容的封装,通过构造ExcelReader对象,指定被读取的Excel文件、流或工作簿,然后调用readXXX方法读取内容为指定格式。

使用

  1. 读取Excel中所有行和列,都用列表表示
ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");
List<List<Object>> readAll = reader.read();
  1. 读取为Map列表,默认第一行为标题行,Map中的key为标题,value为标题对应的单元格值。
ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");
List<Map<String,Object>> readAll = reader.readAll();
  1. 读取为Bean列表,Bean中的字段名为标题,字段值为标题对应的单元格值。
ExcelReader reader = ExcelUtil.getReader("d:/aaa.xlsx");
List<Person> all = reader.readAll(Person.class);