浏览代码

Use JRFileVirtualizer; Export report to xlsx

sunyj 8 年之前
父节点
当前提交
1b2af71f28

+ 220 - 0
src/main/java/com/uas/report/jasperreports/engine/export/CustomJRXlsxExporter.java

@@ -0,0 +1,220 @@
+package com.uas.report.jasperreports.engine.export;
+
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import com.uas.report.util.ObjectUtils;
+import com.uas.report.util.StringUtils;
+
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRPrintText;
+import net.sf.jasperreports.engine.export.Cut;
+import net.sf.jasperreports.engine.export.JRExporterGridCell;
+import net.sf.jasperreports.engine.export.XlsRowLevelInfo;
+import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
+import net.sf.jasperreports.engine.export.ooxml.XlsxBorderHelper;
+import net.sf.jasperreports.engine.export.ooxml.XlsxStyleHelper;
+import net.sf.jasperreports.engine.util.FileBufferedWriter;
+
+/**
+ * 报表导出为Xls
+ * 
+ * @author sunyj
+ * @since 2016年12月14日 下午8:10:56
+ */
+public class CustomJRXlsxExporter extends JRXlsxExporter {
+
+	/**
+	 * 单元格宽度
+	 */
+	public static final int CELL_WIDTH = 50;
+
+	/**
+	 * 单元格高度
+	 */
+	public static final int CELL_HEIGHT = 12;
+
+	/**
+	 * 单元格边框宽度
+	 */
+	public static final short CELL_BORDER_WIDTH = 1;
+
+	/**
+	 * 单元格边框颜色
+	 */
+	public static final short CELL_BORDER_CORLOR = IndexedColors.GREY_25_PERCENT.index;
+
+	/**
+	 * 是否自定义单元格格式
+	 */
+	private boolean customCellStyle = false;
+
+	public CustomJRXlsxExporter(boolean ifCustomCellStyle) {
+		this.customCellStyle = ifCustomCellStyle;
+	}
+
+	@Override
+	protected void setColumnWidth(int col, int width, boolean autoFit) {
+		if (customCellStyle) {
+			width = CELL_WIDTH;
+		}
+		super.setColumnWidth(col, width, autoFit);
+	}
+
+	@Override
+	protected void setRowHeight(int rowIndex, int rowHeight, Cut yCut, XlsRowLevelInfo levelInfo) throws JRException {
+		if (customCellStyle) {
+			rowHeight = CELL_HEIGHT;
+		}
+		super.setRowHeight(rowIndex, rowHeight, yCut, levelInfo);
+	}
+
+	// @Override
+	// protected HSSFCellStyle getLoadedCellStyle(StyleInfo style) {
+	// HSSFCellStyle cellStyle = super.getLoadedCellStyle(style);
+	// if (customCellStyle) {
+	// cellStyle.setBorderTop(CELL_BORDER_WIDTH);
+	// cellStyle.setBorderLeft(CELL_BORDER_WIDTH);
+	// cellStyle.setBorderBottom(CELL_BORDER_WIDTH);
+	// cellStyle.setBorderRight(CELL_BORDER_WIDTH);
+	// cellStyle.setTopBorderColor(CELL_BORDER_CORLOR);
+	// cellStyle.setLeftBorderColor(CELL_BORDER_CORLOR);
+	// cellStyle.setBottomBorderColor(CELL_BORDER_CORLOR);
+	// cellStyle.setRightBorderColor(CELL_BORDER_CORLOR);
+	// }
+	// return cellStyle;
+	// }
+
+	@Override
+	public void exportText(JRPrintText text, JRExporterGridCell gridCell, int colIndex, int rowIndex)
+			throws JRException {
+		// GridCellStyle style = gridCell.getStyle();
+		// JRLineBox box = style.getBox();
+		// System.out.println(box.getPen().getLineWidth()+" "
+		// +box.getPen().getOwnLineWidth()+" " +box.getPen().getLineColor()+"
+		// "+box.getPen().getOwnLineColor()+"
+		// "+box.getPen().getLineStyleValue()+"
+		// "+box.getPen().getOwnLineStyleValue());
+		// System.out.println(box.getTopPen().getLineWidth()+" "
+		// +box.getTopPen().getOwnLineWidth()+" "
+		// +box.getTopPen().getLineColor()+"
+		// "+box.getTopPen().getOwnLineColor()+"
+		// "+box.getTopPen().getLineStyleValue()+"
+		// "+box.getTopPen().getOwnLineStyleValue());
+		// System.out.println(box.getBottomPen().getLineWidth()+" "
+		// +box.getBottomPen().getOwnLineWidth()+" "
+		// +box.getBottomPen().getLineColor()+"
+		// "+box.getBottomPen().getOwnLineColor()+"
+		// "+box.getBottomPen().getLineStyleValue()+"
+		// "+box.getBottomPen().getOwnLineStyleValue());
+		// System.out.println(box.getLeftPen().getLineWidth()+" "
+		// +box.getLeftPen().getOwnLineWidth()+" "
+		// +box.getLeftPen().getLineColor()+"
+		// "+box.getLeftPen().getOwnLineColor()+"
+		// "+box.getLeftPen().getLineStyleValue()+"
+		// "+box.getLeftPen().getOwnLineStyleValue());
+		// System.out.println(box.getRightPen().getLineWidth()+" "
+		// +box.getRightPen().getOwnLineWidth()+" "
+		// +box.getRightPen().getLineColor()+"
+		// "+box.getRightPen().getOwnLineColor()+"
+		// "+box.getRightPen().getLineStyleValue()+"
+		// "+box.getRightPen().getOwnLineStyleValue());
+		// JRBoxPen pen = box.getPen();
+		// JRBoxPen topPen = box.getTopPen();
+		// JRBoxPen rightPen = box.getRightPen();
+		// JRBoxPen bottomPen = box.getBottomPen();
+		// JRBoxPen leftPen = box.getLeftPen();
+		//
+		// pen.setLineWidth(1);
+		// topPen.setLineWidth(1);
+		// rightPen.setLineWidth(1);
+		// bottomPen.setLineWidth(1);
+		// leftPen.setLineWidth(1);
+		//
+		// box.copyPen(pen);
+		// box.copyTopPen(topPen);
+		// box.copyRightPen(rightPen);
+		// box.copyBottomPen(bottomPen);
+		// box.copyLeftPen(leftPen);
+		super.exportText(text, gridCell, colIndex, rowIndex);
+	}
+
+	// @Override
+	// protected void createTextCell(JRPrintText textElement, JRExporterGridCell
+	// gridCell, int colIndex, int rowIndex,
+	// JRStyledText styledText, StyleInfo baseStyle, short forecolor) throws
+	// JRException {
+	// if (customCellStyle) {
+	// String textStr = styledText.getText();
+	// TextValue textValue = getTextValue(textElement, textStr);
+	// // 类型为String,但是实际值为数值,需设置为字符串类型,否则会提示转为数值型
+	// if ((textValue instanceof StringTextValue && isNumber(textStr)) ||
+	// textValue instanceof NumberTextValue) {
+	// baseStyle.setDataFormat(dataFormat.getFormat("@"));
+	// }
+	// super.createTextCell(textElement, gridCell, colIndex, rowIndex,
+	// styledText, baseStyle, forecolor);
+	//
+	// // 数值类型需明确指定,否则会提示转为数值型
+	// if (textValue instanceof NumberTextValue) {
+	// setNumberTextValue(textStr);
+	// }
+	// } else {
+	// super.createTextCell(textElement, gridCell, colIndex, rowIndex,
+	// styledText, baseStyle, forecolor);
+	// }
+	// }
+
+	/**
+	 * 判断字符串是否为数值
+	 * 
+	 * @param textStr
+	 * @return
+	 */
+	private boolean isNumber(String textStr) {
+		if (StringUtils.isEmpty(textStr)) {
+			return false;
+		}
+		try {
+			// 数值可能为1,320.6的形式
+			Double.parseDouble(textStr.replaceAll(",", ""));
+			return true;
+		} catch (NumberFormatException e) {
+			return false;
+		}
+	}
+
+	/**
+	 * 设置单元格格式为数值类型
+	 * 
+	 * @param textStr
+	 */
+	// private void setNumberTextValue(String textStr) {
+	// if (isNumber(textStr)) {
+	// cell.setCellValue(Double.parseDouble(textStr.replaceAll(",", "")));
+	// cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);
+	// }
+	// }
+
+	@Override
+	protected void openWorkbook(OutputStream os) throws JRException {
+		// TODO Auto-generated method stub
+		super.openWorkbook(os);
+		// styleHelper=new CustomXlsxStyleHelper(jasperReportsContext,
+		// xlsxZip.getStylesEntry().getWriter(),
+		// getExporterKey());
+		FileBufferedWriter bordersWriter = (FileBufferedWriter) ObjectUtils.recursivelyGetValue("bordersWriter",
+				styleHelper);
+		XlsxBorderHelper borderHelper = new CustomXlsxBorderHelper(jasperReportsContext, bordersWriter);
+		Field borderHelperField = ObjectUtils.recursivelyGetField("borderHelper", XlsxStyleHelper.class);
+		borderHelperField.setAccessible(true);
+		try {
+			borderHelperField.set(styleHelper, borderHelper);
+		} catch (Throwable e) {
+			throw new IllegalArgumentException("修改 XlsxStyleHelper 失败", e);
+		}
+		borderHelperField.setAccessible(false);
+	}
+}

