8 changed files with 576 additions and 93 deletions
@ -0,0 +1,37 @@ |
|||||
|
package com.zscat.mallplus.oms.vo; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonIgnore; |
||||
|
import com.zscat.mallplus.utils.ExportEntityMap; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
/** |
||||
|
* @Author dimengzhe |
||||
|
* @Date 2023/3/27 8:47 |
||||
|
* @Description |
||||
|
*/ |
||||
|
@Data |
||||
|
public class OrderExcelVo { |
||||
|
|
||||
|
@ExportEntityMap(CnName = "订单编号", EnName = "orderSn") |
||||
|
private String orderSn; |
||||
|
@ExportEntityMap(CnName = "下单日期", EnName = "createTime") |
||||
|
private String createTime; |
||||
|
@ExportEntityMap(CnName = "手机号", EnName = "receiverPhone") |
||||
|
private String receiverPhone; |
||||
|
@ExportEntityMap(CnName = "用户名", EnName = "memberUsername") |
||||
|
private String memberUsername; |
||||
|
@ExportEntityMap(CnName = "商品名称", EnName = "goodsName") |
||||
|
private String goodsName; |
||||
|
@ExportEntityMap(CnName = "价格", EnName = "totalAmount") |
||||
|
private String totalAmount; |
||||
|
@ExportEntityMap(CnName = "数量", EnName = "productQuantity") |
||||
|
private String productQuantity; |
||||
|
@ExportEntityMap(CnName = "取货点", EnName = "receiverDetailAddress") |
||||
|
private String receiverDetailAddress; |
||||
|
@ExportEntityMap(CnName = "订单状态", EnName = "statusName") |
||||
|
private String statusName; |
||||
|
@JsonIgnore |
||||
|
private String storeId; |
||||
|
|
||||
|
|
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package com.zscat.mallplus.utils; |
||||
|
|
||||
|
import java.lang.annotation.*; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @date 2020/9/30 17:38 |
||||
|
* @description |
||||
|
*/ |
||||
|
@Target({ElementType.FIELD}) |
||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||
|
@Documented |
||||
|
public @interface ExportEntityMap { |
||||
|
|
||||
|
String EnName() default "数据库列名"; |
||||
|
|
||||
|
String CnName() default "实体映射名"; |
||||
|
} |
@ -0,0 +1,278 @@ |
|||||
|
package com.zscat.mallplus.utils; |
||||
|
|
||||
|
import org.apache.poi.hssf.usermodel.*; |
||||
|
import org.apache.poi.hssf.usermodel.HeaderFooter; |
||||
|
import org.apache.poi.ss.usermodel.*; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.OutputStream; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.text.SimpleDateFormat; |
||||
|
import java.util.*; |
||||
|
|
||||
|
/** |
||||
|
* @author dimengzhe |
||||
|
* @date 2020/9/30 17:02 |
||||
|
* @description |
||||
|
*/ |
||||
|
|
||||
|
public class ExportExcelUtils { |
||||
|
|
||||
|
public static <T> void export(String excelName, List<T> list, Class<T> c, HttpServletResponse response) { |
||||
|
// 设置日期格式
|
||||
|
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||
|
// 设置默认文件名为当前时间:年月日时分秒
|
||||
|
if (excelName == null || excelName == "") { |
||||
|
excelName = df.format(new Date()).toString(); |
||||
|
} else { |
||||
|
excelName = excelName + df.format(new Date()).toString(); |
||||
|
} |
||||
|
// 设置response头信息
|
||||
|
response.reset(); |
||||
|
// 改成输出excel文件
|
||||
|
response.setContentType("application/vnd.ms-excel"); |
||||
|
// response.setHeader("Content-disposition", "attachment; filename="
|
||||
|
// + new String(excelName.getBytes("gb2312"), "ISO-8859-1") + ".xls");
|
||||
|
response.setHeader("Content-Disposition", "attachment;fileName=" |
||||
|
+ excelName+".xls"); |
||||
|
|
||||
|
try { |
||||
|
//创建一个WorkBook,对应一个Excel文件
|
||||
|
HSSFWorkbook wb = new HSSFWorkbook(); |
||||
|
//在Workbook中,创建一个sheet,对应Excel中的工作薄(sheet)
|
||||
|
HSSFSheet sheet = wb.createSheet(excelName); |
||||
|
//设置 边距、页眉、页脚
|
||||
|
HSSFPrintSetup printSetup = sheet.getPrintSetup(); |
||||
|
//打印方向,true:横向,false:纵向(默认)
|
||||
|
printSetup.setLandscape(true); |
||||
|
printSetup.setHeaderMargin(0.2); |
||||
|
printSetup.setFooterMargin(0.2); |
||||
|
//设置打印缩放为88%
|
||||
|
//printSetup.setScale((short) 55);
|
||||
|
printSetup.setFitHeight((short) 0); |
||||
|
printSetup.setFitWidth((short) 1); |
||||
|
// printSetup.setLeftToRight(true);//列从左向右显示②
|
||||
|
// 纸张
|
||||
|
printSetup.setPaperSize(HSSFPrintSetup.A4_PAPERSIZE); |
||||
|
// 页边距(下)
|
||||
|
sheet.setMargin(HSSFSheet.BottomMargin, (double) 0.8); |
||||
|
// 页边距(左)
|
||||
|
sheet.setMargin(HSSFSheet.LeftMargin, (double) 0); |
||||
|
// 页边距(右)
|
||||
|
sheet.setMargin(HSSFSheet.RightMargin, (double) 0); |
||||
|
// 页边距(上)
|
||||
|
sheet.setMargin(HSSFSheet.TopMargin, (double) 0.8); |
||||
|
//设置打印页面为水平居中
|
||||
|
sheet.setHorizontallyCenter(true); |
||||
|
sheet.setVerticallyCenter(true); |
||||
|
sheet.setAutobreaks(false); |
||||
|
sheet.setFitToPage(false); |
||||
|
Footer footer = sheet.getFooter(); |
||||
|
//设置页数
|
||||
|
footer.setCenter("第" + HeaderFooter.page() + "页,共 " + HeaderFooter.numPages() + "页"); |
||||
|
Header header = sheet.getHeader(); |
||||
|
//自定义页眉,并设置页眉 左中右显示信息
|
||||
|
//居中
|
||||
|
// header.setCenter("Center Header");
|
||||
|
//靠左
|
||||
|
header.setLeft(HSSFHeader.font("宋体", "") + |
||||
|
HSSFHeader.fontSize((short) 16) + excelName + ".xls"); |
||||
|
//靠右
|
||||
|
// header.setRight(HSSFHeader.font("Stencil-Normal", "Italic") +
|
||||
|
// HSSFHeader.fontSize((short) 16) + "Right w/ Stencil-Normal Italic font and size 16");
|
||||
|
|
||||
|
//创建单元格,并设置值表头 设置表头居中
|
||||
|
HSSFCellStyle style = wb.createCellStyle(); |
||||
|
//设置边框
|
||||
|
//下边框
|
||||
|
style.setBorderBottom(BorderStyle.THIN); |
||||
|
style.setBorderLeft(BorderStyle.THIN); |
||||
|
//上边框
|
||||
|
style.setBorderTop(BorderStyle.THIN); |
||||
|
//右边框
|
||||
|
style.setBorderRight(BorderStyle.THIN); |
||||
|
//自动换行
|
||||
|
//style.setWrapText(true);
|
||||
|
//创建一个居中格式
|
||||
|
style.setAlignment(HorizontalAlignment.CENTER); |
||||
|
//上下居中
|
||||
|
style.setVerticalAlignment(VerticalAlignment.CENTER); |
||||
|
//设置字体
|
||||
|
HSSFFont font = wb.createFont(); |
||||
|
font.setFontName("宋体"); |
||||
|
|
||||
|
style.setFont(font); |
||||
|
// 填充工作表
|
||||
|
//获取需要转出的excel表头的map字段
|
||||
|
LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>(); |
||||
|
//循环注解里面的值 填入Link集合
|
||||
|
Field[] declaredFields = c.getDeclaredFields(); |
||||
|
|
||||
|
for (Field declaredField : declaredFields) { |
||||
|
//获取注解对象
|
||||
|
ExportEntityMap declaredAnnotation = declaredField.getDeclaredAnnotation(ExportEntityMap.class); |
||||
|
if (declaredAnnotation != null) { |
||||
|
fieldMap.put(declaredAnnotation.EnName(), declaredAnnotation.CnName()); |
||||
|
} |
||||
|
} |
||||
|
fillSheet(sheet, list, fieldMap, style); |
||||
|
//将文件输出
|
||||
|
OutputStream ouputStream = response.getOutputStream(); |
||||
|
wb.write(ouputStream); |
||||
|
ouputStream.flush(); |
||||
|
ouputStream.close(); |
||||
|
} catch (Exception e) { |
||||
|
System.err.println("导出Excel失败!"); |
||||
|
System.err.println(e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据字段名获取字段对象 |
||||
|
* |
||||
|
* @param fieldName 字段名 |
||||
|
* @param clazz 包含该字段的类 |
||||
|
* @return 字段 |
||||
|
*/ |
||||
|
public static Field getFieldByName(String fieldName, Class<?> clazz) { |
||||
|
//logger.info("根据字段名获取字段对象:getFieldByName()");
|
||||
|
// 拿到本类的所有字段
|
||||
|
Field[] selfFields = clazz.getDeclaredFields(); |
||||
|
// 如果本类中存在该字段,则返回
|
||||
|
for (Field field : selfFields) { |
||||
|
//如果本类中存在该字段,则返回
|
||||
|
if (field.getName().equals(fieldName)) { |
||||
|
return field; |
||||
|
} |
||||
|
} |
||||
|
// 否则,查看父类中是否存在此字段,如果有则返回
|
||||
|
Class<?> superClazz = clazz.getSuperclass(); |
||||
|
if (superClazz != null && superClazz != Object.class) { |
||||
|
//递归
|
||||
|
return getFieldByName(fieldName, superClazz); |
||||
|
} |
||||
|
// 如果本类和父类都没有,则返回空
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据字段名获取字段值 |
||||
|
* |
||||
|
* @param fieldName 字段名 |
||||
|
* @param o 对象 |
||||
|
* @return 字段值 |
||||
|
* @throws Exception 异常 |
||||
|
*/ |
||||
|
public static Object getFieldValueByName(String fieldName, Object o) |
||||
|
throws Exception { |
||||
|
//logger.info("根据字段名获取字段值:getFieldValueByName()");
|
||||
|
Object value = null; |
||||
|
//根据字段名得到字段对象
|
||||
|
Field field = getFieldByName(fieldName, o.getClass()); |
||||
|
//如果该字段存在,则取出该字段的值
|
||||
|
if (field != null) { |
||||
|
//类中的成员变量为private,在类外边使用属性值,故必须进行此操作
|
||||
|
field.setAccessible(true); |
||||
|
//获取当前对象中当前Field的value
|
||||
|
value = field.get(o); |
||||
|
} else { |
||||
|
throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 " |
||||
|
+ fieldName); |
||||
|
} |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 根据带路径或不带路径的属性名获取属性值,即接受简单属性名, |
||||
|
* 如userName等,又接受带路径的属性名,如student.department.name等 |
||||
|
* |
||||
|
* @param fieldNameSequence 带路径的属性名或简单属性名 |
||||
|
* @param o 对象 |
||||
|
* @return 属性值 |
||||
|
* @throws Exception 异常 |
||||
|
*/ |
||||
|
public static Object getFieldValueByNameSequence(String fieldNameSequence, |
||||
|
Object o) throws Exception { |
||||
|
// logger.info("根据带路径或不带路径的属性名获取属性值,即接受简单属性名:getFieldValueByNameSequence()");
|
||||
|
Object value = null; |
||||
|
// 将fieldNameSequence进行拆分
|
||||
|
String[] attributes = fieldNameSequence.split("\\."); |
||||
|
if (attributes.length == 1) { |
||||
|
value = getFieldValueByName(fieldNameSequence, o); |
||||
|
} else { |
||||
|
// 根据数组中第一个连接属性名获取连接属性对象,如student.department.name
|
||||
|
Object fieldObj = getFieldValueByName(attributes[0], o); |
||||
|
//截取除第一个属性名之后的路径
|
||||
|
String subFieldNameSequence = fieldNameSequence |
||||
|
.substring(fieldNameSequence.indexOf(".") + 1); |
||||
|
//递归得到最终的属性对象的值
|
||||
|
value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj); |
||||
|
} |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 向工作表中填充数据 |
||||
|
* |
||||
|
* @param sheet excel的工作表名称 |
||||
|
* @param list 数据源 |
||||
|
* @param fieldMap 中英文字段对应关系的Map |
||||
|
* @param style 表格中的格式 |
||||
|
* @throws Exception 异常 |
||||
|
*/ |
||||
|
public static <T> void fillSheet(HSSFSheet sheet, List<T> list, |
||||
|
LinkedHashMap<String, String> fieldMap, HSSFCellStyle style) throws Exception { |
||||
|
//logger.info("向工作表中填充数据:fillSheet()");
|
||||
|
// 定义存放英文字段名和中文字段名的数组
|
||||
|
String[] enFields = new String[fieldMap.size()]; |
||||
|
String[] cnFields = new String[fieldMap.size()]; |
||||
|
// 填充数组
|
||||
|
int count = 0; |
||||
|
for (Map.Entry<String, String> entry : fieldMap.entrySet()) { |
||||
|
enFields[count] = entry.getKey(); |
||||
|
cnFields[count] = entry.getValue(); |
||||
|
count++; |
||||
|
} |
||||
|
//存储最大列宽
|
||||
|
Map<Integer, Integer> maxWidth = new HashMap<>(); |
||||
|
HSSFRow row = sheet.createRow((int) 0); |
||||
|
HSSFCell cell = null; |
||||
|
// 填充表头
|
||||
|
for (int i = 0; i < cnFields.length; i++) { |
||||
|
cell = row.createCell(i); |
||||
|
cell.setCellValue(cnFields[i]); |
||||
|
cell.setCellStyle(style); |
||||
|
sheet.autoSizeColumn(i); |
||||
|
//设置自适应宽高
|
||||
|
maxWidth.put(i, cell.getStringCellValue().getBytes().length * 256 + 200); |
||||
|
} |
||||
|
// 填充内容
|
||||
|
for (int index = 0; index < list.size(); index++) { |
||||
|
row = sheet.createRow(index + 1); |
||||
|
// 获取单个对象
|
||||
|
T item = list.get(index); |
||||
|
int j = 0; |
||||
|
for (int i = 0; i < enFields.length; i++) { |
||||
|
HSSFCell createCell = row.createCell(j); |
||||
|
Object objValue = getFieldValueByNameSequence(enFields[i], item); |
||||
|
String fieldValue = objValue == null ? "" : objValue.toString(); |
||||
|
cell = row.createCell(i); |
||||
|
createCell.setCellValue(fieldValue); |
||||
|
|
||||
|
int length = createCell.getStringCellValue().getBytes().length * 256 + 200; |
||||
|
//这里把宽度最大限制到15000
|
||||
|
if (length > 15000) { |
||||
|
length = 15000; |
||||
|
} |
||||
|
maxWidth.put(j, Math.max(length, maxWidth.get(j))); |
||||
|
j++; |
||||
|
createCell.setCellStyle(style); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 列宽自适应
|
||||
|
for (int i = 0; i < cnFields.length; i++) { |
||||
|
sheet.setColumnWidth(i, maxWidth.get(i)); |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue