在使用SPRING类的时候经常会遇到因为和业务相关,所以很多代码的重用性不高,为了解决这个问题,专门使用JAVA注解的方式来实现公共的EXCEL与PDF生成视图类。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,
ElementType.TYPE})
public @interface Xls {
/**
* 模板地址
*/
public String templateName() default "";
/**
* 开始行
*/
public int startRow() default 0;
/**
* 文件名称
*/
public String fileName() default "";
/**
* 字段类型
*/
public FieldType cellType() default FieldType.STRING;
/**
* 是否加边框
*/
public boolean cellBorder() default true;
}
EXCEL生成注解
public enum FieldType {
/**
* 字符串类型
*/
STRING,
/**
* 时间类型
*/
DATE,
/**
* 货币类型
*/
MONEY,
/**
* 数字类型
*/
NUMBER,
/**
* 浮点类型
*/
DOUBLE;
}
EXCEL字段类型枚举
public class ViewExcel extends AbstractExcelView {
/**
* excel对象
*/
private HSSFWorkbook workbook;
/**
* 输入流
*/
private FileInputStream is;
/**
* 模板开始插入位置
*/
private int startRow;
/**
* 方法用途: 构建EXCEL<br>
* 实现步骤: <br>
* @param model 包含数据的模型类
* @param workbook excel BOOK对象
* @param request 请求
* @param response 响应
* @throws Exception
*/
@Override
protected void buildExcelDocument(Map<String, Object> model,
HSSFWorkbook workbook, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = model.get("xlsData");
String webRoot = request.getServletContext().getRealPath("/");
if(obj.getClass().getName().indexOf("ArrayList") != -1) {
List<Object> objectList = (List<Object>) obj;
readTemplate(webRoot, objectList.get(0), response);
for(int rowNum = 2; rowNum < objectList.size(); rowNum++) {
writeRowList(objectList, response.getOutputStream());
}
} else {
readTemplate(webRoot, obj, response);
writeRowObject(obj, response.getOutputStream());
}
System.gc();
}
/**
*
* 方法用途: 读取模板<br>
* 实现步骤: <br>
* @param webRoot 应用更目录
* @param obj 包装了注解的对象
* @param response 响应
* @throws Exception
*/
public void readTemplate(String webRoot, Object obj, HttpServletResponse response) throws Exception {
if(obj == null) {
throw new NullPointerException("对象为空不能解析模板");
}
Class<?> clazz = obj.getClass();
Xls xls = clazz.getAnnotation(Xls.class);
System.out.println(xls);
String templateName = xls.templateName();
String filename = xls.fileName();
System.out.println(templateName + ":" + filename);
String tempPath = webRoot + "/template/"
+ templateName;
startRow = xls.startRow();
if (filename.equals("")) {
filename = System.currentTimeMillis() + ".xls";
}
response.setHeader("Content-disposition", "attachment;filename=" + filename);
//String writePath = "e:/framework/src/main/webapp/template/" + filename;
File xlsFile = new File(tempPath);
if (!xlsFile.exists()) {
throw new Exception("模板文件不存在");
}
is = new FileInputStream(xlsFile);
workbook = new HSSFWorkbook(is);
}
/**
* 方法用途:写行集合数据 <br>
* 实现步骤: <br>
* @param objectList 集合对象
* @param out 输出对象
* @throws Exception
*/
public void writeRowList(List<Object> objectList, OutputStream out) throws Exception {
HSSFSheet sheet = workbook.getSheetAt(0);
for(int rowNum = 0; rowNum < objectList.size(); rowNum++) {
Object obj = objectList.get(rowNum);
Class<?> clazz = obj.getClass();
HSSFRow row = sheet.createRow(startRow);
for (int cellNum = 0; cellNum < clazz.getDeclaredFields().length; cellNum++) {
HSSFCell cell = row.createCell(cellNum);
setCell(cell, clazz.getDeclaredFields()[cellNum], obj);
}
}
workbook.write(out);
workbook = null;
objectList.clear();
objectList = null;
out.flush();
out.close();
is.close();
}
/**
* 方法用途:写行单个数据 <br>
* 实现步骤: <br>
* @param obj 对象
* @param out 输出对象
* @throws Exception
*/
public void writeRowObject( Object obj, OutputStream out) throws Exception {
HSSFSheet sheet = workbook.getSheetAt(0);
Class<?> clazz = obj.getClass();
HSSFRow row = sheet.createRow(startRow);
System.out.println(clazz.getDeclaredFields().length);
for (int cellNum = 0; cellNum < clazz.getDeclaredFields().length; cellNum++) {
HSSFCell cell = row.createCell(cellNum);
setCell(cell, clazz.getDeclaredFields()[cellNum], obj);
}
workbook.write(out);
workbook = null;
obj = null;
out.flush();
out.close();
is.close();
}
/**
*
* 方法用途: 设置单元格<br>
* 实现步骤: <br>
* @param cell 单元格对象
* @param field 字段对象
* @param obj 放入单元格的值
*/
public void setCell(HSSFCell cell, Field field, Object obj) {
HSSFCellStyle cellStyle = workbook.createCellStyle();
HSSFDataFormat format = workbook.createDataFormat();
Xls fieldXls = field.getAnnotation(Xls.class);
switch (fieldXls.cellType()) {
case STRING: {
if(fieldXls.cellBorder()) {
setBorder(cellStyle);
}
cell.setCellStyle(cellStyle);
Object value = invokeMethod(obj, field.getName(), null);
cell.setCellValue((String) value);
break;
}
case DATE: {
if(fieldXls.cellBorder()) {
setBorder(cellStyle);
}
cellStyle.setDataFormat(format.getFormat("yyyy年m月d日"));
Object value = invokeMethod(obj, field.getName(), null);
Date date = new Date((Long)value);
cell.setCellValue(date);
cell.setCellStyle(cellStyle);
break;
}
case NUMBER: {
if(fieldXls.cellBorder()) {
setBorder(cellStyle);
}
Object value = invokeMethod(obj, field.getName(), null);
cell.setCellValue((Integer) value);
cell.setCellStyle(cellStyle);
break;
}
case DOUBLE: {
if(fieldXls.cellBorder()) {
setBorder(cellStyle);
}
cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));
Object value = invokeMethod(obj, field.getName(), null);
cell.setCellValue((Double) value);
cell.setCellStyle(cellStyle);
break;
}
case MONEY: {
if(fieldXls.cellBorder()) {
setBorder(cellStyle);
}
cellStyle.setDataFormat(format.getFormat("¥#,##0.00"));
Object value = invokeMethod(obj, field.getName(), null);
cell.setCellValue((Double) value);
cell.setCellStyle(cellStyle);
break;
}
}
}
/**
*
* 方法用途: 设置单元格边框<br>
* 实现步骤: <br>
* @param cellStyle
*/
public void setBorder(HSSFCellStyle cellStyle) {
cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN); //下边框
cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);//左边框
cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);//上边框
cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);//右边框
}
/**
*
* 执行某个Field的getField方法
*
* @param owner
* 类
* @param fieldName
* 类的属性名称
* @param args
* 参数,默认为null
* @return
*/
private Object invokeMethod(Object owner, String fieldName, Object[] args) {
Class<? extends Object> ownerClass = owner.getClass();
// fieldName -> FieldName
String methodName = fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Method method = null;
try {
method = ownerClass.getMethod("get" + methodName);
} catch (SecurityException e) {
// e.printStackTrace();
} catch (NoSuchMethodException e) {
// e.printStackTrace();
return "";
}
// invoke getMethod
try {
return method.invoke(owner);
} catch (Exception e) {
return "";
}
}
}
VIEWEXCEL视图解析对象根据注解解析视图
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,
ElementType.TYPE})
public @interface PDF {
/**
* 生成的文件名
*/
public String filename() default "";
/**
* PDF类型:表格,文本,图片
*/
public PDFType type() default PDFType.TABLE;
/**
* PDF的文本纸类型
*/
public PaperType paperType() default PaperType.A4;
/**
* 顶部框
*/
public int borderTop() default 0;
/**
* 低部框
*/
public int borderBottom() default 0;
/**
* 左部框
*/
public int borderLeft() default 0;
/**
* 右部框
*/
public int borderRight() default 0;
/**
* 字体大小
*/
public int fontSize() default 12;
/**
* 字体颜色
*/
public FontColor fontColor() default FontColor.BLACK;
/**
* 字体样式
*/
public FontStyle fontStyle() default FontStyle.NORMAL;
/**
* 表格列数
*/
public int tableRow() default 3;
/**
* 表格头部字段名
*/
public String tableHeader() default "ROW1,ROW2,ROW3";
/**
* PDF标题
*/
public String title() default "";
/**
* PDF科目
*/
public String subject() default "";
/**
* PDF作者
*/
public String author() default "";
/**
* PDF关键字
*/
public String keywords() default "";
/**
* PDF头部栏信息
*/
public String header() default "";
/**
* PDF底部栏信息
*/
public String footer() default "";
/**
* PDF图片类型的图片地址
*/
public String srcPath() default "";
/**
* 图片宽度
*/
public int width() default 100;
/**
* 图片高度
*/
public int height() default 100;
/**
* 字段类型
*/
public FieldType fieldType() default FieldType.DOUBLE;
}
PDF生成注解
public enum PDFType {
/**
* 表格类型PDF
*/
TABLE,
/**
* 文本类型
*/
WORD,
/**
* 图片类型
*/
PICTURE;
}
PDF文档类型枚举
public enum PaperType {
A0(2384,3370), A1(1684,2384), A2(1191,1684), A3(842,1191),
A4(595,842), A5(420,595), A6(297,420), A7(210,297), A8(148,210),
A9(105,148), A10(73,105), B0(2834,4008), B1(2004,2834), B2(1417,2004),
B3(1000,1417), B4(708,1000), B5(498,708), B6(354,498), B7(249,354), B8(175,249),
B9(124,175), B10(87,124);
private PaperType(int width, int height) {
this.width = width;
this.height = height;
}
public String toString() {
return super.toString() + "w:" + width + " h:" + height;
}
public Rectangle getRectangle() {
return new RectangleReadOnly(this.width, this.height);
}
private int width;
private int height;
}
PDF页面大小枚举
public enum FontStyle {
NORMAL(0),
BOLD(1),
ITALIC(2),
UNDERLINE(3),
STRIKETHRU(4),
BOLDITALIC(1|2);
private FontStyle(int value) {
this.value = value;
}
public int getFontStyleValue() {
return this.value;
}
private int value;
}
PDF字体枚举
public enum FontColor {
WHITE(255, 255, 255),
LIGHT_GRAY(192, 192, 192),
GRAY(128, 128, 128),
DARK_GRAY(64, 64, 64),
BLACK(0, 0, 0),
RED(255, 0, 0),
PINK(255, 175, 175),
ORANGE(255, 200, 0),
YELLOW(255, 255, 0),
GREEN(0, 255, 0),
MAGENTA(255, 0, 255),
CYAN(0, 255, 255),
BLUE(0, 0, 255);
/**
* 方法用途: 构造方法
* 实现步骤: 通过颜色的RGB值创建枚举<br>
* @param int rv 红色
* @param int gv 绿色
* @param int bv 蓝色
*/
private FontColor(int rv,int gv,int bv) {
this.redValue=rv;
this.greenValue=gv;
this.blueValue=bv;
}
/**
* 方法用途: 得到颜色对象
* 实现步骤: 通过枚举类型的值创建颜色对象<br>
*
*/
public Color getRGB() {
return new Color(this.redValue, this.greenValue, this.blueValue);
}
public String toString() {
return super.toString() + "R:" + redValue + " G:" + greenValue + " B:" + blueValue;
}
/**
* 红色值
*/
private int redValue;
/**
* 绿色值
*/
private int greenValue;
/**
* 蓝色值
*/
private int blueValue;
}
PDF字体颜色枚举
public class ViewPDF extends AbstractPdfView {
@Autowired
private TypeFormat typeFormat;
/**
* 构建PDF文档方法
* <p>从控制器中读取对象生成PDF文件,该方法继承之AbstractPdfView的buildPdfDocument</p>
* @param model 试图模型对象,以K/V的方式存储传输数据
* @param document PDF文档对象由基类创建
* @param writer PDF流对象用于写PDF文件
* @param request HTTP请求
* @param response HTTP响应
* @exception Exception
*/
@Override
protected void buildPdfDocument(Map<String, Object> model,
Document document, PdfWriter writer, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object obj = model.get("PDFData");
buildPDF(obj, document, writer);
}
/**
* 构建PDF基础内容方法
* <p>从控制器中读取对象生成PDF文件,该方法继承之AbstractPdfView的buildPdfDocument</p>
* @param obj 需要转换的对象根据对象类型自动判断是集合还是单独对像
* @param document PDF文档对象
* @param writer PDF流对象用于写PDF文件
* @exception Exception
*/
public void buildPDF(Object obj, Document document, PdfWriter writer) throws Exception {
Object o = null;
//判断是否为集合对象
if(obj.getClass().getName().indexOf("ArrayList") != -1) {
List<Object> objectList = (List<Object>) obj;
o = objectList.get(0);
} else {
o = obj;
}
Class<?> clazz = o.getClass();
PDF pdf = clazz.getAnnotation(PDF.class);
PaperType paperType = pdf.paperType();
//设置页面
Rectangle rectPageSize = new Rectangle(paperType.getRectangle());
document.setPageSize(rectPageSize);
//设置边距
int top = 10;
int bottom = 10;
int left = 10;
int right = 10;
if(pdf.borderTop() != 0) {
top = pdf.borderTop();
}
if(pdf.borderBottom() != 0) {
bottom = pdf.borderBottom();
}
if(pdf.borderLeft() != 0) {
left = pdf.borderLeft();
}
if(pdf.borderRight() != 0) {
right = pdf.borderRight();
}
document.setMargins(left, right, top, bottom);
//文档名称
String filename = pdf.filename();
if(filename.equals("")) {
filename = System.currentTimeMillis() + ".pdf";
}
//标题
String title = pdf.title();
if(!title.equals("")) {
document.addTitle(title);
}
//主题
String subject = pdf.subject();
if(!subject.equals("")) {
document.addSubject(subject);
}
//作者
String author = pdf.author();
if(!author.equals("")) {
document.addAuthor(author);
}
//关键字
String keywords = pdf.keywords();
if(!author.equals("")) {
document.addKeywords(keywords);
}
//设置文档头与低
buildDocHeaderFooter(document, pdf);
//判断文档类型
switch(pdf.type()) {
case TABLE: {
Table table = buildTable((List<Object>) obj, pdf);
document.add(table);
break;
}
case WORD: {
document = buildText(document, obj);
break;
}
}
}
/**
* 构建文档类PDF
* <p>构建文档类的PDF文件</p>
* @param document PDF文档对象
* @param obj 转换的实体对象
* @return Document 返回包装好的文档对象
* @exception Exception
*/
private Document buildText(Document document, Object obj) throws Exception {
Class<?> clazz = obj.getClass();
//处理每个字段
for(Field field : clazz.getDeclaredFields()) {
PDF pdf = field.getAnnotation(PDF.class);
int size = pdf.fontSize();
int style = pdf.fontStyle().getFontStyleValue();
Color color = pdf.fontColor().getRGB();
switch(pdf.type()) {
case TABLE: {
List<Object> objList = (List<Object>) invokeMethod(obj, field.getName(), null);
Object o = objList.get(0);
PDF cellPdf = o.getClass().getAnnotation(PDF.class);
Table table = buildTable(objList, cellPdf);
document.add(table);
break;
}
case WORD: {
Paragraph par = new Paragraph(getFieldValue(obj, field), getFont(size, style, color));
document.add(par);
break;
}
case PICTURE: {
String path = pdf.srcPath();
int w = pdf.width();
int h = pdf.height();
Image jpeg = Image.getInstance(path);
jpeg.scaleAbsolute(w, h);
jpeg.setAlignment(Image.ALIGN_CENTER);
document.add(jpeg);
break;
}
}
}
return document;
}
/**
* 字段格式化
* <p>根据字段的注解类型格式化成指定的字符串类型</p>
* @param obj 转换的实体对象
* @param field 字段对象
* @return String 返回转换好的字符串
*
*/
private String getFieldValue(Object obj, Field field) {
PDF fieldPdf = field.getAnnotation(PDF.class);
Object value = invokeMethod(obj, field.getName(), null);
String formatValue = "";
switch(fieldPdf.fieldType()) {
case STRING: {
formatValue = value.toString();
break;
}
case MONEY: {
formatValue = typeFormat.formatMoney((double)value);
break;
}
case DATE: {
formatValue = typeFormat.formatCNSimple(new Date((long)value));
break;
}
case DOUBLE: {
formatValue = typeFormat.formatDouble((double)value);
break;
}
case NUMBER: {
formatValue = value.toString();
break;
}
}
return formatValue;
}
/**
* 构建表格
* <p>构建表格类型的文档或者是文档类型嵌套的表格</p>
* @param objList 对象集合
* @param PDF 注解对象
* @return Table 返回构建好的表格对象
* @exception Exception
*/
private Table buildTable(List<Object> objList, PDF pdf) throws Exception {
int row = pdf.tableRow();
Table table = new Table(row);
String[] rowNames = pdf.tableHeader().split(",");
int size = pdf.fontSize();
int style = pdf.fontStyle().getFontStyleValue();
Color color = pdf.fontColor().getRGB();
//设置表格头
for(String rowName : rowNames) {
System.out.println(rowName);
table.addCell(buildCell(rowName, getFont(size, style, color)));
}
//填充表格内容
for(Object obj : objList) {
for(Field field : obj.getClass().getDeclaredFields()) {
table.addCell(buildCell(getFieldValue(obj, field), getFont(size, style, color)));
}
}
return table;
}
/**
* 构建PDF的头部和底部
* <p>根据注解构建PDF文档的头部信息与底部信息</p>
* @param document PDF文档对象
* @param PDF 注解对象
* @return Document 返回包装好的文档对象
* @exception Exception
*/
private void buildDocHeaderFooter(Document document, PDF pdf) throws Exception {
String headerMsg = pdf.header();
String footerMsg = pdf.footer();
int size = pdf.fontSize();
int style = pdf.fontStyle().getFontStyleValue();
Color color = pdf.fontColor().getRGB();
if(!headerMsg.equals("")) {
HeaderFooter header = new HeaderFooter(new Paragraph(headerMsg, getFont(size, style, color)), false);
header.setAlignment(Element.ALIGN_CENTER);
document.setHeader(header);
}
if(!footerMsg.equals("")) {
HeaderFooter footer = new HeaderFooter(new Paragraph(footerMsg, getFont(size, style, color)), false);
footer.setAlignment(Element.ALIGN_CENTER);
document.setFooter(footer);
}
}
/**
* 返回字体
* <p>根据注解构建PDF文档的子体大小,风格,颜色</p>
* @param size 字体大小
* @param style 字体风格
* @param color 字体颜色
* @return Font 返回构建好的字体对象
* @exception Exception
*/
private Font getFont(int size, int style, Color color) throws Exception {
BaseFont bfChinese = BaseFont.createFont("STSongStd-Light",
"UniGB-UCS2-H", false);
Font bold_fontChinese = new Font(bfChinese, size, style, color);
return bold_fontChinese;
}
/**
* 构建单元格
* <p>根据注解构建PDF表格的单元格</p>
* @param value 单元格值
* @param font 字体
* @return Cell 返回构建好的单元格
* @exception Exception
*/
private Cell buildCell(String value, Font font) throws Exception {
return new Cell(new Phrase(value, font));
}
/**
* 执行某个Field的getField方法
* @param owner类
* @param fieldName 类的属性名称
* @param args参数,默认为null
* @return
*/
private Object invokeMethod(Object owner, String fieldName, Object[] args) {
Class<? extends Object> ownerClass = owner.getClass();
// fieldName -> FieldName
String methodName = fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
Method method = null;
try {
method = ownerClass.getMethod("get" + methodName);
} catch (SecurityException e) {
// e.printStackTrace();
} catch (NoSuchMethodException e) {
// e.printStackTrace();
return "";
}
// invoke getMethod
try {
return method.invoke(owner);
} catch (Exception e) {
return "";
}
}
}
PDFVIEW生成类