Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
package com.example.demo.util;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
/**
* Excel导出自适应宽度工具类
*
* @author LL
* @date 2020/12/02 22:28
*/
public class AdaptiveWidthUtils {
/**
* 自适应宽度(中文支持)
*
* @param sheet sheet
* @param size 因为for循环从0开始,size值为 列数-1
*/
public static void setSizeColumn(Sheet sheet, int size) {
for (int columnNum = 0; columnNum <= size; columnNum++) {
int columnWidth = sheet.getColumnWidth(columnNum) / 256;
for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row currentRow;
//当前行未被使用过
if (sheet.getRow(rowNum) == null) {
currentRow = sheet.createRow(rowNum);
} else {
currentRow = sheet.getRow(rowNum);
}
if (currentRow.getCell(columnNum) != null) {
Cell currentCell = currentRow.getCell(columnNum);
if (currentCell.getCellType() == CellType.STRING) {
int length = currentCell.getStringCellValue().getBytes().length;
if (columnWidth < length) {
columnWidth = length;
}
}
}
}
sheet.setColumnWidth(columnNum, columnWidth * 256);
}
}
}
3.1、实体类
package com.example.demo.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author LL
* @description : 用户信息
* @date 2021/02/25 14:59
*/
@Data
@ApiModel(description = "用户信息")
public class User {
@ApiModelProperty(notes = "id")
private Integer id;
@ApiModelProperty(notes = "姓名")
private String name;
@ApiModelProperty(notes = "年龄")
private Integer age;
}
3.2、controller层
package com.example.demo.controller;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.example.demo.service.UserService;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author LL
* @description : 用户管理模块
* @date 2021/02/25 15:38
*/
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
@Api(value = "user", tags = "用户管理模块")
public class UserController {
private final UserService userService;
@GetMapping("/export/{id}")
@ApiOperation(value = "导出")
public void export(@PathVariable Integer id, HttpServletResponse response) {
// 通过工具类创建writer,默认创建xls格式
ExcelWriter writer = ExcelUtil.getWriter(true);
//自定义标题别名
writer.addHeaderAlias("id", "ID");
writer.addHeaderAlias("name", "姓名");
writer.addHeaderAlias("age", "年龄");
// 合并单元格后的标题行,使用默认标题样式
writer.merge(2, "用户信息");
// 一次性写出内容,使用默认样式,强制输出标题
List<User> userList = userService.exportUser(id);
writer.write(userList, true);
//out为OutputStream,需要写出到的目标流
// 设置所有列为自动宽度,不考虑合并单元格
AdaptiveWidthUtils.setSizeColumn(writer.getSheet(), 2);
//response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
//test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
ServletOutputStream out = null;
try {
String fileName = URLEncoder.encode("用户信息.xlsx", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
out = response.getOutputStream();
writer.flush(out, true);
} catch (IOException e) {
logger.error("用户信息导出异常", e);
} finally {
// 关闭writer,释放内存
writer.close();
}
//此处记得关闭输出Servlet流
IoUtil.close(out);
}
}
3.3、service层
package com.example.demo.service;
import com.example.demo.model.User;
import java.util.List;
/**
* @author LL
* @description : 用户管理
* @date 2021/02/25 15:54
*/
public interface UserService {
/**
* 导出用户信息
* @param id 用户信息id
*/
List<User> exportUser(Integer id);
}
package com.example.demo.service;
import com.example.demo.dao.UserMapper;
import com.example.demo.model.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author LL
* @description :
* @date 2021/02/25 16:11
*/
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Override
public List<User> exportUser(Integer id) {
userMapper.exportUser(id);
}
}
3.4、dao层
package com.example.demo.dao;
import com.example.demo.model.User;
import java.util.List;
/**
* @author LL
* @description : 用户管理
* @date 2021/02/25 16:13
*/
public interface UserMapper {
/**
* 导出用户信息
*
* @param id 用户信息id
*/
List<User> exportUser(Integer id);
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserMapper">
<sql id="TableName">
tbl_user
sql>
<select id="exportUser">
SELECT
*
FROM
tbl_user
WHERE
id = #{id}
select>
mapper>
提示(since 4.1.5)
默认情况下Excel中写出Bean字段不能保证顺序,此时可以使用addHeaderAlias方法设置标题别名,Bean的写出顺序就会按照标题别名的加入顺序排序。
如果不需要设置标题但是想要排序字段,请调用writer.addHeaderAlias(“age”,
“age”)设置一个相同的别名就可以不更换标题。 未设置标题别名的字段不参与排序,会默认排在前面。
Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,每次调用merge(合并单元格)或者write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,只有调用flush或者close方法后才会真正写出文件。
由于机制原因,在写出结束后需要关闭ExcelWriter对象,调用close方法即可关闭,此时才会释放Workbook对象资源,否则带有数据的Workbook一直会常驻内存。
如遇到问题,欢迎留言,我会及时回复!