原创不易 转载请说明出处
之前使用itext做报表本以为一切都大功告成,结果下载下来预览的时候有些中文不显示,
各种百度各种尝试,从代码到模板始终得不到解决,原本以为这是一个很小的问题结果反而成为一个解决时间最长的问题。
最后经过各种尝试最终才解决了问题。
下面从头到尾详细说说如何用itext做报表以及各种问题的解决方案
由于报表是基于springMVC的所以第一步先说说如何在这种模式下使用itext导出已经存在的excel或者word转换成的模板。 至于直接用代码创建PDF,或者用html模板生成PDF暂且不做讨论。
一:新建一个AbstractIText5PdfView类继承AbstractView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
protected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { //接收从控制层传过来的数据(具体根据自己的情况而定) Integer _Id = AbstractIText5PdfView.makeId(iid); SubPavRecordEntity sub = AbstractIText5PdfView.makeSubPavR(SubPavR); List<SubPavRecordEntity>subList=AbstractIText5PdfView.makeSubPavRList(SubPavRList1); List<SubPavRecordEntity>numList=AbstractIText5PdfView.makeRecordnumList(SubPavRList2); String fileName = "E:/ass/tpms/ert.pdf"; //模板路径 String newfileName="E:/ass/tpms/q.pdf";//生成模板的路径 PdfReader reader; FileOutputStream out; ByteArrayOutputStream bos = null; PdfStamper stamper; try { out = new FileOutputStream(newfileName);//输出流 reader = new PdfReader(fileName);//读取pdf模板 bos = new ByteArrayOutputStream(); stamper = new PdfStamper(reader, bos); AcroFields form = stamper.getAcroFields(); //在模板设置字体的话就不需要在代码设置 如果非要设置的话请参考方法一:字体大小在模板设置即可。这种方法没有亲自试验 注意:要导入字体包 方法二:直接用setFieldProperty把字体属性设置进去 BaseFont bf = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED); AcroFields form= ps.getAcroFields(); //设置文本域表单的字体 // 对于模板要显中文的,在此处设置字体比在pdf模板中设置表单字体的好处: //1.模板文件的大小不变;2.字体格式满足中文要求 s.setFieldProperty("fill_3","textfont",bf,null); s.setFieldProperty("fill_5","textfont",bf,null); s.setFieldProperty("fill_2","textfont",bf,null); s.setFieldProperty("fill_4","textfont",bf,null); s.setFieldProperty("fill_6","textfont",bf,null); 可以使用循环的方式添加字体属性: BaseFont bf = BaseFont.createFont("STSong-Light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED); Font FontChinese = new Font(bf, 12, Font.NORMAL); AcroFields s = ps.getAcroFields(); System.out.println("s: " + s); System.out.println("AcroFields: " + s.getFields()); System.out.println("AcroFields.class: " + s.getFields().getClass()); System.out.println("getSignatureNames: " + s.getSignatureNames()); System.out.println("getSignatureNames: " + s.getTotalRevisions()); System.out.println("s: " + s.getBlankSignatureNames()); System.out.println("s: " + s.getFieldCache()); System.out.println("s: " + s.getSubstitutionFonts()); int i = 1; for (Iterator it = s.getFields().keySet().iterator(); it.hasNext(); i++) { String name = (String) it.next(); String value = s.getField(name); System.out.println("[" + i + "- name:" + name + ", value: "+value+"]"); s.setFieldProperty(""+name.trim(),"textfont",bf,null); } //减少代码冗余 //编辑文本域表单的内容 for (SubPavRecordEntity subPavR : subList) { form.setField("fill_140", subPavR.getSamplingparts()); form.setField("fill_141", subPavR.getHoledepth()); form.setField("fill_124", subPavR.getDish1()); form.setField("fill_125", subPavR.getDishweight1()); form.setField("fill_126", subPavR.getDishwetweight1()); form.setField("fill_127", subPavR.getDishdryweight1()); form.setField("fill_128", subPavR.getWaterweight1()); form.setField("fill_129", subPavR.getDryweight1()); form.setField("fill_130", subPavR.getContainwater1()); form.setField("fill_92", subPavR.getAvecontainwater()); form.setField("fill_93", subPavR.getWetmixweight()); form.setField("fill_94",subPavR.getFiveweight()); } 可能出现的问题:1.中文预览的时候不显示 2.部分中文显示不全,可能乱码 解决方案:我尝试了Adobe Acrobat DC带的各种字体,最终都不能解决问题,但是经过不断的测试发现无论在代码上修改, 还是模板上修改,最终的效果是一样的。 So 问题只能定位到字体的编码格式上 我抱着试试的心态在网上下载了 仿宋GB_2312格式的字体 结果所有问题都迎刃而解。 stamper.setFormFlattening(true);//如果为false那么生成的PDF文件还能编辑,一定要设为true stamper.close(); } catch (Exception e) { e.printStackTrace(); } writeToResponse(response, bos); } |
第二步新建一个BusinessPdfView类可以不用实现 如果需要用代码创建pdf则直接可以写在这各类里面在此不作表述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class BusinessPdfView extends AbstractIText5PdfView { @Override protected void buildPdfDocument(Map<String, Object> map, Document document, PdfWriter writer, HttpServletRequest request, HttpServletResponse response) throws Exception { } } } |
第三步:在控制层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
public ModelAndView ireport(Model model, HttpServletRequest request) throws Exception { Integer id =oConvertUtils.getInt( request.getParameter( "id" )); SubPavRecordEntity one = subPavRecordService.get(SubPavRecordEntity.class, id); List<SubPavRecordEntity> one1 = subPavRecordService.findByProperty(SubPavRecordEntity.class, "passid", one.getPassid()); List<SubPavRecordEntity> findRec = subPavRecordService.findByProperty(SubPavRecordEntity.class, "recordnum", one.getRecordnum()); PuddlabilityCheckPassList pud = systemService.get(PuddlabilityCheckPassList.class,Integer.valueOf(one.getPassid())); //传递参数 AbstractIText5PdfView.makeSubPavR(one); AbstractIText5PdfView.makeSubPavRList(one1); AbstractIText5PdfView.makeRecordnumList(findRec); AbstractIText5PdfView.makePud(pud); Map<String,Object> map = new HashMap<String,Object>(); // 参数 设置,这里略,根据自己的东西进行匹配吧。 BusinessPdfView view = new BusinessPdfView(); view.setAttributesMap(map); // 这里使用了spring mvc 的人,应该不陌生,其他配置就略了。 return new ModelAndView(view); } |
第四步 新建一个PDFUtil的类文件 工具包 根据自己的情况而定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
public class PDFUtil { // 对参数的封装形式比如{name} public static final String BEGIN = "{"; public static final String END = "}"; // 换行形式{#} public static final String NEW_LINE = "#"; // 默认的行间距、首行距离等,自己添加 public static final float DEFAULT_LEADING = 20; public static final float DEFAULT_LINE_INDENT = 30; // 基本字体和样式 public static BaseFont bfChinese; public static Font fontChinese; public static Font UNDER_LINE = null; static{ try { // SIMKAI.TTF 默认系统语言,这里没使用第三方语言包 //bfChinese = BaseFont.createFont(PDFTest.class.getResource("/content/")+"SIMKAI.TTF",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED); bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); fontChinese = new Font(bfChinese, 14, Font.NORMAL); UNDER_LINE = new Font(bfChinese, 14,Font.UNDERLINE); } catch (DocumentException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // 默认样式 public static Paragraph getParagraph(String context){ return getParagraph(context,fontChinese); } public static Paragraph getParagraph(Chunk chunk){ return new Paragraph(chunk); } // 指定字体样式 public static Paragraph getParagraph(String context,Font font){ return new Paragraph(context,font); } // 获得新行,首行缩进,和行间距 public static Paragraph getNewParagraph(String context,float fixedLeading,float firstLineIndent){ Paragraph p = getParagraph(context); p.setLeading(fixedLeading); p.setFirstLineIndent(firstLineIndent); return p; } public static Paragraph getParagraph(String content , Font font , float fixedLeading , int alignment){ Paragraph p = getParagraph(content); p.setFont(font); p.setLeading(fixedLeading); p.setAlignment(alignment); return p; } // 默认段落样式 public static Paragraph getDefaultParagraph(String context){ Paragraph p = getParagraph(context); // 默认行间距 p.setLeading(DEFAULT_LEADING); // 默认首行空隙 p.setFirstLineIndent(DEFAULT_LINE_INDENT); return p; } // 将参数和字符串内容组合成集合 public static List<Paragraph> createParagraphs(String context ,Map<String,Object> map){ int index = 0; List<Paragraph> list = new ArrayList<Paragraph>(); Paragraph p = getDefaultParagraph(null); while((index = context.indexOf(BEGIN)) > -1){ String text = context.substring(0,index); context = context.substring(index, context.length()); index = context.indexOf(END); String param = null; if(index > 0){ param = context.substring(BEGIN.length(),index); } p.add(text); if(!NEW_LINE.equals(param)){ Object value = map.get(param); if(value != null){ p.add(new Chunk(value.toString(),UNDER_LINE)); }else{ p.add(new Chunk("")); } }else{ list.add(p); p = getDefaultParagraph(null); p.setSpacingBefore(0); } context = context.substring(index+END.length(),context.length()); } list.add(p); list.add(getParagraph(context)); return list; } |
没有jar包的需要自行导入:iTextAsian.jar ,itext-2.1.7.jar;视自己情况而定
最后注意导入包的形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import com.cy.framework.core.util.DataUtils; import com.cy.framework.core.util.oConvertUtils; import com.cy.tpms.entity.sub.PuddlabilityCheckPassList; import com.cy.tpms.entity.sub.SubPavRecordEntity; import com.lowagie.text.Document; import com.lowagie.text.DocumentException; import com.lowagie.text.Element; import com.lowagie.text.Font; import com.lowagie.text.FontFactory; import com.lowagie.text.PageSize; import com.lowagie.text.Paragraph; import com.lowagie.text.pdf.AcroFields; import com.lowagie.text.pdf.BaseFont; import com.lowagie.text.pdf.PdfCopy; import com.lowagie.text.pdf.PdfImportedPage; import com.lowagie.text.pdf.PdfReader; import com.lowagie.text.pdf.PdfStamper; import com.lowagie.text.pdf.PdfWriter; |
缺jar包的自行下载导入
最后我吧所有的主要问题做个简单总结:适用于直接使用模板填充
一:报表中文不显示:
模板添加仿宋_GB2312字体即可解决
代码设置相对不较麻烦 当还是可行 一般要先添加内容在设置字体属性 顺序不对也会没效果。
二:报表字体粗细不一
在excel或者word模板设置为文本格式,设置好字体以及格式 在转换为pdf 再次用PDF模板编辑的时候设置如上字体以及代码。即可解决。