+ 71 - 0
src/main/java/com/uas/report/jasperreports/engine/export/CustomXlsxBorderHelper.java

@@ -0,0 +1,71 @@
+package com.uas.report.jasperreports.engine.export;
+
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.jasperreports.engine.JRLineBox;
+import net.sf.jasperreports.engine.JRPen;
+import net.sf.jasperreports.engine.JasperReportsContext;
+import net.sf.jasperreports.engine.export.JRExporterGridCell;
+import net.sf.jasperreports.engine.export.JRXlsAbstractExporter;
+import net.sf.jasperreports.engine.export.ooxml.XlsxBorderHelper;
+import net.sf.jasperreports.engine.export.ooxml.XlsxBorderInfo;
+
+public class CustomXlsxBorderHelper extends XlsxBorderHelper {
+
+	private Map<String, Integer> borderCache = new HashMap<String, Integer>();
+
+	public CustomXlsxBorderHelper(JasperReportsContext jasperReportsContext, Writer writer) {
+		super(jasperReportsContext, writer);
+	}
+
+	@Override
+	public int getBorder(JRExporterGridCell gridCell, JRXlsAbstractExporter.SheetInfo sheetInfo) {
+		if (Boolean.TRUE.equals(sheetInfo.ignoreCellBackground) || gridCell.getBox() == null) {
+			return -1;
+		}
+
+		XlsxBorderInfo borderInfo = new XlsxBorderInfo(gridCell.getBox());
+		Integer borderIndex = borderCache.get(borderInfo.getId());
+		if (borderIndex == null) {
+			borderIndex = Integer.valueOf(borderCache.size());
+			export(borderInfo);
+			borderCache.put(borderInfo.getId(), borderIndex);
+		}
+		return borderIndex.intValue();
+	}
+
+	@Override
+	public void export(JRLineBox box) {
+		if (box != null) {
+			export(new XlsxBorderInfo(box));
+		}
+	}
+
+	@Override
+	public void export(JRPen pen) {
+		if (pen != null) {
+			export(new XlsxBorderInfo(pen));
+		}
+	}
+
+	private void export(XlsxBorderInfo info) {
+		{
+			write("<border>");
+			exportBorder(info, "left");
+			exportBorder(info, "right");
+			exportBorder(info, "top");
+			exportBorder(info, "bottom");
+			write("<diagonal/></border>\n");
+		}
+	}
+
+	private void exportBorder(XlsxBorderInfo info, String side) {
+		write("<" + side);
+		write(" style=\"thin\">");
+		write(">");
+		write("<color rgb=\"AFABAB\"/>");
+		write("</" + side + ">");
+	}
+}

