`
greemranqq
  • 浏览: 967303 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论
阅读更多

        最近临时做个PDF 生成预览 下载的一些东西,了解了下,发现itext 这个插件包 和spring 是已经集成在一起的,其实itext 已经很强大了,普通的servlet 也够了,这里先大概介绍一下吧!
        spring mvc 里面的视图结构很多,这里我转载一下:

     

 

      可以看到其中有AbstractPdf 的类,这里简单介绍它,如果你要用其他的视图,可以参考该图,是否已经实现。

     

// 可以看出 是继承的抽象视图,可以参考上面图例,具体内容我们这里不探讨,直接看方法
public abstract class AbstractPdfView extends AbstractView {

 

 

    

// 这里是设置了我们返回类型
public AbstractPdfView() {
		setContentType("application/pdf");
	}

// 这里默认是下载
	@Override
	protected boolean generatesDownloadContent() {
		return true;
	}

 

 

     

@Override
        // 这个方法和名字描述一样,就是创建输出模型的,总的来说是创建Document
	protected final void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// IE workaround: write into byte array first.
		ByteArrayOutputStream baos = createTemporaryOutputStream();
                // 这里创建 itext 是识别的Document
		// Apply preferences and build metadata.
		Document document = newDocument();
		PdfWriter writer = newWriter(document, baos);
		prepareWriter(model, writer, request);
               
		buildPdfMetadata(model, document, request);

		// Build PDF document.
		document.open();
                 // 具体PDF内容让子类自己处理,后面我们会看到。
		buildPdfDocument(model, document, writer, request, response);
		document.close();

		// Flush to HTTP response.返回客户端
		writeToResponse(response, baos);
	}

  

// 默认A4 大小
protected Document newDocument() {
		return new Document(PageSize.A4);
	}


// 创建流对象
	protected PdfWriter newWriter(Document document, OutputStream os) throws DocumentException {
		return PdfWriter.getInstance(document, os);
	}

 

 

 

从上面看,整个过程很简单,抽象了一些行为,但是大部分都要子类进行实现,一些简单的功能 也是调用itext 里面的东西进行实现,大部分情况我们只需要itext 就行了,这里仅仅作为spring 视图特性的一种介绍。

因为spring 3.0 支持itext 2的版本,而 我是itest 5 版本,导入引入路径变了,这里我仿照上面的类,从新写一个。

 

/**
 * 这里就全部复制spring 的,然后引入的东西改成第5版的就行了
 *  代码 几乎不变,唯一变的是引用路径~。~ 没贴出来了,自己导入就能看见
 * @author Ran
 *
 */
public abstract class AbstractIText5PdfView extends AbstractView {
	 public AbstractIText5PdfView() {  
	        setContentType("application/pdf");  
	    }  
	  
	    @Override  
	    protected boolean generatesDownloadContent() {  
	        return true;  
	    }  
	  
	    @Override  
	    protected final void renderMergedOutputModel(Map<String, Object> model,  
	            HttpServletRequest request, HttpServletResponse response)  
	            throws Exception {  
	    	// 获得流
	        ByteArrayOutputStream baos = createTemporaryOutputStream();  
	        Document document = newDocument();  
	        PdfWriter writer = newWriter(document, baos);  
	        prepareWriter(model, writer, request);  
	        buildPdfMetadata(model, document, request);  
	        document.open();  
	        buildPdfDocument(model, document, writer, request, response);  
	        document.close();  
	        writeToResponse(response, baos);  
	    }  
	  
	    protected Document newDocument() {  
	        return new Document(PageSize.A4);  
	    }  
	  
	    protected PdfWriter newWriter(Document document, OutputStream os)  
	            throws DocumentException {  
	        return PdfWriter.getInstance(document, os);  
	    }  
	  
	    protected void prepareWriter(Map<String, Object> model, PdfWriter writer,  
	            HttpServletRequest request) throws DocumentException {  
	  
	        writer.setViewerPreferences(getViewerPreferences());  
	    }  
	  
	    protected int getViewerPreferences() {  
	        return PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage;  
	    }  
	  
	    protected void buildPdfMetadata(Map<String, Object> model,  
	            Document document, HttpServletRequest request) {  
	    }  
	  
	    protected abstract void buildPdfDocument(Map<String, Object> model,  
	            Document document, PdfWriter writer, HttpServletRequest request,  
	            HttpServletResponse response) throws Exception;  
}

 

 

下面看看我的子类,如何构建我们需要的对象

 

/**
 * 
 * @author 生成我需要的PDF
 *
 */
public class BusinessPdfView extends AbstractIText5PdfView{
     	// 标题
	public static final String title_content = "测试数据";
	// 敬语
	public static final String honorific_content ="亲爱的程序员:";
	
	// 这是主体内容
	public static  String context = "我的名字叫:{name} 编号:{no}{#}"
		+"这是另一行内容:{xxx}";
	
	// 表格标题
	public static String[] cellTitles = {"标题1","标题2","标题3"}; 
	
	// 银行信息
	public static String bank_content = "请贵司将货款汇入我公司如下银行帐户:{account}";

	public static void test(Map<String,Object> map){
		
	}
	
	// 从写方法
	// 这里我要实现一个 大概这样的PDF
	//   标题
	//抬头:
	//    正文(...)
	//    表格(...)
	
	@Override
	protected void buildPdfDocument(Map<String, Object> map,
			Document document, PdfWriter writer, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		try{
			document.open();
			// 标题居中
			Paragraph title = PDFUtil.getParagraph(
                       new Chunk(title_content,new Font(PDFUtil.bfChinese,16,Font.BOLD)));
			title.setAlignment(Paragraph.ALIGN_CENTER);
			// 中文  黑体
			document.add(title);
			
			Paragraph head = PDFUtil.getParagraph(honorific_content);
			head.setSpacingBefore(20);
			head.setSpacingAfter(10);
			document.add(head);
			
			// 正文
			List<Paragraph> paragraphs = PDFUtil.createParagraphs(context, map);
			for(Paragraph p : paragraphs){
				document.add(p);
			}
			// 表格标题
			PdfPTable table = new PdfPTable(cellTitles.length);
			table.setSpacingBefore(20);
			table.setSpacingAfter(30);
			for(String str : cellTitles){
				table.addCell(PDFUtil.getParagraph(str));
			}
			// 表格数据
			List<String> cells = (List<String>) map.get("poTableList");
			if(cells != null){
				for(String cell : cells){
					table.addCell(cell);
				}
			}
			document.add(table);
			// 关闭
			document.close();
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

 

 

      上面代码很简单,我仅仅是向Document 里面设置各种值,段落等信息就行,其他的spring 就帮我们搞定。其中我用到一个工具类,这里也贴出来。

       工具类仅仅是封装了itext 的API,然后对我需要的参数替换 规则,以及换行等内容进行了处理。

       还有关键的编码处理,一会介绍。

 

/**
 * 这仅仅作为itext5 提供一些方法,更多的需要自己去看相关API
 * @author Ran
 *
 */
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;
	}
}

 

 

   当子类完成了之后,回到我们的控制层,看看如何调用。

   

@RequestMapping("/business/applyFor.pdf")
	public ModelAndView text(HttpServletRequest req, HttpServletResponse res){
            Map<String,Object> map = new HashMap<String,Object>();
            // 参数 设置,这里略,根据自己的东西进行匹配吧。
            BusinessPdfView view = new BusinessPdfView();
	   view.setAttributesMap(map);
	   // 这里使用了spring mvc 的人,应该不陌生,其他配置就略了。			
	    return new ModelAndView(view);
}

 

 

上面就完成了,整个过程,重点还是itext API 那些调用,下面我们用itext 单独生成PDF,这里类可以导入的jar,可以直接使用:语言包请下载我从新打包的

 

public class PDFTest {
	// 基本字体和样式
	static BaseFont bfChinese = null;
	static Font fontChinese = null;
	static String CHANGE_LINE = "\n    ";
	static Font UNDER_LINE = null;
	
	/**
	 * 这里
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		Document document = new Document(PageSize.A4, 33, 33, 33, 33);
		PdfWriter writer = null;
		try {
// 语言 .tif 结尾的,都是Windows下的,我是拷贝进行项目了
//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);
			
			writer = PdfWriter.getInstance(document, new FileOutputStream("hellword.pdf"));
			// 打开
			document.open();
			Paragraph title = new Paragraph();
			// 设置页面格式
			title.setSpacingBefore(8);
			title.setSpacingAfter(2);
			title.setAlignment(1);
			// 设置PDF标题
			title.add(new Chunk("付款申请书",new Font(bfChinese, 16,Font.BOLD)));
			document.add(title);
			// 抬头
			Paragraph head = getParagraph("致:程序员们");
			head.setSpacingBefore(30);
			document.add(head);
			// 文字参数
			Map<String,String> map = new HashMap<String, String>();
			map.put("name", "ranqiqiang");
			map.put("sex", "男");
			map.put("height", "178");
			map.put("time", new Date().toString());
			// 文字数据
			String str =  getString();
			List<Paragraph> l = getPars(str, map);
		
			for(Paragraph p : l){
				document.add(p);
			}
			//表格数据
			//创建一个有4列的表格
			PdfPTable table = new PdfPTable(4);
			// 可以对表格进行控制

			
			// 默认会生成普通cell,特殊cell 要通过PdfPCell 进行设置
			table.addCell(getParagraph("发票税率"));
			table.addCell(getParagraph("发票编号"));
			table.addCell(getParagraph("发票类型"));
			table.addCell(getParagraph("金额"));
			// 剩余的表格数据
			List<String> cells = getTableParams();
			for(String cell:cells){
				table.addCell(getParagraph(cell));
			}
			document.add(table);
			

	
			
			document.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}		
	}
	
	

	

	// 给Dcouemnt 添加内容
	public Document setDocumentContext(Document document,List<Paragraph> paragraphs){
		if(paragraphs != null){
			for(Paragraph paragraph : paragraphs){
				try {
					document.add(paragraph);
				} catch (DocumentException e) {
					e.printStackTrace();
				}
			}
		}
		return document;
	}
	
	public static String setParams(String context,List<String> params,String str_replace){
			if(context == null || params == null || str_replace == null){
				return context;
			}
			for(String param : params){
				Chunk chunk = new Chunk(param, UNDER_LINE);
				context = context.replaceFirst(str_replace, chunk.toString());
			}
			return context;
	}
	
	public static void setParams(String param,Paragraph pa){
		pa.add( new Chunk(param, UNDER_LINE));
	}
	
	
	public static String setParams(String context,List<String> params){
		return setParams(context, params,"\\?");
	}
	
	public static List<Chunk> getListChunks(List<String> params){
		List<Chunk> chunks = new ArrayList<Chunk>();
		for(String param : params){
			Chunk e = new Chunk(param, UNDER_LINE);
			chunks.add(e);
		}
		return chunks;
	}
	

	
	public static List<String> getList(){
		List<String> params = new ArrayList<String>();
		params.add("计划-08-采购-购置-传输08-202-002-006");
		params.add("2008503180");
		params.add("993290.00");
		params.add("到货款");
		params.add("20%");
		params.add("198658.00");
		params.add("壹拾玖万捌仟陆佰伍拾捌圆整");
		params.add("1");
		params.add("198658.00");
		return params;
	}
	
	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 String getString2(){
		String str = "贵司与我司签订的采购合同,合同编号:"
			+"{conNo},采购订单号:{poNo} ,该合同金额为:{conMoney} 。"
			+"{#}  发票明细:{pp}  {#}  魔法:{xx} {#} OVER!";
		return str;
	}
	
	public static String getString(){
		String str = 
			  "{#}工程师们,大家晚上好,我叫:{name},性别:{sex},身高:{height}cm."
			+ "当前时间是:{time}{#}"
			+ "这是文字行的测试数据,下面我们尝试表格型的测试数据。"
			+ "{#}这里展示我们的订单信息:{#}";
		return str;
	}
	
	public static List<String> getTableParams(){
		// 为了方便就按顺序存放
		List<String> l = new ArrayList<String>();
		l.add("%12");
		l.add("T9090990");
		l.add("食品类发票");
		l.add("1000.0");
		
		l.add("%15");
		l.add("Q12023");
		l.add("服务类发票");
		l.add("9999.0");
		return l;
	}
	
	public static List<Paragraph> getPars(String context ,Map<String,String> 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(param));
				}
			}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;
	}
	

	// 默认样式
	public static Paragraph getParagraph(String context){
		return getParagraph(context,fontChinese);
	}
	
	// 指定字体样式
	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 getDefaultParagraph(String context){
		Paragraph p = getParagraph(context);
		// 默认行间距
		p.setLeading(DEFAULT_LEADING);
		// 默认首行空隙
		p.setFirstLineIndent(DEFAULT_LINE_INDENT);
		return p;
	}
	
}

 

 

上面的类,可能有点乱,也是测试用用。在语言包的选择上,itext 5 的和我下到的iTextAsian.jar 不同,因为引用路径变了,也就是说解压iTextAsian.jar,然后将lowagie 改为itextpdf 就行了,然后从新压缩。

命令:jar cvf iTextAsian.jar com/itextpdf/text/pdf/fonts/*

 

这里我都做好了,下面两个jar,可以直接使用。

 

小结:

        1.最近比较忙,上面的例子很粗糙,但是能给大家一个思路,基本上照着上面的写都可以完成。

        2.对于itext 的使用,我也是第一次,很多地方不完善,API  以及语言 还不深入,暂时能用就行,需要深入的,大家自己研究。

        3.spring mvc 提供了很多视图,大家平时操作的时候,可以先了解下,如果提供了,可以减少你的部分代码。

        4.如果有误的地方,请指出,非常感谢~。~

 

  • 大小: 74.3 KB
3
4
分享到:
评论
1 楼 songplwh 2016-03-14  
这些子类算是service么   那么那些工具类又算什么   实施到spring mvc框架里去

相关推荐

Global site tag (gtag.js) - Google Analytics