2023-04-27写好的,代码已上传,看这篇链接:https://www.jianshu.com/p/4f7df3148a63
基于poi5.x,jxl2.x版本,下载jar包,引入到项目中即可,poi或者jxl想使用哪个就引入哪个依赖。
以下内容为旧内容不用看了
一、先进行效果展示
image.png
二、问题
开发过程中发现了如下问题
若A3,A4,A5都一致,那么就需要合并,标题4这列的计算为A1C1+A2C2+A3*C3=D3合并列,因为计算后D1为12,D2累加后为:24,D3累加后为:36,所以理论上要保留36,但是合并后,却是D1的值。这时候就需要获取到合并的首行,然后将其设置为最终计算列D3的值了。
见代码: hssfSheet.getRow((i+j-count) < j ? j : (i+j-count)).getCell(3).setCellValue(bigDecimal.floatValue());单元格如果使用默认的,在计算完数字之后,打开excel文件,加入求和公式等函数,计算结果不准确的问题。
解决:需要对单元格设置为数字类型:cell4.setCellType(CellType.NUMERIC);
三、代码
package com.util.poi;
import com.alibaba.excel.util.DateUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class ExcelMain {
static class Student {
private String id;
private String userName;
private String passWord;
private Float score;
public Student(String id, String userName, String passWord, Float score) {
this.id = id;
this.userName = userName;
this.passWord = passWord;
this.score = score;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
public Float getScore() {
return score;
}
public void setScore(Float score) {
this.score = score;
}
}
public static void main(String[] args) {
String fileName = String.format("《%s》项目测试文件生成%s", "测试导出", DateUtils.format(new Date(), "yyyy-MM-dd"));
System.out.println("文件名:" + fileName);
System.out.println("文件存放系统临时路径:" + System.getProperty("java.io.tmpdir"));
// 创建一个Excel
HSSFWorkbook workbook = new HSSFWorkbook();
// 创建一个shell标签
HSSFSheet hssfSheet = workbook.createSheet(fileName);
// 设置单元格默认宽度
hssfSheet.setDefaultColumnWidth(20);
// excel设置列数
String[] titleArr = {"标题1","标题2","标题3","标题4"};
// 在shell里面增加一个合并单元格(此列合并第一行到第titleArr.length行,第一行行标为0,所以第四行是titleArr.length-1)
hssfSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, titleArr.length-1));
// 创建第0行,即第一行
HSSFRow titleRow = hssfSheet.createRow(0);
// 创建标题样式
HSSFCellStyle titleCellStyle = createTitleCellStyle(workbook);
// 为什么循环titleArr.length呢?因为设置了边框,如果只创建一个单元格,合并后其他三个没边框
for (int i = 0; i < titleArr.length; i++) {
HSSFCell titleCell = titleRow.createCell(i);
titleCell.setCellValue("合并单元格的第一列的标题");
titleCell.setCellStyle(titleCellStyle);
}
HSSFCell hssfCell = null;
HSSFRow row = hssfSheet.createRow(1);
for (int i = 0; i < titleArr.length; i++) {
hssfCell = row.createCell(i);//列索引从0开始
hssfCell.setCellValue(titleArr[i]);//列名1
hssfCell.setCellStyle(titleCellStyle);//列居中显示
}
// 写入实体数据,下方的list应当是从数据库查询出来的数据,这里模拟
Student person1 = new Student("1","赵本山","10086", 11.20f);
Student person2 = new Student("1","赵本山","10086", 12.20f);
Student person3 = new Student("2","赵本山","10010", 14.00f);
Student person4 = new Student("2","赵本山","10010", 16.00f);
Student person5 = new Student("3","宋小宝","10086", 18.33f);
Student person6 = new Student("4","文松","10086", 9.9f);
Student person7 = new Student("5","小损样","10086", 6.00f);
Student person8 = new Student("6","谢大脚","10086", 151f);
List list = new ArrayList<>();
list.add(person1);
list.add(person1);
list.add(person1);
list.add(person2);
list.add(person4);
list.add(person3);
list.add(person3);
list.add(person5);
list.add(person6);
list.add(person6);
list.add(person6);
list.add(person7);
list.add(person8);
// 定义数据单元格的样式
HSSFCellStyle columCellStyle = createColumCellStyle(workbook);
// 定义一个合并单元格集合
List cellRangeAddressList = new ArrayList<>();
String watch = null;
int count = 0; //计数器用来计算需要合并的列数
BigDecimal bigDecimal = null; //用来计算数值的
//为啥j定义为2呢,因为第一行是【合并单元格的第一列的标题】,第二行是titleArr的标题,所以从第三行开始创建数据行
for (int i = 0, j = 2; i < list.size(); i++) {
row = hssfSheet.createRow(i+j);
Student person = list.get(i);
String id = person.getId();
String userName = person.getUserName();
String passWord = person.getPassWord();
Float score = person.getScore();
HSSFCell cell = row.createCell(0);
cell.setCellValue(id);
cell.setCellStyle(columCellStyle);
// 第一个循环,watch肯定是空的,要设置值的
if (StringUtils.isEmpty(watch)){
watch = userName;
bigDecimal = new BigDecimal(0);
}
// 以name为合并依据,即:名称相同的合并
if (watch.equals(userName)){
count++;
bigDecimal = bigDecimal.add(new BigDecimal(score).multiply(new BigDecimal(id)));
}else {
watch = userName;
if (count > 1){
try {
cellRangeAddressList.add(new CellRangeAddress(i+j-count, i+j-1, 0, 0));
cellRangeAddressList.add(new CellRangeAddress(i+j-count, i+j-1, 3, 3));
hssfSheet.getRow((i+j-count) < j ? j : (i+j-count)).getCell(3).setCellValue(bigDecimal.floatValue());
} catch (Exception e) {
e.printStackTrace();
}
}
count = 1;
bigDecimal = new BigDecimal(score).multiply(new BigDecimal(id));
}
// 若是遍历到最后一行,还存在需要合并的需要做判断,否则会跳出循环不合并
if (i == (list.size()-1) && count > 1){
try {
cellRangeAddressList.add(new CellRangeAddress(i+j-count+1, i+j, 0, 0));
cellRangeAddressList.add(new CellRangeAddress(i+j-count+1, i+j, 3, 3));
hssfSheet.getRow((i+j-count+1) < j ? j : (i+j-count+1)).getCell(3).setCellValue(bigDecimal.floatValue());
} catch (Exception e) {
e.printStackTrace();
}
}
HSSFCell cell1 = row.createCell(0);
cell1.setCellType(CellType.STRING);
cell1.setCellValue(userName);
cell1.setCellStyle(columCellStyle);
HSSFCell cell2 = row.createCell(1);
cell2.setCellType(CellType.STRING);
cell2.setCellValue(passWord);
cell2.setCellStyle(columCellStyle);
HSSFCell cell3 = row.createCell(2);
cell3.setCellType(CellType.STRING);
cell3.setCellValue(passWord);
cell3.setCellStyle(columCellStyle);
HSSFCell cell4 = row.createCell(3);
short format = workbook.createDataFormat().getFormat("0.00");
cell4.setCellType(CellType.NUMERIC);
cell4.setCellValue(score*3);
cell4.setCellStyle(columCellStyle);
cell4.getCellStyle().setDataFormat(format);
}
for (CellRangeAddress cellRangeAddress : cellRangeAddressList) {
try {
hssfSheet.addMergedRegion(cellRangeAddress);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
File file = new File(System.getProperty("java.io.tmpdir") + "/"+fileName+".xls");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(file);
try {
workbook.write(out);
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (out != null){
out.flush();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 创建标题样式
* @param wb
* @return
*/
private static HSSFCellStyle createTitleCellStyle(HSSFWorkbook wb) {
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.CENTER);//水平居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直对齐
cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
cellStyle.setBorderLeft(BorderStyle.THIN); //左边框
cellStyle.setBorderRight(BorderStyle.THIN); //右边框
cellStyle.setBorderTop(BorderStyle.THIN); //上边
HSSFFont headerFont = (HSSFFont) wb.createFont(); // 创建字体样式
headerFont.setBold(true); //字体加粗
headerFont.setFontName("仿宋"); // 设置字体类型
headerFont.setFontHeightInPoints((short) 15); // 设置字体大小
cellStyle.setFont(headerFont); // 为标题样式设置字体样式
return cellStyle;
}
/**
* 创建标题样式
* @param wb
* @return
*/
private static HSSFCellStyle createColumCellStyle(HSSFWorkbook wb) {
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setAlignment(HorizontalAlignment.LEFT);//水平居中
cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//垂直对齐
cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
cellStyle.setBorderLeft(BorderStyle.THIN); //左边框
cellStyle.setBorderRight(BorderStyle.THIN); //右边框
cellStyle.setBorderTop(BorderStyle.THIN); //上边
HSSFFont headerFont = (HSSFFont) wb.createFont(); // 创建字体样式
headerFont.setBold(false); //字体加粗
headerFont.setFontName("仿宋"); // 设置字体类型
headerFont.setFontHeightInPoints((short) 11); // 设置字体大小
cellStyle.setFont(headerFont); // 为标题样式设置字体样式
return cellStyle;
}
}