+ 28 - 1
src/main/java/com/uas/report/service/impl/PrintServiceImpl.java

@@ -42,6 +42,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.uas.report.SpecialProperties;
 import com.uas.report.SystemProperties;
 import com.uas.report.jasperreports.engine.export.CustomJRXlsExporter;
+import com.uas.report.jasperreports.engine.export.CustomJRXlsxExporter;
 import com.uas.report.model.ExportType;
 import com.uas.report.model.Master;
 import com.uas.report.service.FileService;
@@ -56,6 +57,7 @@ import com.uas.report.util.ReportUtils;
 import com.uas.report.util.StringUtils;
 
 import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRParameter;
 import net.sf.jasperreports.engine.JasperCompileManager;
 import net.sf.jasperreports.engine.JasperFillManager;
 import net.sf.jasperreports.engine.JasperPrint;
@@ -65,6 +67,8 @@ import net.sf.jasperreports.engine.export.JRPdfExporter;
 import net.sf.jasperreports.engine.export.JRRtfExporter;
 import net.sf.jasperreports.engine.export.JRTextExporter;
 import net.sf.jasperreports.engine.export.JRXlsExporter;
+import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
+import net.sf.jasperreports.engine.fill.JRFileVirtualizer;
 import net.sf.jasperreports.engine.xml.JRXmlLoader;
 import net.sf.jasperreports.export.ExporterInput;
 import net.sf.jasperreports.export.OutputStreamExporterOutput;
