接到一个需求,要求动态生成一个excel,其中表头要是动态生成的(表头字段不确定)。
Talk is cheap,let me show the code.
@RequestMapping(value={"/exportPdfDynamic"})
public String exportPdfDynamic(HttpServletResponse response) throws UnsupportedEncodingException{
OutputStream os = null;
PdfStamper ps = null;
PdfReader reader = null;
try {
List<User> users = new ArrayList<>();
User user1 = new User();
user1.setId("111");
user1.setUsername("小花");
user1.setSex("女");
user1.setPassword("secret");
users.add(user1);
User user2 = new User();
user2.setId("222");
user2.setUsername("小明");
user2.setSex("");
user2.setPassword("secret");
users.add(user2);
String filename="user_info.pdf";
//数据填充到PDF
String filePath = generatePDFs(users,filename);
//将生成的PDF展示到浏览器下载
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
"com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
String path = this.getClass().getClassLoader().getResource("PDF/"+filename).getPath();
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(filename, "UTF-8"));
os = response.getOutputStream();
reader = new PdfReader(path);
ps = new PdfStamper(reader, os);
ps.setFormFlattening(true);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ps.close();
reader.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
com.lowagie.text.Document document = new com.lowagie.text.Document();// 建立一个Document对象
private static com.lowagie.text.Font headfont;// 设置字体大小
private static com.lowagie.text.Font keyfont;// 设置字体大小
private static com.lowagie.text.Font textfont;// 设置字体大小
static {
//中文格式
com.lowagie.text.pdf.BaseFont bfChinese;
try {
// 设置中文显示
bfChinese = com.lowagie.text.pdf.BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1", com.itextpdf.text.pdf.BaseFont.IDENTITY_H, com.itextpdf.text.pdf.BaseFont.EMBEDDED);
headfont = new com.lowagie.text.Font(bfChinese, 14, com.lowagie.text.Font.BOLD);// 设置字体大小
keyfont = new com.lowagie.text.Font(bfChinese, 6, com.lowagie.text.Font.BOLD);// 设置字体大小
textfont = new com.lowagie.text.Font(bfChinese, 6, com.lowagie.text.Font.NORMAL);// 设置字体大小
} catch (Exception e) {
e.printStackTrace();
}
}
private String generatePDFs(List<User> list,String filename){
String saveFilePathAndName = "";
try{
String root = this.getClass().getClassLoader().getResource("/").getPath();
File file = new File(root+"PDF/"+filename);
if (!new File(root+"PDF").exists()){
new File(root+"PDF").mkdir();
}
file.createNewFile();
document.setPageSize(com.lowagie.text.PageSize.A4);// 设置页面大小
com.lowagie.text.pdf.PdfWriter.getInstance(document, new FileOutputStream(file));
document.open();
file.createNewFile(); //生成一个pdf文件
//确定表头字段
String[] head = {};
String[] headForBody = {};
if (null != list && list.size() > 0) {
//确定表头字段
Field[] field = User.class.getDeclaredFields();
try {
Set<String> hashSet = new HashSet<String>();
SimpleDateFormat sdf = null;
sdf= new SimpleDateFormat("MM/dd/yyyy");
for (int i = 0; i < list.size(); i++) {
User user = list.get(i);
//取表头
dealVoForHead(user);
//设置日期格式
if(user.getPassportIssueDate() != null){
user.setPassportIssueDate(sdf.format(new Date(Long.valueOf(user.getPassportIssueDate()))));
}
for(int j=0 ; j<field.length ; j++){//遍历所有属性
PropertyDescriptor pd = new PropertyDescriptor(field[j].getName(), User.class);
Method getMethod = pd.getReadMethod();//获得该属性的get方法
if(getMethod.invoke(user) != null){//执行get方法,获取所有对象中不为空的字段
//去重
hashSet.add(getMethod.getName().substring(3));
}
}
}
//设置表头顺序
List<String> arrList = new ArrayList<>();
int hashSetSice = hashSet.size();
for(int i=0 ; i<hashSetSice ; i++){
if(hashSet.contains("Id")){
arrList.add("Id");
hashSet.remove("Id");
}else if(hashSet.contains("Username")){
arrList.add("Username");
hashSet.remove("Username");
}else if(hashSet.contains("Sex")){
arrList.add("Sex");
hashSet.remove("Sex");
}else if(hashSet.contains("PassportIssueDate")){
arrList.add("PassportIssueDate");
hashSet.remove("PassportIssueDate");
}
}
head = arrList.toArray(new String[arrList.size()]);
headForBody = arrList.toArray(new String[arrList.size()]);
//表头多语言化
// transHeadInternational(head,lang);
} catch (Exception e){
e.printStackTrace();
}
}
//根据表头和list生成PDF
generatePDF(head, headForBody, list, head.length);
} catch (Exception e){
e.printStackTrace();
}
return saveFilePathAndName;
}
/**
* 为获取表头处理数据
* @return
*/
private User dealVoForHead(User user){
//将不必要的字段置空,以免影响后面统计有值的字段数
user.setPassword(null);
//将为""的字段置空,当所有对象的某字段都为""或null时,该字段就不作为表头
if(user.getId()==null || user.getId().equals("")){
user.setId(null);
}
if(user.getSex()==null || user.getSex().equals("")){
user.setSex(null);
}
if(user.getUsername()==null || user.getUsername().equals("")){
user.setUsername(null);
}
if(user.getPassportIssueDate()==null || user.getPassportIssueDate().equals("")){
user.setPassportIssueDate(null);
}
return user;
}
/**
* 创建一个表格对象
*
* @param colNumber 表格的列数
* @return 生成的表格对象
*/
public com.lowagie.text.pdf.PdfPTable createTable(int colNumber) {
com.lowagie.text.pdf.PdfPTable table = new com.lowagie.text.pdf.PdfPTable(colNumber);
try {
table.setTotalWidth(520);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setBorder(1);
} catch (Exception e) {
e.printStackTrace();
}
return table;
}
/**
* 为表格添加一个内容
*
* @param value 值
* @param font 字体
* @param align 对齐方式
* @param colspan 占多少列
* @param boderFlag 是否有有边框
* @return 添加的文本框
*/
public com.lowagie.text.pdf.PdfPCell createCell(String value, com.lowagie.text.Font font, int align, int colspan, boolean boderFlag) {
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(align);
cell.setColspan(colspan);
cell.setPhrase(new com.lowagie.text.Phrase(value, font));
cell.setPadding(3.0f);
if (!boderFlag) {
cell.setBorder(0);
cell.setPaddingTop(15.0f);
cell.setPaddingBottom(8.0f);
}
return cell;
}
/**
* 为表格添加一个内容
*
* @param value 值
* @param font 字体
* @param align 对齐方式
* @return 添加的文本框
*/
public com.lowagie.text.pdf.PdfPCell createCell(String value, com.lowagie.text.Font font, int align) {
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(align);
cell.setPhrase(new com.lowagie.text.Phrase(value, font));
return cell;
}
/**
* 为表格添加一个内容
*
* @param value 值
* @param font 字体
* @return 添加的文本框
*/
public com.lowagie.text.pdf.PdfPCell createCell(String value, com.lowagie.text.Font font) {
com.lowagie.text.pdf.PdfPCell cell = new com.lowagie.text.pdf.PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setPhrase(new com.lowagie.text.Phrase(value, font));
return cell;
}
public <T> void generatePDF(String[] head, String[] headForBody, List<User> list, int colNum) {
if(colNum == 0){
colNum = 1;
}
// 创建一个表格
com.lowagie.text.pdf.PdfPTable table = createTable(colNum);
// 添加备注,靠左,不显示边框
String addTitle=addTitle = "User Info:";
table.addCell(createCell(addTitle, headfont, Element.ALIGN_LEFT, colNum, false));
if (null != list && list.size() > 0) {
Class classType = list.get(0).getClass();
//设置表头
for (int i = 0; i < colNum; i++) {
table.addCell(createCell(head[i], keyfont, Element.ALIGN_CENTER));
}
//填充表格内容
int size = list.size();
for (int i = 0; i < size; i++) {
User t = list.get(i);
for (int j = 0; j < colNum; j++) {
//获得首字母
String firstLetter = headForBody[j].substring(0, 1).toUpperCase();
//获得get方法,getName,getAge等
String getMethodName = "get" + firstLetter + headForBody[j].substring(1);
Method method;
try {
//通过反射获得相应的get方法,用于获得相应的属性值
method = classType.getMethod(getMethodName, new Class[]{});
System.out.print(getMethodName + ":" + method.invoke(t, new Class[]{}) + ",");
//添加数据
table.addCell(createCell((method.invoke(t, new Class[]{})==null?"":method.invoke(t, new Class[]{})).toString(), textfont));
} catch (Exception e){
e.printStackTrace();
}
}
System.out.println("");
}
}
try {
//将表格添加到文档中
document.add(table);
} catch (DocumentException e) {
e.printStackTrace();
}
//关闭流
document.close();
}
效果如下: