参考記事出典:
springboot+itextpdf テンプレートに従ってPDFファイルを生成し、オンラインでPDFファイルをダウンロード
JAVAはテンプレートに従ってPDFファイルを生成し、エクスポートします
Java は、指定された長さに従って文字列を文字列配列に分割します。
私の命を救ってくれた上記のブロガーに感謝します~~~
私のシステム環境: win10, IDEA, jdk1.8
1.Adobe Acrobat DCのダウンロード
Baidu リンク: リンク: https://pan.baidu.com/s/1RSV8D6kXDbWeV2owgw2Zyg
抽出コード: f8p8
は自分で取得できます。
2. テンプレートの準備
1. Word でテンプレートを描画し、pdf として保存します。
私が生成した pdf テンプレートを下の画像に示します。
2. ソフトウェアを開きます: Adobe Acrobat DC
ページは下図のとおりで、[ツール] - [フォームの準備] を選択し
、ここに上記の pdf ファイルを配置して、
フォームの編集ページに入り、フィールドを編集します (フィールド名は、プログラム内のフィールド名と一致している必要があります)。 . 私の編集は下の写真に示されています。
[備考]欄は下線が必要で、コメント文が少し長くなるかもしれないので、ここではこのように設定しましたが、私の考えは次のとおりです
。 、bz-line2、bz-line3 の 3 つのテキスト ドメインを作成し、それぞれの属性を設定します (ドメインをダブルクリックするだけで、テキスト サイズ、スタイルなどを設定できます)。2.プログラムでは
、データ (文字列型) を読み込み、固定長に従って文字列をインターセプトし、bz-line1、bz-line2、bz-line3 に循環的に配置します。プログラムの後半で、私が使用するばかげた方法を示します。. . .
3. 実は。. 下線が不要な場合は、[プロパティ] の [複数行] に直接チェックを入れることで、複数テキストの改行を実現できます。
3. 編集したテンプレートを保存する
三、Java実装
1. Maven の依存関係を追加する
<!-- PDF工具类 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<!-- PDF中文支持 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
2.ローカルで指定されたパスにpdfを直接生成します
(1)、pdfUtils クラス
public class PdfUtils {
private final static Logger log = LoggerFactory.getLogger(PdfUtils.class);
// 利用模板生成pdf,这将直接保存到指定路径
public static void pdfout(Map<String,Object> o,String templatePath,String newPDFPath) {
PdfReader reader;
FileOutputStream out=null;
ByteArrayOutputStream bos=null;
PdfStamper stamper;
try {
//系统字体
String prefixFont = "";
String os = System.getProperties().getProperty("os.name");
if (os.startsWith("win") || os.startsWith("Win")) {
prefixFont = "C:\\Windows\\Fonts" + File.separator;
} else {
prefixFont = "/usr/share/fonts/chinese" + File.separator;
}
//必须加“,0”或“,1”,否则会报错:com.itextpdf.text.DocumentException: Font 'C:\Windows\Fonts\simsun.ttc' with 'Identity-H' is not recognized.
BaseFont bf = BaseFont.createFont(prefixFont + "simsun.ttc,0" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
out = new FileOutputStream(newPDFPath);// 输出流
reader = new PdfReader(templatePath);// 读取pdf模板
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
Map<String,String> datemap = (Map<String,String>)o.get("datemap");
form.addSubstitutionFont(bf);
for(String key : datemap.keySet()){
//为了文字可以有下划线,并且换行,控制每行字数,当字数超过时,将剩余文字填充至下一备选域
if ("hzbz".equals(key)){
String hzbz = datemap.get(key);
String[] hzbzArray = stringToStringArray(hzbz,24);
for(int i = 0; i < hzbzArray.length; i++){
String fkey = "hzbz-line" + (i+1);
form.setField(fkey,hzbzArray[i]);
}
}else if("bz".equals(key)){
String bz = datemap.get(key);
String[] bzArray = stringToStringArray(bz,24);
for(int i = 0; i < bzArray.length; i++){
String fkey = "bz-line" + (i+1);
form.setField(fkey,bzArray[i]);
}
}else{
String value = datemap.get(key);
form.setField(key,value);
}
}
//图片类的内容处理
Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");
for(String key : imgmap.keySet()) {
Image value = imgmap.get(key);
//String imgpath = value;
Image image = value;
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
//根据路径读取图片
//Image image = Image.getInstance(imgpath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
stamper.setFormFlattening(true);// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.close();
Document doc = new Document(PageSize.A4, 50, 40, 40, 50);
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
//form.getTotalRevisions();
int pages= stamper.getReader().getNumberOfPages();
for(int i=1;i<=pages;i++){
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);
copy.addPage(importPage);
}
doc.close();
} catch (IOException e) {
log.error("pdfout",e);
} catch (DocumentException e) {
log.error("pdfout",e);
}finally {
if(out!=null){
try{
out.close();
}catch(Exception e){
}
}
if(bos!=null){
try{
bos.close();
}catch(Exception e){
}
}
}
}
// 将字符串按照指定长度分割成字符串数组
public static String[] stringToStringArray(String src, int length) {
//检查参数是否合法
if (null == src || src.equals("")) {
return null;
}
if (length <= 0) {
return null;
}
int n = (src.length() + length - 1) / length; //获取整个字符串可以被切割成字符子串的个数
String[] split = new String[n];
for (int i = 0; i < n; i++) {
if (i < (n - 1)) {
split[i] = src.substring(i * length, (i + 1) * length);
} else {
split[i] = src.substring(i * length);
}
}
return split;
}
public static byte[] inputstream2Bytes(InputStream inStream) throws IOException{
byte[] in_b = null;
try{
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据
int rc = 0;
while ((rc = inStream.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
in_b = swapStream.toByteArray(); //in_b为转换之后的结果
}catch(Exception e){
log.error("inputstream2Bytes",e);
}finally {
inStream.close();
}
return in_b;
}
/**
* @Description: 文件转流
*/
public static InputStream file2InputStream(File file) throws IOException{
return new FileInputStream(file);
}
(2)、コントローラ層
@Controller
@RequestMapping("/pdf")
public class PdfController {
@PostMapping("/createPdf")
@ResponseBody
public DataObject CreatePdf() throws AppException {
//1、调用数据库,获取数据
//此处写读取数据的代码
//2、将数据存为key-value
//存文字信息
Map<String,String> map = new HashMap();
//存图像信息
Map<String,Image> mapI = new HashMap();
map.put("name","田XX");
map.put("sex","女");
map.put("grbh","123456789010");
map.put("sfzh","000000000000000000");
map.put("rylb","啊哦");
map.put("time1","2021-9-27");
map.put("ddyy1","啊哦");
map.put("time2","");
map.put("ddyy2","");
map.put("hzbz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");
map.put("bz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");
try{
//图片路径
File pic_file = new File("F:\\1555074510295049.jpg");
Image pic_image = Image.getInstance(inputstream2Bytes(file2InputStream(pic_file)));
mapI.put("pic",pic_image);
}catch(Exception e){
}
Map<String,Object> o=new HashMap();
o.put("datemap",map);
o.put("imgmap",mapI);
// 模板路径
String templatePath = "/META-INF/resources/static/template/template.pdf";
// 生成的新文件路径
String newPDFPath = "F:\\template_sc.pdf";
pdfout(o,templatePath,newPDFPath);
return DataObject.getInstance();
}
}
(3)正面玄関
layui.sight.ajaxRequest({
type : 'post',
async : true,
url : layui.sight.compileUrl('${rc.contextPath}/pdf/CreatePdf'),
data : [],
callback : function(data) {
alert("成功!")
},
failedCallback : function(data) {
}
});
3.PDFをエクスポート
(1) pdfUtils クラス
public class PdfUtils {
private final static Logger log = LoggerFactory.getLogger(PdfUtils.class);
/**
* 利用模板生成pdf导出
*/
public static void pdfExport(Map<String, Object> o, HttpServletResponse response) {
// 模板路径
String templatePath = "/META-INF/resources/static/template/template.pdf";
File file = new File(templatePath);
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
PdfReader reader;
ByteArrayOutputStream bos;
PdfStamper stamper;
OutputStream out = null;
try {
BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 输出流
response.setContentType("application/pdf");
response.setHeader("Content-Disposition",
"attachment;fileName=" + URLEncoder.encode("template_scsc.pdf", "UTF-8"));
out = new BufferedOutputStream(response.getOutputStream());
// 读取pdf模板
reader = new PdfReader(templatePath);
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
Map<String,String> datemap = (Map<String,String>)o.get("datemap");
form.addSubstitutionFont(bf);
for(String key : datemap.keySet()){
//为了文字可以有下划线,并且换行,控制每行字数,当字数超过时,将剩余文字填充至下一备选域
if ("hzbz".equals(key)){
String hzbz = datemap.get(key);
String[] hzbzArray = stringToStringArray(hzbz,24);
for(int i = 0; i < hzbzArray.length; i++){
String fkey = "hzbz-line" + (i+1);
form.setField(fkey,hzbzArray[i]);
}
}else if("bz".equals(key)){
String bz = datemap.get(key);
String[] bzArray = stringToStringArray(bz,24);
for(int i = 0; i < bzArray.length; i++){
String fkey = "bz-line" + (i+1);
form.setField(fkey,bzArray[i]);
}
}else{
String value = datemap.get(key);
form.setField(key,value);
}
}
//图片类的内容处理
Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");
for(String key : imgmap.keySet()) {
Image value = imgmap.get(key);
//String imgpath = value;
Image image = value;
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
//根据路径读取图片
//Image image = Image.getInstance(imgpath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
stamper.setFormFlattening(true);
stamper.close();
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
copy.addPage(importPage);
doc.close();
} catch (IOException | DocumentException e) {
System.out.println(e);
} finally {
try {
assert out != null;
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 将字符串按照指定长度分割成字符串数组
public static String[] stringToStringArray(String src, int length) {
//检查参数是否合法
if (null == src || src.equals("")) {
return null;
}
if (length <= 0) {
return null;
}
int n = (src.length() + length - 1) / length; //获取整个字符串可以被切割成字符子串的个数
String[] split = new String[n];
for (int i = 0; i < n; i++) {
if (i < (n - 1)) {
split[i] = src.substring(i * length, (i + 1) * length);
} else {
split[i] = src.substring(i * length);
}
}
return split;
}
public static byte[] inputstream2Bytes(InputStream inStream) throws IOException{
byte[] in_b = null;
try{
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100]; //buff用于存放循环读取的临时数据
int rc = 0;
while ((rc = inStream.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
in_b = swapStream.toByteArray(); //in_b为转换之后的结果
}catch(Exception e){
log.error("inputstream2Bytes",e);
}finally {
inStream.close();
}
return in_b;
}
/**
* @Description: 文件转流
*/
public static InputStream file2InputStream(File file) throws IOException{
return new FileInputStream(file);
}
(2)、コントローラ層
@Controller
@RequestMapping("/pdf")
public class PdfController {
@RequestMapping("/exportPdf")
public void exportPdf(HttpServletRequest request, HttpServletResponse response) throws AppException {
//调用数据库,获取数据
//将数据存为key-value
//存文字信息
Map<String,String> map = new HashMap();
//存图像信息
Map<String,Image> mapI = new HashMap();
map.put("name","田XX");
map.put("sex","女");
map.put("grbh","12345678910");
map.put("sfzh","00000000000000000");
map.put("rylb","啊哦");
map.put("time1","2021-9-27");
map.put("ddyy1","啊哦");
map.put("time2","");
map.put("ddyy2","");
map.put("hzbz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");
map.put("bz","有的人一生默默无闻,有的人一生轰轰烈烈,甚至千古流芳,为什么会这样?因为默默无闻的人只是满足于现状,而不去想怎么轰轰烈烈过一生,不要求自己,去做");
try{
//图片路径
File pic_file = new File("F:\\1555074510295049.jpg");
Image pic_image = Image.getInstance(inputstream2Bytes(file2InputStream(pic_file)));
mapI.put("pic",pic_image);
}catch(Exception e){
}
Map<String,Object> o=new HashMap();
o.put("datemap",map);
o.put("imgmap",mapI);
pdfExport(o,response);
}
}
(3)正面玄関
function down(){
var url = layui.sight.compileUrl('${rc.contextPath}/pdf/exportPdf');
window.open(encodeURI(url));
}
4. 最終的な効果
写真はうまく選択されていません。.
五、問題がある
プロジェクトがパッケージ化された後、jar パッケージが開始されたときに null ポインター エラーが報告されます.具体的なエラーの説明をコピーするのを忘れていました.
解決策: PdfUtils
を変更します。変更後:
/**
* 利用模板生成pdf导出
*/
public static void pdfExport(Map<String, Object> o, HttpServletResponse response) throws IOException {
// 生成的新文件路径
String filePath = "D:\\test.text";
// 模板路径
Resource resource = new ClassPathResource("/META-INF/resources/static/template/template.pdf");
File inuModel = new File(filePath);
FileUtils.copyInputStreamToFile(resource.getInputStream(), inuModel);
PdfReader reader;
ByteArrayOutputStream bos;
PdfStamper stamper;
OutputStream out = null;
try {
BaseFont bf = BaseFont.createFont("C:/Windows/Fonts/simfang.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 输出流
response.setContentType("application/pdf");
response.setHeader("Content-Disposition",
"attachment;fileName=" + URLEncoder.encode("template_scsc.pdf", "UTF-8"));
out = new BufferedOutputStream(response.getOutputStream());
// 读取pdf模板
reader = new PdfReader(filePath);
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
Map<String,String> datemap = (Map<String,String>)o.get("datemap");
form.addSubstitutionFont(bf);
for(String key : datemap.keySet()){
String value = datemap.get(key);
form.setField(key,value);
}
//图片类的内容处理
Map<String, Image> imgmap = (Map<String,Image>)o.get("imgmap");
for(String key : imgmap.keySet()) {
Image value = imgmap.get(key);
//String imgpath = value;
Image image = value;
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
//根据路径读取图片
//Image image = Image.getInstance(imgpath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
stamper.setFormFlattening(true);
stamper.close();
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
copy.addPage(importPage);
doc.close();
} catch (IOException | DocumentException e) {
System.out.println(e);
} finally {
try {
assert out != null;
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}