用注解的方式来实现SPIRNG视图转换

本文介绍了一种利用Java注解简化EXCEL和PDF文档生成的方法,通过定义特定的注解,可以轻松地将数据模型转换为EXCEL表格或PDF文档,支持多种字段类型及格式化选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在使用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生成类




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值