一:基础设置
Salesforce中的PDF页面本质上还是Visualforce[简称VF]页面,所以只需要给VF页面加上一个属性[renderAs="pdf"] 即可生成一个PDF页面
1 <apex:page renderAs="pdf">
2 this is a Visualforce page!!! 这是一个VF页面
3 </apex:page>
预览页面,可以看到生成了一个PDF页面,但是只显示了英文,涉及的中文字体都没有出现
对于中文,在PDF中,需要设置font-family: Arial Unicode MS;才能显示中文字体。
添加上属性
1 body { 2 font-family: Arial Unicode MS; 3 font-size:14px; 4 font-weight:200; 5 }
此时还需要额外设置几个属性,applyHtmlTag="false" applyBodyTag="false" showheader="false"
原因是Salesforce对自己的页面做了相当程度的封装,所以在这样的全部都是自定义的情况下,设置上面的属性将VF自带的样式关闭,此时预览页面
可以看到中文的正常显示。需要注意的,PDF页面不支持JS,不支持文字的加粗,只能通过文字的字号大小进行区分。
我们来看一个基本的PDF页面模板
1 <apex:page renderAs="pdf" showheader="false" standardstylesheets="false" applyBodyTag="false" applyHtmlTag="false" contentType="text/html; charset=UTF-8"> 2 <html> 3 <head> 4 <style> 5 body { 6 font-family: Arial Unicode MS; 7 font-size:14px; 8 font-weight:200; 9 } 10 </style> 11 </head> 12 this is a Visualforce page!!! 这是一个VF页面 13 <!-- 输入你想要的页面内容 --> 14 </html> 15 </apex:page>
二:页眉和页脚
经常需要使用的PDF页面内容肯定包括页眉和页脚的显示设置,下面用一个demo进行示范
1 @page { 2 @top-center { 3 content: element(header); 4 } 5 @bottom-left { 6 content: element(footer); 7 } 8 } 9 div.header { 10 display: block; 11 height: 20px; 12 position: running(header); 13 } 14 div.footer { 15 display: block; 16 padding: 5px; 17 position: running(footer); 18 } 19 .pagenumber:before { 20 content: counter(page); 21 } 22 .pagecount:before { 23 content: counter(pages); 24 }
页眉页脚对应的页面代码如下
1 <!-- 设置页眉和页脚 --> 2 <!-- 页眉 --> 3 <div class="header" style="border-bottom: 1px solid #ccc"> 4 <div> 5 <img src="{!$Resource.Logo}" style="display: block;height: 20px;float:left;" /> 6 <div style="float:left;"> 7 <span style="font-size:12px;color: #808080;"> https://www.cnblogs.com/</span> 8 <span style="font-size:12px;"> 9 <span style="color: #808080;"> 博客地址:</span> 10 https://www.cnblogs.com/luqinghua/ 11 </span> 12 </div> 13 <div style="clear: both;"></div> 14 </div> 15 </div> 16 <!-- 页脚 --> 17 <div class="footer"> 18 <div style="text-align: center;"> Page <span class="pagenumber"/>/<span class="pagecount"/></div> 19 <div style="border-top: 1px solid #ccc;text-align: center;"> 20 <span style="font-size:12px;color: #808080;"> ADD:Salesforce开发整理[八]</span> 21 <span style="font-size:12px;color: #808080;"> TEL: 152-0721-6593</span> 22 <span style="font-size:12px;color: #808080;"> EMAIL: luqinghua621@gmail.com</span> 23 </div> 24 </div>
页面预览效果
三:中文自动换行
在PDF上换行,如果是前端可以使用<br/> 强制换行,或者文字内使用 换行,但是经常会有传递的中文参数,如果长度超出的情况下,需要自动换行的情况,此时我们可以在后台将中文字符串转换成一个字符串的集合,再在前端页面输出,此时可以看到自动换行的效果。
后台控制器代码
1 public with sharing class PrintPDFController { 2 public List<String> list_Name{get;set;} // PDF标题 3 public PrintPDFController() { 4 String CompanyName = '公司名称特别长超出你需要限制的长度比如15个字公司名称特别长超出你' 5 + '需要限制的长度比如15个字公司名称特别长超出你需要限制的长度比如15' 6 + '个字公司名称特别长超出你需要限制的长度比如15个字'; 7 list_Name = spliteStringToList(CompanyName); 8 } 9 10 11 public List<String> spliteStringToList(String field){ 12 List<String> StringList = new List<String>(); 13 for(integer i = 0 ; i < field.length(); i++){ 14 StringList.add(field.Substring(i,i+1)); 15 } 16 return StringList; 17 } 18 }
前端输出
1 <apex:repeat value="{!list_Name}" var="name"><apex:outputText value="{!name}"/><textarea/></apex:repeat>
可以看到前端的预览
所有的超出页面长度显示的中文都会自动换行显示
四:保留系统中的长文本字段样式输出
打印系统中的长文本字段时需要保留原本的样式进行输出,譬如在业务机会上的描述里面写这样的格式信息,在后台获取并输出
后台控制器代码
1 public with sharing class PrintPDFController { 2 public Integer Index{get;set;} 3 public List<String> IndexList{get;set;} 4 public List<List<List<String>>> ContentList{get;set;} 5 public Map<String,List<List<String>>> ContentMap{get;set;} 6 7 public PrintPDFController() { 8 Opportunity opp = [ SELECT 9 Id, 10 Description 11 FROM 12 Opportunity 13 WHERE 14 Id =:'0066F00000sAyL1QAK' Limit 1]; 15 Index = 0; 16 IndexList = new List<String>(); 17 ContentList = new List<List<List<String>>>(); 18 ContentMap = new Map<String,List<List<String>>>(); 19 spliteString(opp.Description); 20 } 21 public void spliteString(String s){ 22 Index++; 23 IndexList.add(String.valueOf(Index)); 24 List<String> str = s.split(' '); 25 List<String> str_temp; 26 List<List<String>> sTable = new List<List<String>>(); 27 for(String tr:str){ 28 str_temp = new List<String>(); 29 for(Integer i=0;i<tr.length();i++){ 30 str_temp.add(tr.subString(i,i+1)); 31 } 32 sTable.add(str_temp); 33 } 34 ContentList.add(sTable); 35 ContentMap.put(String.valueOf(Index),sTable); 36 } 37 }
前端代码
1 <div> 2 <h3>业务机会描述</h3> 3 <div> 4 <table> 5 <apex:repeat value="{!IndexList}" var="index"> 6 <tr style="border:0px"> 7 <td width="90%" style="border:0px;font-size:13px;"> 8 <apex:repeat value="{!ContentMap[index]}" var="contentList"> 9 <apex:repeat value="{!contentList}" var="con">{!con}<textarea/></apex:repeat> 10 <br/> 11 </apex:repeat> 12 </td> 13 </tr> 14 </apex:repeat> 15 </table> 16 </div> 17 </div>
预览页面效果
五:小技巧汇总
最后记录几个小技巧:
1、控制PDF某一区域作为一个整体不能被分页切割,使用 page-break-inside:avoid; ,可用于div,span,table,tr,td等一切你想要要保持在同一个页面显示的内容;
2、与之相对的就是强制换页使用:<P style='page-break-after:always'> </P> ,类似WORD中的分页符,缺点是其本身也占有一行。
3、PDF页面不支持Javascript的使用,对于某些条件限制的需求,可以使用IF作为判断,比如
value="{!IF(ord.Deals__c=='01-标准','■','□')}"
或者 用于style元素中控制样式的显示
style="{!IF(pi.Company__c!="几米",'display:none;','100%;')}"
4、VF页面时间格式化
<apex:outputText value="{0, date, yyyy-MM-dd}"> <apex:param value="{!con.PlanStartDate__c}" /> </apex:outputText>
如有错漏,欢迎指正,有问题可以在评论区留言,大家共同进步。
----------------------------------------------------- end -----------------------------------------------
最后贴上本文使用的demo页面源码
后台控制器:PrintPDFController
1 public with sharing class PrintPDFController { 2 public List<String> list_Name{get;set;} // PDF标题 3 4 public Integer Index{get;set;} 5 public List<String> IndexList{get;set;} 6 public List<List<List<String>>> ContentList{get;set;} 7 public Map<String,List<List<String>>> ContentMap{get;set;} 8 9 public PrintPDFController() { 10 String CompanyName = '公司名称特别长超出你需要限制的长度比如15个字公司名称特别长超出你' 11 + '需要限制的长度比如15个字公司名称特别长超出你需要限制的长度比如15' 12 + '个字公司名称特别长超出你需要限制的长度比如15个字'; 13 list_Name = spliteStringToList(CompanyName); 14 15 Opportunity opp = [ SELECT 16 Id, 17 Description 18 FROM 19 Opportunity 20 WHERE 21 Id =:'0066F00000sAyL1QAK' Limit 1]; 22 23 Index = 0; 24 IndexList = new List<String>(); 25 ContentList = new List<List<List<String>>>(); 26 ContentMap = new Map<String,List<List<String>>>(); 27 28 spliteString(opp.Description); 29 } 30 31 32 public List<String> spliteStringToList(String field){ 33 List<String> StringList = new List<String>(); 34 for(integer i = 0 ; i < field.length(); i++){ 35 StringList.add(field.Substring(i,i+1)); 36 } 37 return StringList; 38 } 39 40 public void spliteString(String s){ 41 Index++; 42 IndexList.add(String.valueOf(Index)); 43 List<String> str = s.split(' '); 44 List<String> str_temp; 45 List<List<String>> sTable = new List<List<String>>(); 46 for(String tr:str){ 47 str_temp = new List<String>(); 48 for(Integer i=0;i<tr.length();i++){ 49 str_temp.add(tr.subString(i,i+1)); 50 } 51 sTable.add(str_temp); 52 } 53 ContentList.add(sTable); 54 ContentMap.put(String.valueOf(Index),sTable); 55 } 56 }
前端VF页面
1 <apex:page renderAs="pdf" showheader="false" standardstylesheets="false" applyBodyTag="false" applyHtmlTag="false" contentType="text/html; charset=UTF-8" controller="PrintPDFController"> 2 <html> 3 <head> 4 <style> 5 body { 6 font-family: Arial Unicode MS; 7 font-size:14px; 8 font-weight:200; 9 } 10 @page { 11 @top-center { 12 content: element(header); 13 } 14 @bottom-left { 15 content: element(footer); 16 } 17 } 18 div.header { 19 display: block; 20 height: 20px; 21 position: running(header); 22 } 23 div.footer { 24 display: block; 25 padding: 5px; 26 position: running(footer); 27 } 28 .pagenumber:before { 29 content: counter(page); 30 } 31 .pagecount:before { 32 content: counter(pages); 33 } 34 </style> 35 </head> 36 this is a Visualforce page!!! 这是一个VF页面 37 <br/> 38 <!-- 输入你想要的页面内容 --> 39 <apex:repeat value="{!list_Name}" var="name"><apex:outputText value="{!name}"/><textarea/></apex:repeat> 40 <br/> 41 42 <div> 43 <h3>业务机会描述</h3> 44 <div> 45 <table> 46 <apex:repeat value="{!IndexList}" var="index"> 47 <tr style="border:0px"> 48 <td width="90%" style="border:0px;font-size:13px;"> 49 <apex:repeat value="{!ContentMap[index]}" var="contentList"> 50 <apex:repeat value="{!contentList}" var="con">{!con}<textarea/></apex:repeat> 51 <br/> 52 </apex:repeat> 53 </td> 54 </tr> 55 </apex:repeat> 56 </table> 57 </div> 58 </div> 59 60 <!-- 设置页眉和页脚 --> 61 <!-- 页眉 --> 62 <div class="header" style="border-bottom: 1px solid #ccc"> 63 <div> 64 <img src="{!$Resource.Logo}" style="display: block;height: 20px;float:left;" /> 65 <div style="float:left;"> 66 <span style="font-size:12px;color: #808080;"> https://www.cnblogs.com/</span> 67 <span style="font-size:12px;"> 68 <span style="color: #808080;"> 博客地址:</span> 69 https://www.cnblogs.com/luqinghua/ 70 </span> 71 </div> 72 <div style="clear: both;"></div> 73 </div> 74 </div> 75 <!-- 页脚 --> 76 <div class="footer"> 77 <div style="text-align: center;"> Page <span class="pagenumber"/>/<span class="pagecount"/></div> 78 <div style="border-top: 1px solid #ccc;text-align: center;"> 79 <span style="font-size:12px;color: #808080;"> ADD:Salesforce开发整理[八]</span> 80 <span style="font-size:12px;color: #808080;"> TEL: 152-0721-6593</span> 81 <span style="font-size:12px;color: #808080;"> EMAIL: luqinghua621@gmail.com</span> 82 </div> 83 </div> 84 </html> 85 </apex:page>