Java无模版导出Excel 0基础教程

0 写在前面

经常写数据导出到EXCEL,没有模板的情况下使用POI技术。以此作为记录,以后方便使用。

1 依赖

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

2 工具类

样式工具:

import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.hssf.usermodel.HeaderFooter;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.*;import java.io.UnsupportedEncodingException;public class ExcelStyleUtils {/*** 生成标题样式* @param workbook* @return*/public static XSSFCellStyle genTitleStyle(XSSFWorkbook workbook) {// 创建标题样式XSSFCellStyle style = workbook.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);style.setWrapText(true);// 标题居中,没有边框,所以这里没有设置边框,设置标题文字样式XSSFFont titleFont = workbook.createFont();// 加粗titleFont.setBold(true);// 文字尺寸titleFont.setFontHeight((short) 15);titleFont.setFontHeightInPoints((short) 15);style.setFont(titleFont);return style;}/*** 生成表头样式* @param workbook* @return*/public static XSSFCellStyle genTableStyle(XSSFWorkbook workbook) {// 创建表头样式XSSFCellStyle style = workbook.createCellStyle();style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);style.setWrapText(true);style.setBorderRight(BorderStyle.THIN);style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderLeft(BorderStyle.THIN);style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderTop(BorderStyle.THIN);style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderBottom(BorderStyle.THIN);style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 设置字体样式Font headerFont = workbook.createFont();headerFont.setFontName("Arial");headerFont.setFontHeightInPoints((short) 10);headerFont.setBold(true);headerFont.setColor(IndexedColors.WHITE.getIndex());style.setFont(headerFont);return style;}/*** 创建文本样式* @param workbook* @return*/public static XSSFCellStyle genContextStyle(XSSFWorkbook workbook) {XSSFCellStyle style = workbook.createCellStyle();// 文本水平居中显示style.setAlignment(HorizontalAlignment.CENTER);// 文本竖直居中显示style.setVerticalAlignment(VerticalAlignment.CENTER);// 文本自动换行style.setWrapText(true);//生成Excel表单,需要给文本添加边框样式和颜色/*CellStyle.BORDER_DOUBLE      双边线CellStyle.BORDER_THIN        细边线CellStyle.BORDER_MEDIUM      中等边线CellStyle.BORDER_DASHED      虚线边线CellStyle.BORDER_HAIR        小圆点虚线边线CellStyle.BORDER_THICK       粗边线*/// 设置文本边框style.setBorderBottom(BorderStyle.THIN);style.setBorderLeft(BorderStyle.THIN);style.setBorderRight(BorderStyle.THIN);style.setBorderTop(BorderStyle.THIN);// 设置文本边框颜色style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());// 设置字体样式XSSFFont contextFont = workbook.createFont();contextFont.setFontName("Arial");// 文字尺寸contextFont.setFontHeightInPoints((short) 10);style.setFont(contextFont);return style;}/*** 设置表单,并生成表单* @param workbook* @param sheetName* @return*/public static XSSFSheet genSheet(XSSFWorkbook workbook, String sheetName){// 生成表单XSSFSheet sheet = workbook.createSheet(sheetName);// 设置表单文本居中sheet.setHorizontallyCenter(true);sheet.setFitToPage(false);// 打印时在底部右边显示文本页信息Footer footer = sheet.getFooter();footer.setRight( "Page " + HeaderFooter.numPages()+ " Of "+ HeaderFooter.page());// 打印时在头部右边显示Excel创建日期信息Header header = sheet.getHeader();header.setRight("Create Date " + HeaderFooter.date() + " " + HeaderFooter.time());// 设置打印方式XSSFPrintSetup ps = sheet.getPrintSetup();ps.setLandscape(true); // true:横向打印,false:竖向打印 ,因为列数较多,推荐在打印时横向打印ps.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); // 打印尺寸大小设置为A4纸大小return sheet;}/*** 自适应宽度处理*/public static void setAutoColumnWidth(XSSFSheet sheet, int maxColumnNum) {try {for (int columnNum = 0; columnNum <= maxColumnNum; columnNum++) {int columnWidth = sheet.getColumnWidth(columnNum) / 256;for (int rowNum = 1; 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);int length = currentCell.toString().getBytes("GBK").length;if (columnWidth < length + 1) {columnWidth = length + 1;}}}int maxWith = 128 * 255;if (columnWidth * 300 > maxWith) {sheet.setColumnWidth(columnNum, maxWith);} else {sheet.setColumnWidth(columnNum, columnWidth * 300);}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}}/*** 设置某些列的值只能sheet中某列输入预制的数据,显示下拉框.** @param sheet     模板sheet页(需要设置下拉框的sheet)* @param sheetName 隐藏的sheet页,用于存放下拉框的值 (下拉框值对应一列)* @param lastRow   存放下拉框值的最后一行* @param col       存放下拉框值的列名 "A"* @param firstRow  添加下拉框对应开始行* @param endRow    添加下拉框对应结束行* @param firstCol  添加下拉框对应开始列* @param endCol    添加下拉框对应结束列* @return XSSFSheet 设置好的sheet.*/public static XSSFSheet setXSSFValidation(XSSFSheet sheet, String sheetName, int lastRow, String col, int firstRow, int endRow, int firstCol, int endCol) {// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);// 下拉框列String cell = sheetName + "!$" + col + "$2:$" + col + "$" + lastRow;// 创建验证对象DataValidationHelper helper = sheet.getDataValidationHelper();DataValidationConstraint constraint = helper.createFormulaListConstraint(cell);// 这句话是关键 引用ShtDict的单元格DataValidation dataValidate = helper.createValidation(constraint, regions);dataValidate.setSuppressDropDownArrow(true);dataValidate.createErrorBox("提示", "请输入规定范围内容");dataValidate.setShowErrorBox(true);sheet.addValidationData(dataValidate);return sheet;}}

处理工具Java接口

import org.apache.poi.ss.usermodel.HorizontalAlignment;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SimpleExcel {/*** 导出到Excel中的名字*/String labelName() default "";/*** 自定义日期格式, 如: yyyy-MM-dd*/String dateFormat() default "";/*** 导出数据样式, 居中:左对齐..*/HorizontalAlignment alignStyle() default HorizontalAlignment.CENTER;}

水印工具

/*** Excel 添加水印。支持 SXSSFWorkbook 和 XSSFWorkbook 模式*/
public class WaterMarkUtil {/*** Excel 导出添加水印* @param workbook ExcelWorkbook*/public static void insertWaterMarkTextToXlsx(Workbook workbook, String waterMarkText) throws IOException {// 根据工作博类型两种方式添加水印if (workbook instanceof SXSSFWorkbook) {insertWaterMarkTextToXlsx((SXSSFWorkbook) workbook, waterMarkText);} else if (workbook instanceof XSSFWorkbook) {insertWaterMarkTextToXlsx((XSSFWorkbook) workbook, waterMarkText);}//throw new RemoteException("HSSFWorkbook 模式不支持 Excel 水印");}/*** 给 Excel 添加水印* @param workbook      SXSSFWorkbook* @param waterMarkText 水印文字内容*/public static void insertWaterMarkTextToXlsx(SXSSFWorkbook workbook, String waterMarkText) throws IOException {BufferedImage image = createWatermarkImage(waterMarkText);ByteArrayOutputStream imageOs = new ByteArrayOutputStream();ImageIO.write(image, "png", imageOs);int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);XSSFPictureData pictureData = (XSSFPictureData) workbook.getAllPictures().get(pictureIdx);for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表SXSSFSheet sheet = workbook.getSheetAt(i);//这里由于 SXSSFSheet 没有 getCTWorksheet() 方法,通过反射取出 _sh 属性XSSFSheet shReflect = (XSSFSheet) ReflectUtil.getFieldValue(sheet, "_sh");PackagePartName ppn = pictureData.getPackagePart().getPartName();String relType = XSSFRelation.IMAGES.getRelation();PackageRelationship pr = shReflect.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);shReflect.getCTWorksheet().addNewPicture().setId(pr.getId());}}/*** 给 Excel 添加水印* @param workbook      XSSFWorkbook* @param waterMarkText 水印文字内容*/public static void insertWaterMarkTextToXlsx(XSSFWorkbook workbook, String waterMarkText) throws IOException {BufferedImage image = createWatermarkImage(waterMarkText);ByteArrayOutputStream imageOs = new ByteArrayOutputStream();ImageIO.write(image, "png", imageOs);int pictureIdx = workbook.addPicture(imageOs.toByteArray(), XSSFWorkbook.PICTURE_TYPE_PNG);XSSFPictureData pictureData = workbook.getAllPictures().get(pictureIdx);for (int i = 0; i < workbook.getNumberOfSheets(); i++) {//获取每个Sheet表XSSFSheet sheet = workbook.getSheetAt(i);PackagePartName ppn = pictureData.getPackagePart().getPartName();String relType = XSSFRelation.IMAGES.getRelation();PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);sheet.getCTWorksheet().addNewPicture().setId(pr.getId());}}/*** 创建水印图片* @param waterMark 水印文字*/public static BufferedImage createWatermarkImage(String waterMark) {String[] textArray = waterMark.split("\n");Font font = new Font("microsoft-yahei", Font.PLAIN, 32);int width = 500;int height = 400;BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 背景透明 开始Graphics2D g = image.createGraphics();image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);g.dispose();// 背景透明 结束g = image.createGraphics();g.setColor(new Color(Color.lightGray.getRGB()));// 设定画笔颜色g.setFont(font);// 设置画笔字体// g.shear(0.1, -0.26);// 设定倾斜度//设置字体平滑g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);//文字从中心开始输入,算出文字宽度,左移动一半的宽度,即居中FontMetrics fontMetrics = g.getFontMetrics(font);// 水印位置int x = width / 2;int y = height / 2;// 设置水印旋转g.rotate(Math.toRadians(-40), x, y);for (String s : textArray) {// 文字宽度int textWidth = fontMetrics.stringWidth(s);g.drawString(s, x - (textWidth / 2), y);// 画出字符串y = y + font.getSize();}g.dispose();// 释放画笔return image;}/*** 设置打印的参数* @param wb XSSFWorkbook*/public static void setPrintParams(XSSFWorkbook wb) {XSSFSheet sheet = wb.getSheetAt(0);XSSFPrintSetup printSetup = sheet.getPrintSetup();// 打印方向,true:横向,false:纵向(默认printSetup.setLandscape(true);//设置A4纸printSetup.setPaperSize(XSSFPrintSetup.A4_PAPERSIZE);// 将整个工作表打印在一页(缩放),如果行数很多的话,可能会出问题// sheet.setAutobreaks(true);//将所有的列调整为一页,行数多的话,自动分页printSetup.setScale((short) 70);//缩放的百分比,自行调整sheet.setAutobreaks(false);}}

导出Excel工具类

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;/*** Excel的工具类*/
public class SimpleExcelUtil<T> {/*** 工作薄*/private XSSFWorkbook wb;/*** 工作表*/private XSSFSheet sheet;/*** 需要导出的数据*/private List<T> exportList;/*** 对象的class对象*/private Class<T> clazz;/*** 被选中需要导出的字段名称*/private Map<String, Object> checkedFieldsName;/*** 被选中需要导出的字段对象*/private List<Field> checkedFields;private SimpleExcelUtil() {}public SimpleExcelUtil(Class<T> clazz) {this.clazz = clazz;}/*** 导出Excel* @param list       导出数据列表* @param fieldsName 选中需要导出的字段* @param sheetName  sheet页名称*/public void exportExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String sheetName, String labelTitle, Boolean isWaterMark, String waterMarkText) {// 初始化数据init(list, sheetName, fieldsName);// 加入标题数据createTopTitleRow(labelTitle);// 在标题下方加入表头数据createTopRow();try {// 在表头下方,添加目标数据createOtherRow();// 调整自适应列宽setAutoColumnWidth(sheet, checkedFields.size());// 添加水印try {if (isWaterMark) {WaterMarkUtil.insertWaterMarkTextToXlsx(wb, waterMarkText);}} catch (Exception e) {throw new Exception("添加水印失败");}} catch (Exception e) {e.printStackTrace();}// 生成excel文件并入responsetry {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");response.setHeader("Content-Disposition","attachment;filename=" + new String((labelTitle + ".xlsx").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));wb.write(response.getOutputStream());} catch (IOException e) {e.printStackTrace();} finally {try {wb.close();} catch (IOException e) {e.printStackTrace();}}}/*** 将数据导出Excel(重载,自定义导出列)* @param response* @param list 需要导出的数据* @param fieldsName 自定义导出字段* @param labelTitle 首行标题内容*/public void exportExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String labelTitle) {exportExcel(response, list, fieldsName, null, labelTitle, false, null);}/*** 导出含有水印的Excel* @param response* @param labelTitle 首行标题内容* @param list 需要导出的数据* @param fieldsName 自定义导出字段* @param waterMarkText 水印内容*/public void exportWaterMarkExcel(HttpServletResponse response, List<T> list, Map<String, Object> fieldsName, String labelTitle, String waterMarkText) {exportExcel(response, list, fieldsName, null, labelTitle, true, waterMarkText);}/*** sheet页第一行加入导出的标题数据*/private void createTopTitleRow(String title) {Row row = sheet.createRow(0);// 设定固定行高row.setHeightInPoints(30);Cell cell = row.createCell(0);//前端只传一个值合并单元格报错if (checkedFields.size() > 1) {// 对标题所处列进行单元格的合并(对应下面导出的字段列数)CellRangeAddress region = new CellRangeAddress(0, 0, 0, checkedFields.size() - 1);sheet.addMergedRegion(region);}// 设置单元格样式CellStyle style = wb.createCellStyle();// 设置单元格水平样式style.setAlignment(HorizontalAlignment.CENTER);// 设置单元格垂直样式style.setVerticalAlignment(VerticalAlignment.CENTER);// 设置字体样式Font font = wb.createFont();font.setBold(true);font.setFontHeightInPoints((short) 15);font.setFontName("Arial");font.setColor(IndexedColors.BLACK.getIndex());style.setFont(font);cell.setCellValue(title);cell.setCellStyle(style);}/*** sheet第二行加入表头数据*/private void createTopRow() {Row row = sheet.createRow(1);// 设定固定行高row.setHeightInPoints(20);for (int index = 0; index < checkedFields.size(); index++) {Cell cell = row.createCell(index);cell.setCellValue(checkedFields.get(index).getAnnotation(SimpleExcel.class).labelName());// 表头格式CellStyle style = wb.createCellStyle();style.setBorderRight(BorderStyle.THIN);style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderLeft(BorderStyle.THIN);style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderTop(BorderStyle.THIN);style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderBottom(BorderStyle.THIN);style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setAlignment(HorizontalAlignment.CENTER);style.setVerticalAlignment(VerticalAlignment.CENTER);style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);Font headerFont = wb.createFont();headerFont.setFontName("Arial");headerFont.setFontHeightInPoints((short) 10);headerFont.setBold(true);headerFont.setColor(IndexedColors.WHITE.getIndex());style.setFont(headerFont);cell.setCellStyle(style);}}/*** 添加导出数据*/private void createOtherRow() throws IllegalAccessException {// 导出数据格式CellStyle style = wb.createCellStyle();style.setVerticalAlignment(VerticalAlignment.CENTER);style.setBorderRight(BorderStyle.THIN);style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderLeft(BorderStyle.THIN);style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderTop(BorderStyle.THIN);style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());style.setBorderBottom(BorderStyle.THIN);style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());Font dataFont = wb.createFont();dataFont.setFontName("Arial");dataFont.setFontHeightInPoints((short) 10);style.setFont(dataFont);for (int rowNum = 2; rowNum <= exportList.size() + 1; rowNum++) {Row row = sheet.createRow(rowNum);row.setHeightInPoints(18);T t = exportList.get(rowNum - 2);for (int colNum = 0; colNum < checkedFields.size(); colNum++) {Cell cell = row.createCell(colNum);Field field = checkedFields.get(colNum);field.setAccessible(true);// 处理不同单元格字段对应不同样式if (colNum != 0) {CellStyle cStyle = wb.createCellStyle();cStyle.cloneStyleFrom(row.getCell(colNum - 1).getCellStyle());cStyle.setAlignment(checkedFields.get(colNum).getAnnotation(SimpleExcel.class).alignStyle());cell.setCellStyle(cStyle);addCell(cell, field, t);continue;}// 单元格水平样式自定义style.setAlignment(checkedFields.get(colNum).getAnnotation(SimpleExcel.class).alignStyle());cell.setCellStyle(style);// 单元格设置值addCell(cell, field, t);}}}/*** 单元格中添加数据* @param cell  单元格* @param field 字段* @param t     list中的一条数据*/private void addCell(Cell cell, Field field, T t) throws IllegalAccessException {Class<?> fieldType = field.getType();if (String.class == fieldType && field.get(t) != null) {cell.setCellValue((String) field.get(t));} else if (((Integer.TYPE == fieldType) || (Integer.class == fieldType)) && field.get(t) != null) {cell.setCellValue((Integer) field.get(t));} else if (((Long.TYPE == fieldType) || (Long.class == fieldType)) && field.get(t) != null) {cell.setCellValue((Long) field.get(t));} else if (((Double.TYPE == fieldType) || (Double.class == fieldType)) && field.get(t) != null) {cell.setCellValue((Double) field.get(t));} else if (((Float.TYPE == fieldType) || (Float.class == fieldType)) && field.get(t) != null) {cell.setCellValue((Float) field.get(t));} else if (BigDecimal.class == fieldType && field.get(t) != null) {cell.setCellValue(((BigDecimal) field.get(t)).toString());} else if (Date.class == fieldType && field.get(t) != null) {String dateFormat = field.getAnnotation(SimpleExcel.class).dateFormat();cell.setCellValue(dateFormat((Date) field.get(t), dateFormat));}}/*** 时间格式转换* @param date       日期* @param dateFormat 日期格式* @return*/private String dateFormat(Date date, String dateFormat) {// 默认格式if (dateFormat == null || "".equals(dateFormat)) {dateFormat = "yyyy-MM-dd";}SimpleDateFormat df = new SimpleDateFormat(dateFormat);return df.format(date);}/*** 初始化*/public void init(List<T> list, String sheetName, Map<String, Object> fieldsName) {this.exportList = list;this.checkedFieldsName = fieldsName;// 初始化导出数据initExportList();// 初始化工作薄initWorkbook();// 初始化工作表initSheet(sheetName == null ? "Sheet1" : sheetName);// 初始化待导出的字段initFields();}/*** 初始化导出数据*/private void initExportList() {// 防止导出过程中出现空指针if (Objects.isNull(this.exportList)) {this.exportList = new ArrayList<>();}}/*** 初始化工作簿*/private void initWorkbook() {this.wb = new XSSFWorkbook();}/*** 初始化工作表*/private void initSheet(String sheetName) {this.sheet = wb.createSheet(sheetName);}/*** 初始化checkedFields* checkedFields用户选中的字段* 1.如果checkedFieldsName没有定义(未自定义导出字段),所有字段全部导出* 2.如果checkedFieldsName进行了定义,根据定义字段进行导出*/private void initFields() {// 获取对象所有字段对象Field[] fields = clazz.getDeclaredFields();// 过滤出checkedFieldsthis.checkedFields = Arrays.asList(fields).stream().filter(item -> {if (!Objects.isNull(this.checkedFieldsName)) {if (item.isAnnotationPresent(SimpleExcel.class)) {return checkedFieldsName.containsKey(item.getName());}} else {return item.isAnnotationPresent(SimpleExcel.class);}return false;}).collect(Collectors.toList());}/*** 自适应宽度处理*/private static void setAutoColumnWidth(XSSFSheet sheet, int maxColumnNum) {try {for (int columnNum = 0; columnNum <= maxColumnNum; columnNum++) {int columnWidth = sheet.getColumnWidth(columnNum) / 256;for (int rowNum = 1; 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);int length = currentCell.toString().getBytes("GBK").length;if (columnWidth < length + 1) {columnWidth = length + 1;}}}int maxWith = 128 * 255;if (columnWidth * 300 > maxWith) {sheet.setColumnWidth(columnNum, maxWith);} else {sheet.setColumnWidth(columnNum, columnWidth * 300);}}} catch (UnsupportedEncodingException e) {e.printStackTrace();}}}

3 测试代码

与实际复杂业务不同 在此我们只做模拟

3.1实体User 类

import lombok.Data;@Data
public class User {// 姓名private String name;// 性别private String sex;// 年龄private Integer age;// 邮箱private String email;// 生日private String birthday;// 住址private String address;public User(String name, String sex, Integer age, String email, String birthday, String address) {this.name = name;this.sex = sex;this.age = age;this.email = email;this.birthday = birthday;this.address = address;}
}

Controller

import com.example.demo17.service.ExcelTestService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;@RestController
@RequestMapping("/test")
public class ExcelTestController {@Resourceprivate ExcelTestService excelTestService;@GetMapping("/export-excel")public void export(HttpServletResponse response) {excelTestService.exportExcel(response);}}

Service

import javax.servlet.http.HttpServletResponse;public interface ExcelTestService {void exportExcel(HttpServletResponse response);
}
import com.example.demo17.demos.web.User;
import com.example.demo17.util.ExcelStyleUtils;
import com.example.demo17.util.WaterMarkUtil;
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.*;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/*** @Classname ExcelTestServiceImpl* @Date 2024/7/18 14:30* @Created by Yue Teng*/
@Service("ExcelTestService")
public class ExcelTestServiceImpl implements ExcelTestService{@Overridepublic void exportExcel(HttpServletResponse response) {// 模拟数据User user1 = new User("岳腾", "男", 23, "ateng1118@163.com", "2001-02-17", "泰山区山东出版(泰山)文创设计产业园");User user2 = new User("岳公凯", "男", 23, "fengyexieyang@gmail.com", "2001-03-01", "淄博市高新区仪器仪表产业园");User user3 = new User("路舜", "男", 22, "1078550822@qq.com", "2002-06-13", "槐荫区华图教育");User user4 = new User("王尊贞", "男", 24, "2323189192@qq.com", "2000-12-25", "历城区中建凤栖第");List<User> users = new ArrayList<>();users.add(user1);users.add(user2);users.add(user3);users.add(user4);// 初始化导出文件名字String labelTitle = "人员表.xlsx";//设置导出格式String excelName = new String(labelTitle.getBytes(), StandardCharsets.ISO_8859_1);// 创建工作簿XSSFWorkbook excel = new XSSFWorkbook();// 绘制第一个sheet -> 人员表creatUserSheet(excel,users);// 生成excel文件并入responsetry {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");response.setHeader("Content-Disposition", "attachment;filename=" + excelName);excel.write(response.getOutputStream());excel.close();} catch (IOException e) {e.printStackTrace();}}/*** 绘制sheet* @param excel* @param users*/private void creatUserSheet(XSSFWorkbook excel , List<User> users) {// 设置sheet名称XSSFSheet sheet = excel.createSheet();// 此处sheetIndex的参数代表值绘制的第几个sheet页,如果有绘制多个sheet的需求,则0,1,2,3,4……这样创建,不同的sheet页可以复用一个方法或者单独写不同的方法excel.setSheetName(0, "人员");XSSFCellStyle header = ExcelStyleUtils.genContextStyle(excel);header.setFillPattern(FillPatternType.SOLID_FOREGROUND);    //设置填充方案header.setFillForegroundColor(IndexedColors.YELLOW.getIndex());  //设置填充颜色// 创建标题XSSFRow titleRow = sheet.createRow(0);XSSFCell titleCell = titleRow.createCell(0);// 合并标题单元格 4个参数分别为 起始行 截止行 起始列 截止列sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 6));titleCell.setCellValue("人员明细");// 设置标题样式XSSFCellStyle titleStyle = ExcelStyleUtils.genTitleStyle(excel);titleCell.setCellStyle(titleStyle);// 创建表头1XSSFRow tableRow1 = sheet.createRow(2);// 创建表头样式XSSFCellStyle tableStyle = ExcelStyleUtils.genTableStyle(excel);// 组装表头数据String[] tableTitleInit = {"序号", "姓名", "性别", "年龄", "邮箱", "生日" , "住址"};for (int i = 0; i < tableTitleInit.length; i++) {XSSFCell tableRowCell = tableRow1.createCell(i);tableRowCell.setCellStyle(tableStyle);tableRowCell.setCellValue(tableTitleInit[i]);}// 对以上数据设置自适应宽度ExcelStyleUtils.setAutoColumnWidth(sheet, 6);// 主数据内容导出// 记录行数从表头下方(第四行)开始int rowNum = 3;// 创建文本样式XSSFCellStyle contextStyle = ExcelStyleUtils.genContextStyle(excel);for (int i = 0; i < users.size(); i++) {// 创建数据行XSSFRow tableRow = sheet.createRow(rowNum);// 取导出数据User data = users.get(i);// 进行逐列单元格塞入数据for (int j = 0; j < 7; j++) {XSSFCell rowCell = tableRow.createCell(j);rowCell.setCellStyle(contextStyle);switch (j) {case 0:// 序号rowCell.setCellValue(i + 1);break;case 1:// 姓名rowCell.setCellValue(data.getName());break;case 2:// 性别rowCell.setCellValue(data.getSex());break;case 3:// 年龄rowCell.setCellValue(data.getAge());break;case 4:// 邮箱rowCell.setCellValue(data.getEmail());break;case 5:// 生日rowCell.setCellValue(birthdayConvert(data.getBirthday()));break;case 6:// 住址rowCell.setCellValue(data.getAddress());break;}}rowNum++;}// 对以上数据设置自适应宽度ExcelStyleUtils.setAutoColumnWidth(sheet, 7);// 添加水印try {// 定义水印String waterMarkText = "我是水印";WaterMarkUtil.insertWaterMarkTextToXlsx(excel, waterMarkText);} catch (Exception e) {try {throw new Exception("添加水印失败");} catch (Exception ex) {throw new RuntimeException(ex);}}}/*** 生日转换,只用来演示在上方switch - case 语句内部可以转换数据* @param birthday* @return*/public String birthdayConvert(String birthday){Date date = null;try {date = new SimpleDateFormat("yyyy-MM-dd").parse(birthday);} catch (ParseException e) {throw new RuntimeException(e);}return new SimpleDateFormat("yyyy年MM月dd日").format(date);}
}

4 导出测试

使用Postman进行接口测试,没接触过Postman的小伙伴可以看我这篇博客Postman导出excel文件

在这里插入图片描述

保存为文件

在这里插入图片描述

5 写在末尾

可以看到导出很成功,包括水印 sheet页名称自适应宽度。还有一些高亮……等功能可以直接搜索使用

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

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

相关文章

C# 各版本语法新功能汇总

C# 8.0 以后 官网 C# 7.3 》》in C# 7.2 》》 命名参数、具名参数 》》》 条件 ref 表达式 C# 7.1 》》 default 运算符 default 在C#7.1中得到了改进&#xff0c;不再需要default&#xff08;T&#xff09;了 //变量赋值C#7.0 var s "字符串"; s default(s…

鸿蒙基本工程目录

工程级目录 AppScope 中存放应用全局所需要的资源文件。entry 是应用的主模块&#xff0c;存放 HarmonyOS 应用的代码、资源等。oh_modules 是工程的依赖包&#xff0c;存放工程依赖的源文件。build-profile.json5 是工程级配置信息&#xff0c;包括签名、产品配置等。hvigorf…

一文带你了解 GB 18030-2022 字符集

GB18030 全称《‌信息技术 中文编码字符集》‌&#xff0c;‌是我国信息技术领域的强制性国家标准之一&#xff0c;是中华人民共和国国家标准所规定的变长多字节字符集&#xff0c;字符以单字节、双字节或四字节编码。 当前执行标准为 GB 18030-2022&#xff0c;于 2023 年 8 月…

Linux·权限与工具(上)

1. shell命令以及运行原理 Linux严格意义上来说是一个操作系统&#xff0c;我们称之为 "核心(kernel)" &#xff0c;但我们一般的用户不呢个直接使用到核心&#xff0c;因为不会用。所以开发者在核心外面封装了一层 "外壳(shell)" 程序&#xff0c;来与核心…

24暑假算法刷题 | Day15 | LeetCode 110. 平衡二叉树,257. 二叉树的所有路径,404. 左叶子之和,222. 完全二叉树的节点个数

目录 110. 平衡二叉树题目描述题解 257. 二叉树的所有路径题目描述题解 404. 左叶子之和题目描述题解 222. 完全二叉树的节点个数题目描述题解 110. 平衡二叉树 点此跳转题目链接 题目描述 给定一个二叉树&#xff0c;判断它是否是平衡二叉树 平衡二叉树 是指该树所有节点的…

VMware Vsphere创建虚拟机

作者&#xff1a;红米 一、上传系统镜像 1、打开数据中心 2、新建文件夹&#xff0c;存放镜像 3、点击上传文件按钮 4、找到本地镜像上传 二、安装虚拟机 1、创建虚拟机 2、选择创建类型 3、为虚拟机命名并选择虚拟机安装的所在位置 4、选择计算资源 5、选择存储 6、选择兼容…

Linux系统部署MySQL数据库

1.Linux插入光盘&#xff0c;使用df-h获取光盘信息&#xff0c;默认/dev/sr0文件为光盘文件 使用命令 mount -o ro /dev/sr0 /media进行手动挂载 mount -o ro /dev/sr0 /media 2.进入cd /etc/yum.repos.d目录 编辑配置yum库&#xff0c;编辑vim yum.repos [BaseOS] nameba…

什么是IoC控制反转思想?

目录 一.什么是IoC&#xff1f; IoC核心思想 一.什么是IoC&#xff1f; IoC&#xff08;Inversion of Control&#xff09;即控制反转&#xff0c;这里的控制是代表控制权的意思&#xff0c;IoC是一种编程思想&#xff0c;旨在降低代码之间的耦合度、降低代码的维护成本。…

算法力扣刷题记录 五十二【617.合并二叉树】

前言 二叉树篇&#xff0c;继续。 记录 五十二【617.合并二叉树】 一、题目阅读 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要…

算法day04 位运算 插入排序 二分法 对数器

位运算: 1&#xff09;有一个数组只包含这样的数&#xff0c;有几个数出现偶数次&#xff0c;有1个数出现奇数次&#xff0c;要求时间复杂度不超过o(n),怎么求出现奇数次的数。 使用 ^ 异或运算整个数组&#xff0c;偶数次运算结果为0&#xff0c;只留下最后一个奇数次的数。 …

【元器件】二极管、三极管、MOS管

二极管 D 二极管是一种具有两个电极&#xff08;即正极和负极&#xff09;的电子器件。它是一种非线性元件&#xff0c;具有许多重要的功能和应用 三极管 Q 概述 一种控制电流的半导体器件&#xff0c;其作用是把微弱信号放大成幅度值较大的电信号&#xff0c;也用作无触点开…

鸿蒙语言基础类库:【@system.prompt (弹窗)】

弹窗 说明&#xff1a; 从API Version 8 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口[ohos.prompt]。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import prompt from system.prompt;…

6个高效再利用的UI作品集设计模板

UI 作品集是指用户界面设计师的个人作品集。它展示了设计师的设计能力、技巧和风格&#xff0c;也是充分展示他们设计能力的证明。优秀的UI 作品集应具有简洁明了、美观大方、良好的互动体验和明确的目标。本文将从两个方面的介绍 Ui 作品集模板的全部内容&#xff1a;UI 作品集…

JMX 反序列化漏洞

前言 前段时间看到普元 EOS Platform 爆了这个洞&#xff0c;Apache James&#xff0c;Kafka-UI 都爆了这几个洞&#xff0c;所以决定系统来学习一下这个漏洞点。 JMX 基础 JMX 前置知识 JMX&#xff08;Java Management Extensions&#xff0c;即 Java 管理扩展&#xff0…

叉车指纹一键启动/熄火车辆,“锁”住叉车安全

在现代工业领域&#xff0c;叉车作为重要的物流搬运工具&#xff0c;其安全性和便捷性一直是人们关注的焦点。为此&#xff0c;我们引入了一项技术——叉车指纹一键启动/熄火系统&#xff0c;真正实现了叉车安全的“锁定”。 这项技术不仅仅是简单的启动或关闭车辆的手段&#…

前端:Vue学习-2

前端&#xff1a;Vue学习-2 1. vue的生命周期2. 工程化开发和脚手架Vue CLI2.1 组件化开发2.2 scoped解决样式冲突2.3 data是一个函数2.4 组件通信2.5 非父子通信- event bus事件&#xff0c;provide&inject 3.v-model原理->实现父子组件双向绑定4. sync 修饰符->实现…

centos7 中tcp连接问题

centos对telnet过来的包没有响应 通过tcpdump查看到的TCP连接的不正常的报文&#xff0c;如下 通过tcpdump查看到的TCP连接的正常的报文 &#xff0c;如下 解决方法&#xff1a; cat /proc/sys/net/ipv4/tcp_tw_recycle cat /proc/sys/net/ipv4/tcp_timestamps 如果两个参数…

【Java算法】前缀和 下

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 一.连续数组 题目链接&#xff1a;525.连续数组 代码 public int findMaxLength(int[] nums) {HashMap<Integer,Integer> mapnew HashMap<>();map.put(0,-1);…

【系统架构设计师】十三、软件可靠性(基本概念|软件可靠性建模)

目录 一、基本概念 1.1 定义 1.2 软件可靠性的定量描述 1.3 可靠性测试的意义 1.4 广义的软件可靠性测试和狭义的软件可靠性测试 二、软件可靠性建模 2.1 可靠性模型的组成 2.2 可靠性模型的共同假设 2.3 可靠性模型的重要特性 2.4 可靠性建模方法 往期推荐 历年真…

SD-WAN组网搭建5G备份方案实现方式

SD-WAN&#xff08;Software-Defined Wide Area Network&#xff0c;软件定义广域网&#xff09;结合5G作为备份链路是现代企业网络弹性策略的一部分&#xff0c;尤其是在需要高可用性和快速故障切换的场景下。以下是实现SD-WAN组网并集成5G备份方案的一般步骤&#xff1a; 1. …