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