@@ -152,6 +156,11 @@ public class PrintServiceImpl implements PrintService {
 
 		// 向报表模板传递参数:报表路径、where条件、其他参数
 		Map<String, Object> parameters = new HashMap<>();
+		File virtualizerDir = new File(fileService.getMasterPath("tmp") + "/virtualizer");
+		if (!virtualizerDir.exists()) {
+			virtualizerDir.mkdirs();
+		}
+		parameters.put(JRParameter.REPORT_VIRTUALIZER, new JRFileVirtualizer(2, virtualizerDir.getAbsolutePath()));
 		parameters.put(ReportConstants.PARAMETER_REPORT_DIR, fileService.getMasterPath(masterOfJrxml));
 		if (!StringUtils.isEmpty(whereCondition)) {
 			parameters.put(ReportConstants.PARAMETER_WHERE_CONDITION, whereCondition);
@@ -201,7 +210,8 @@ public class PrintServiceImpl implements PrintService {
 				}
 
 				if (exportType == ExportType.XLS || exportType == ExportType.XLS_DATA) {
-					exportReportToXls(jasperPrint, outputStream, customCellStyle);
+//					exportReportToXls(jasperPrint, outputStream, customCellStyle);
+					exportReportToXlsx(jasperPrint, outputStream, customCellStyle);
 				} else if (exportType == ExportType.DOC) {
 					exportReportToDoc(jasperPrint, outputStream);
 				} else if (exportType == ExportType.TXT) {
@@ -520,6 +530,23 @@ public class PrintServiceImpl implements PrintService {
 		exporter.exportReport();
 	}
 
+	/**
+	 * 以xlsx的格式导出报表
+	 * 
+	 * @param jasperPrint
+	 * @param outputStream
+	 * @throws JRException
+	 */
+	private void exportReportToXlsx(JasperPrint jasperPrint, OutputStream outputStream, boolean customCellStyle)
+			throws JRException {
+		JRXlsxExporter exporter = new CustomJRXlsxExporter(customCellStyle);
+		ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
+		exporter.setExporterInput(exporterInput);
+		OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);
+		exporter.setExporterOutput(exporterOutput);
+		exporter.exportReport();
+	}
+
 	/**
 	 * 以doc的格式导出报表
 	 * 

+ 302 - 0
src/main/java/com/uas/report/util/ObjectUtils.java

@@ -0,0 +1,302 @@
+package com.uas.report.util;
+
+import com.alibaba.fastjson.JSONArray;
+import java.io.*;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * 对象工具类
+ *
+ * @author sunyj
+ * @since 2017年9月1日 下午3:54:26
+ */
+public class ObjectUtils {
+
+	/**
+	 * 判断是否为 null、空数组、空串或者空集合
+	 *
+	 * @param obj
+	 *            对象
+	 * @return 是否为 null、空数组、空串或者空集合
+	 */
+	public static boolean isEmpty(Object obj) {
+		if (obj == null) {
+			return true;
+		}
+		if (obj.getClass().isArray()) {
+			if (obj instanceof long[]) {
+				return ArrayUtils.isEmpty((long[]) obj);
+			} else if (obj instanceof int[]) {
+				return ArrayUtils.isEmpty((int[]) obj);
+			} else if (obj instanceof short[]) {
+				return ArrayUtils.isEmpty((short[]) obj);
+			} else if (obj instanceof byte[]) {
+				return ArrayUtils.isEmpty((byte[]) obj);
+			} else if (obj instanceof char[]) {
+				return ArrayUtils.isEmpty((char[]) obj);
+			} else if (obj instanceof boolean[]) {
+				return ArrayUtils.isEmpty((boolean[]) obj);
+			} else if (obj instanceof float[]) {
+				return ArrayUtils.isEmpty((float[]) obj);
+			} else if (obj instanceof double[]) {
+				return ArrayUtils.isEmpty((double[]) obj);
+			}
+			return ArrayUtils.isEmpty((Object[]) obj);
+		}
+		return (obj instanceof String && StringUtils.isEmpty(obj))
+				|| (obj instanceof Collection && CollectionUtils.isEmpty((Collection<?>) obj))
+				|| (obj instanceof Map && CollectionUtils.isEmpty((Map<?, ?>) obj));
+	}
+
+	/**
+	 * 将对象转为 String
+	 *
+	 * @param obj
+	 *            对象
+	 * @return 转换的 String
+	 */
+	public static String toString(Object obj) {
+		if (obj == null) {
+			return "";
+		}
+		if (obj instanceof String) {
+			return (String) obj;
+		}
+		if (obj.getClass().isArray()) {
+			if (obj instanceof long[]) {
+				return Arrays.toString((long[]) obj);
+			} else if (obj instanceof int[]) {
+				return Arrays.toString((int[]) obj);
+			} else if (obj instanceof short[]) {
+				return Arrays.toString((short[]) obj);
+			} else if (obj instanceof byte[]) {
+				return Arrays.toString((byte[]) obj);
+			} else if (obj instanceof char[]) {
+				return Arrays.toString((char[]) obj);
+			} else if (obj instanceof boolean[]) {
+				return Arrays.toString((boolean[]) obj);
+			} else if (obj instanceof float[]) {
+				return Arrays.toString((float[]) obj);
+			} else if (obj instanceof double[]) {
+				return Arrays.toString((double[]) obj);
+			}
+			return Arrays.toString((Object[]) obj);
+		}
+		return obj.toString();
+	}
+
+	/**
+	 * 深克隆对象
+	 *
+	 * @param t
+	 *            要克隆的对象
+	 * @return 克隆得到的对象
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T extends Serializable> T clone(T t)
+			throws IOException, ClassNotFoundException, NotSerializableException {
+		if (t == null) {
+			return null;
+		}
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		new ObjectOutputStream(out).writeObject(t);
+		ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
+		return (T) in.readObject();
+	}
+
+	/**
+	 * 深克隆集合对象
+	 *
+	 * @param collection
+	 *            要克隆的对象
+	 * @return 克隆得到的对象
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> Collection<T> clone(Collection<T> collection) throws InstantiationException,
+			IllegalAccessException, NotSerializableException, ClassNotFoundException, IOException {
+		if (collection == null) {
+			return null;
+		}
+		Collection<T> result = collection.getClass().newInstance();
+		for (T t : collection) {
+			if (t instanceof Serializable) {
+				result.add((T) clone((Serializable) t));
+			} else if (t instanceof Collection) {
+				result.add((T) clone((Collection<?>) t));
+			} else if (t instanceof Map) {
+				result.add((T) clone((Map<String, ?>) t));
+			} else {
+				throw new IllegalArgumentException("未实现 Serializable 接口");
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * 深克隆 Map 对象
+	 *
+	 * @param map
+	 *            要克隆的对象
+	 * @return 克隆得到的对象
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> Map<String, T> clone(Map<String, T> map) throws InstantiationException, IllegalAccessException,
+			NotSerializableException, ClassNotFoundException, IOException {
+		if (map == null) {
+			return null;
+		}
+		Map<String, T> result = map.getClass().newInstance();
+		Set<Entry<String, T>> entrySet = map.entrySet();
+		for (Entry<String, T> entry : entrySet) {
+			T value = entry.getValue();
+			if (value instanceof Serializable) {
+				result.put(entry.getKey(), (T) clone((Serializable) value));
+			} else if (value instanceof Collection) {
+				result.put(entry.getKey(), (T) clone((Collection<?>) value));
+			} else if (value instanceof Map) {
+				result.put(entry.getKey(), (T) clone((Map<String, ?>) value));
+			} else {
+				throw new IllegalArgumentException("未实现 Serializable 接口");
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * JSONArray 转为指定类型的 List
+	 *
+	 * @param array
+	 *            JSONArray
+	 * @param clazz
+	 *            指定的类型
+	 * @param <T>
+	 *            指定的类型
+	 * @return 指定类型的 List
+	 */
+	public static <T> List<T> toList(JSONArray array, Class<T> clazz) {
+		if (array == null) {
+			return null;
+		}
+		List<T> list = new ArrayList<>();
+		for (int i = 0; i < array.size(); i++) {
+			list.add(array.getObject(i, clazz));
+		}
+		return list;
+	}
+
+	/**
+	 * 利用反射获取指定对象的指定字段的值
+	 *
+	 * @param field
+	 *            指定字段
+	 * @param k
+	 *            指定对象
+	 * @return 指定字段的值
+	 */
+	public static <K> Object getValue(Field field, K k) throws IllegalStateException {
+		Object value;
+		try {
+			if (!field.isAccessible()) {
+				field.setAccessible(true);
+				value = field.get(k);
+				field.setAccessible(false);
+			} else {
+				value = field.get(k);
+			}
+		} catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
+			throw new IllegalStateException("通过反射取值失败", e);
+		}
+		return value;
+	}
+
+	/**
+	 * 利用反射递归获取指定对象的指定字段的值
+	 *
+	 * @param field
+	 *            指定字段
+	 * @param k
+	 *            指定对象
+	 * @return 指定字段的值
+	 */
+	public static <K> Object recursivelyGetValue(String field, K k) {
+		return getValue(recursivelyGetField(field, k.getClass()), k);
+	}
+
+	/**
+	 * 递归获取指定类的指定字段(包括父类的私有字段)
+	 *
+	 * @param field
+	 *            指定字段
+	 * @param clazz
+	 *            指定类
+	 * @return 指定字段
+	 * @throws IllegalArgumentException
+	 */
+	public static Field recursivelyGetField(String field, Class<?> clazz) throws IllegalArgumentException {
+		try {
+			return clazz.getDeclaredField(field);
+		} catch (NoSuchFieldException e) {
+			Class<?> superclass = clazz.getSuperclass();
+			if (superclass != null) {
+				return recursivelyGetField(field, superclass);
+			}
+			throw new IllegalArgumentException(clazz + "中不存在字段:" + field);
+		}
+	}
+
+	/**
+	 * 获取指定类的指定字段
+	 *
+	 * @param field
+	 *            指定字段
+	 * @param clazz
+	 *            指定类
+	 * @return 指定字段
+	 * @throws IllegalArgumentException
+	 */
+	public static Field getField(String field, Class<?> clazz) throws IllegalArgumentException {
+		try {
+			return clazz.getDeclaredField(field);
+		} catch (NoSuchFieldException e) {
+			throw new IllegalArgumentException(clazz + "中不存在字段:" + field);
+		}
+	}
+
+	/**
+	 * 递归获取父类(包括私有字段)的所有字段
+	 *
+	 * @param clazz
+	 *            指定类
+	 * @return 所有字段
+	 */
+	public static List<Field> recursivelyGetParentField(Class<?> clazz) {
+		List<Field> fields = new ArrayList<>();
+		Class<?> superclass = clazz.getSuperclass();
+		if (superclass != null) {
+			fields.addAll(recursivelyGetField(superclass));
+		}
+		return fields;
+	}
+
+	/**
+	 * 递归获取所有字段(包括父类的私有字段)
+	 *
+	 * @param clazz
+	 *            指定类
+	 * @return 所有字段
+	 */
+	private static List<Field> recursivelyGetField(Class<?> clazz) {
+		List<Field> fields = new ArrayList<>();
+		Field[] declaredFields = clazz.getDeclaredFields();
+		if (!ArrayUtils.isEmpty(declaredFields)) {
+			fields.addAll(Arrays.asList(declaredFields));
+		}
+		Class<?> superclass = clazz.getSuperclass();
+		if (superclass != null) {
+			fields.addAll(recursivelyGetField(superclass));
+		}
+		return fields;
+	}
+}