相关文章推荐
直爽的围巾  ·  JSON_VALUE ...·  2 月前    · 
非常酷的柳树  ·  Go database/sql ...·  1 年前    · 
豪爽的热水瓶  ·  BeautifulSoup 中的 ...·  1 年前    · 
最近要生成打印版的保单信息,内容比较多,也比较复杂,iText直接生成的话,想必花很多时间,而且可能也很难维护,偶然看到了HTML 在 Fly Saucer的帮助下能转换成PDF,解析CSS还不错,顿时随便拿个网页转了一下,比想象中好,于是决定用在项目中了:         然而真正用起来的话,会遇到很多问题,在此我一一总觉出来,然后给予解我的决办法,也希望大家有什么更好的办法的话,互相分享;         我的想法是,截取请求,当客户发送一次请求后,我们后台务必会解析JSP,然后生成HTML返回给浏览器,这时我们就可以获取response所携带的字节流。但是,由于我们写到response中的流是无法再次获取的(在服务端);就像我们用OutputStream 把内容写入文件一样,我们只持有当前OutputStream对象的话,是无法再次获取已经写入的内容一样,这就是输出流的不可逆性;所以,我们得借助 HttpServletResponseWrapper 接口,我们编写一个自己的类实现这个接口,然后我们的类就可以充当 HttpServletResponse 来使用(相当于我们的类冒充 HttpServletResponse一样 ),然后我们在Servlet中截取请求,再把请求跳转到要打印成PDF的jsp页面,当请求回来时,我们就可以获取请求带回来的数据,然后转换成String,生成PDF,同时写入真正的 HttpServletResponse 对象中返回给客户端
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class PDFResponseWrapper extends HttpServletResponseWrapper {
    private ByteArrayOutputStream buffer = null; 
     private ServletOutputStream out = null; 
     private PrintWriter writer = null; 
     public PDFResponseWrapper(HttpServletResponse resp) throws IOException { 
         super(resp); 
         buffer = new ByteArrayOutputStream();// 真正存储数据的流 
         out = new WapperedOutputStream(buffer); 
         String encoding = resp.getCharacterEncoding();
         writer = new PrintWriter(new OutputStreamWriter(buffer, encoding)); 
     /**重载父类获取outputstream的方法*/ 
     @Override 
     public ServletOutputStream getOutputStream() throws IOException { 
         return out; 
     /**重载父类获取writer的方法*/ 
     @Override 
     public PrintWriter getWriter() throws UnsupportedEncodingException { 
         return writer; 
     /**重载父类获取flushBuffer的方法*/ 
     @Override 
     public void flushBuffer() throws IOException { 
         if (out != null) { 
             out.flush(); 
         if (writer != null) { 
             writer.flush(); 
     @Override 
     public void reset() { 
         buffer.reset(); 
     /**将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据*/ 
    public byte[] getResponseData() throws IOException { 
         flushBuffer(); 
         return buffer.toByteArray(); 
     /**内部类,对ServletOutputStream进行包装*/ 
    private class WapperedOutputStream extends ServletOutputStream { 
         private ByteArrayOutputStream bos = null; 
         public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException { 
             bos = stream; 
         @Override 
         public void write(int b) throws IOException { 
             bos.write(b); 
         @Override 
         public void write(byte[] b) throws IOException { 
             bos.write(b, 0, b.length); 
  
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import com.itextpdf.text.DocumentException;
import com.sinosoft.flex.service.insure.InsuredMaterialDownload;
import com.sinosoft.flex.service.insure.PDFResponseWrapper;
import com.sinosoft.flex.service.insure.PlanApproveBL;
import com.sinosoft.flex.service.insure.PolicyPDFPrintGenerationBL;
public class SubServletForPDF extends SuperServlet{
    private static final long serialVersionUID = 1L;
    private static Logger log = Logger.getLogger(PlanApproveBL.class);
    @Override
    public void service(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        String operator1 = "operator1";
        String policyPDF = "policyPDF";
        String operator = request.getParameter("operator");
        ///    投保单资料下载1  分红,万能险种资料下载
        if(operator1.equals(operator)){
            /// Other Logic
        }else if(policyPDF.equals(operator)){
            PolicyPDFPrintGenerationBL pdfBL = new PolicyPDFPrintGenerationBL();
            String printPDF = request.getParameter("print");
            if(printPDF != null && printPDF.equals("Y")){
               // Other Logic
            }else{
                String poNo = request.getParameter("poNo");
                if(poNo == null || poNo.length() <1){
                    log.info("获取保单信息失败,请传入保单号");
                    Error err = new Error("查询数据失败");
                     throw new RuntimeErrorException(err);
                request.setAttribute("poNo", poNo);
                String servletPath = pdfBL.getServletPath(poNo);  // 获取转发的请求路径,然后把请求转向生成PDF的JSP页面
                response.setCharacterEncoding("UTF-8");
                PDFResponseWrapper responWrapper = new PDFResponseWrapper(response);
                request.getRequestDispatcher(servletPath).forward(request, responWrapper);
                byte[] data = responWrapper.getResponseData();   // 获取out.write()进来的 html 字节流
                String str = new String(data,"UTF-8");
                pdfBL.convertHtmlToPdf(str);                    // html格式的 字符串转换成PDF,代码在下面 
                OutputStream out = response.getOutputStream();
                out.write(data);
                out.close();
import org.apache.log4j.Logger;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import com.sinosoft.flex.pubfun.PubFun;
import com.sinosoft.utility.SSRS;
public class PolicyPDFPrintGenerationBL {
    private static Logger log = Logger.getLogger(PlanApproveBL.class);
    public boolean convertHtmlToPdf(String html){  
        try {
            OutputStream os = new FileOutputStream("D:\\letter\\iText_22.pdf");       
            ITextRenderer renderer = new ITextRenderer();       
//        String url = new File(inputFile).toURI().toURL().toString();   
            System.out.println(html);
            renderer.setDocumentFromString(html);     
            // 解决中文支持问题       
            ITextFontResolver fontResolver = renderer.getFontResolver();      
            fontResolver.addFont("C:/Windows/Fonts/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);  /// 宋体
                 下面为黑体
            fontResolver.addFont("C:/Windows/Fonts/simhei.ttf",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); 
            //解决图片的相对路径问题  
            renderer.getSharedContext().setBaseURL("file:G:\\tmp\\practice/");  
            renderer.layout();      
            renderer.createPDF(os);    
            os.flush();  
            os.close();  
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        return true;  
    public String getServletPath(String policyNo){
        String policyInfoSql = "select a.insureordertype, 'BJ' from FCOrder a where a.insureorderid = ?";
        SSRS tSSRS = PubFun.queryData(policyInfoSql, policyNo);
        if(tSSRS.MaxRow != 1){
            log.error("获取保单信息失败,参数: "+policyNo+"SQL:"+policyInfoSql);
            return null;
        String policyType = tSSRS.GetText(1, 1);
        String subType = tSSRS.GetText(1, 2);
        String servletPath = "/insure/PolicyFPDPrint"+policyType+subType;
        return servletPath;
             我修改好了的jar包:http://download.csdn.net/detail/tingyingg/9706074 

    (2).表格中TD换行的话,我试了网上说的方法是可行的的,但达不到我想要的效果,因为设置了样式之后,你表格中的 td 大小就不能再次调节了,具体方法请参见下面这篇文章:

http://kaka2008.iteye.com/blog/1005894

    (3). 粗体:

            你发现,无论是 STSong, 还是 SimSun, 当你设置粗体之后,在页面显示是加粗的,但打印出的PDF,却怎么也无法加粗, 这是我阅读源码的原因之一,但可惜花了两天左右的时间,我还是找不出解决的方法;  最后,我忽然发现我可以用黑体代替粗体, 而且效果还不错, 如果客户没那么严格要求,或者说是又不想多花钱用商业软件的话,这个效果已经很不错了。                 ----------------------  如果有谁有其他更好的方法的话,一定记得分享出来...................

      (4)。 Checkbox,多选框无法显示。

               这也是一个致命的问题啊,我一开始想到的最坏的打算是图片代替,  这样的话会比较麻烦,因为有很多Checkbox的时候,加载,判断都是很麻烦的;                 最后我的思路是(稍微比上面这个好点),用一个特殊字符   √   , 还可以调节大小(font-size),哈哈,这个在中文下可以显示出来,不知道英文会不会显示正常,然后在外面套一个 div ,固定个大小, 不就成多选框了吗。当然,你得封装判断的方法,我的方法是,调用一个类,在类里面从数据库中查询各个选项的值,然后判断,是不是被选中,选中的话,返回一个 className (color:#000),把这个class赋值给div,就显示打钩,否则,返回另一个 className(color:#fff),这样打钩在框框里面就看不见了, 
 .chk{width:12px;height:12px;line-height:12px;font-size:12px;display:inline;border:1px solid #444444;margin:0px 4px 0px 4px;color:#ffffff;}
          .chked{width:12px;font-size:12px;display:inline;border:1px solid #444444; margin:0px 4px 0px 4px;font-weight:bold;}
public String getCheckData(String dataType,String codeKey){
        String clasName = null;
        String val = chkData.get(dataType);
        val = chkData.get(dataType);
        clasName = (codeKey.equals(val)) ? "chked" : "chk";
        if(dataType.equals("10100103")){
            System.out.println("codeKey :"+codeKey);
        return clasName;
                    最近要生成打印版的保单信息,内容比较多,也比较复杂,iText直接生成的话,想必花很多时间,而且可能也很难维护,偶然看到了HTML 在 Fly Saucer的帮助下能转换成PDF,解析CSS还不错,顿时随便拿个网页转了一下,比想象中好,于是决定用在项目中了:        然而真正用起来的话,会遇到很多问题,在此我一一总觉出来,然后给予解我的决办法,也希望大家有什么更好的办法的话,互相分享;
public static void htmlToPDF(String pdfPath, String htmlPath) throws Exception {
        try {
            ITextRenderer renderer = new ITextRenderer();
            ITextFontResolver fontResolver = renderer.getFontResolver();
            OutputStre
				
由于项目需求要把ckeditor的html可编辑报表到导出成为pdf, 择用了FlySaucer,结果遇到了中文问题,无法正常,导致一内容过长,超出了显示页面,以下为解决方案: 1. 对于让中文能正常的排版,需要在table中的style中加:table-layout:fixed; word-break:break-strict;  这会使内容居中。 2. 这个是重点,需要对
因为如果是通过设置宽度来进自动的话,则无法通过letter-spacing或者word-spacing设置字间距,实际上此时字间距的本质是间距,单只有一个汉字,所以只能通过设置line-height进设置