Java实现HTML(带图片)转PDF的解决方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/erlian1992/article/details/82631290

Java实现HTML(带图片)转PDF的解决方案

前端页面实现

后端具体实现:

Controller

package com.huajin.ptoms.controller.user;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.huajin.baymax.logger.XMsgError;
import com.huajin.baymax.logger.Xlogger;
import com.huajin.ptoms.controller.HjBaseController;
import com.huajin.ptoms.service.MemberFilingLetterService;
import com.huajin.ptoms.util.PdfUtil;

/**
 * 会员资格证书控制层
 *
 * @author hongwei.lian
 * @date 2018年9月10日 下午1:41:44
 */
@Controller
@RequestMapping("/user/membeFilingLetter")
public class MemberFilingLetterController extends HjBaseController {
	
	@Autowired
	private MemberFilingLetterService memberFilingLetterService;
	
	/**
	 * 打印预览会员资格证书
	 *
	 * @param memberId 
	 * @author hongwei.lian
	 * @date 2018年9月10日 下午1:41:58
	 */
	@RequestMapping("printletter")
	public void printLetter(@RequestParam("memberId") int memberId){
		try {
			//-- 获取PDF签章地址
			String filepath = memberFilingLetterService.downMemberLetter(memberId, super.getExchangeId());
			//-- 设置PDF响应头
			HttpServletResponse response = PdfUtil.setPdfResponse(super.response());
			//-- 打印PDF
			PdfUtil.printLetter(filepath, response.getOutputStream());
		} catch (Exception e) {
			Xlogger.error(XMsgError.buildSimple(getClass().getName(), "printLetter", e));
		}
	}
	
}

PdfUtil工具类

package com.huajin.ptoms.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.property.Property;

public class PdfUtil {
	
	/**
	 * 设置PDF响应头
	 *
	 * @param response
	 * @return 
	 * @author hongwei.lian
	 * @date 2018年9月10日 下午6:02:47
	 */
	public static HttpServletResponse setPdfResponse(HttpServletResponse response) {
		response.setCharacterEncoding("utf-8");
		response.setContentType("application/pdf");
		return response;
	}
	
	/**
	 * 打印PDF
	 *
	 * @param filepath
	 * @param outputStream 
	 * @author hongwei.lian
	 * @date 2018年9月10日 下午6:04:26
	 */
	public static void printLetter(String filepath, OutputStream outputStream){
		FileInputStream inputStream = null;
		try {
			File file = new File(filepath);
			inputStream = new FileInputStream(file);
			byte[] data = new byte[(int)file.length()];
			inputStream.read(data);
	        outputStream.write(data);
	        outputStream.flush();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (Objects.nonNull(outputStream)) {
					outputStream.close();
				}
				if (Objects.nonNull(inputStream)) {
					inputStream.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
}

MemberFilingLetterService服务层

package com.huajin.ptoms.service;

import java.io.File;
import java.io.StringWriter;
import java.util.Date;
import java.util.Objects;

import org.apache.commons.io.FileUtils;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.huajin.baymax.exception.BayMaxBaseException;
import com.huajin.baymax.support.ResponseCodeBase;
import com.huajin.baymax.util.DateUtils;
import com.huajin.exchange.enums.notice.LetterType;
import com.huajin.exchange.utils.PdfUtils;
import com.huajin.ptoms.domain.UcUser;
import com.huajin.usercenterclient.vo.SealApplyVo;

/**
 * 会员资格证书生成业务层
 *
 * @author hongwei.lian
 * @date 2018年9月10日 下午1:38:08
 */
@Service
public class MemberFilingLetterService {
	
	@Autowired
	private VelocityEngine velocityEngine;

	@Autowired
	private UcUserService ucUserService;
	
	@Autowired
	private SysParamService sysParamService;
	
	@Autowired
	private FeSealService feSealService;
	
	@Autowired
	private FeExchangeService feExchangeService;
	
	/**
	 * 下载/打印会员资格证书
	 *
	 * @param memberId
	 * @param exchangeId
	 * @return
	 * @throws Exception 
	 * @author hongwei.lian
	 * @date 2018年9月10日 下午1:38:52
	 */
	public String downMemberLetter(int memberId, int exchangeId) throws Exception {
		UcUser member = ucUserService.getUserAllById(memberId, 0);
		if (Objects.isNull(member)) {
			throw new BayMaxBaseException(ResponseCodeBase.SYSTEM_ERROR, null, "会员不存在!");
		}
		//-- 创建目标文件目录
		String destPath = sysParamService.getNoticeFileStorageAddress() + File.separator + "member" + File.separator;
		File destPathFile = new File(destPath);
		if (!destPathFile.exists()) {
			destPathFile.mkdirs();
		}
		//-- 会员资格证书文件路径
		String fileName = String.valueOf(LetterType.开户通知书.type) + "_" + member.getUserGuid() + ".pdf";
		String noticeFilePath = destPath + fileName;
		File destFile = new File(noticeFilePath);
		if (!destFile.exists() || Objects.equals(FileUtils.sizeOf(destFile), 0)) {
			String origin = destPath + "origin" + File.separator + fileName;
			//-- 创建并生成pdf
			this.createMemberNoticeFile(origin, member);
			SealApplyVo seal = feSealService.getUserSeal(exchangeId);
			if (Objects.nonNull(seal)) {
				//-- 会员资格证书签章
				feSealService.sealPdfByCoordinate(origin, destPath, seal.getSealInfoId(), 
						feExchangeService.getDefaultExchangeInfo().getExchangeName(), "会员资格证书", "会员资格证书", 
						1, 500, 50);
			}
		}
		return noticeFilePath;
	}

	/**
	 * 生成会员资格证书
	 *
	 * @param destFilePath
	 * @param member
	 * @throws Exception 
	 * @author hongwei.lian
	 * @date 2018年9月10日 下午1:39:11
	 */
	private void createMemberNoticeFile(String destFilePath, UcUser member) throws Exception {
		VelocityContext context = new VelocityContext();
		context.put("member", member);
		context.put("exchange", feExchangeService.getExchangeInfo(member.getExchangeId()));
		context.put("today", DateUtils.formatDate(new Date(), "yyyy年MM月dd日"));
		StringWriter stringWriter = new StringWriter();
		velocityEngine.mergeTemplate("/template/membership.html", "UTF-8", context, stringWriter);
		PdfUtils.htmlToPdf(stringWriter.toString(), destFilePath);
	}

}

PdfUtils工具类

package com.huajin.exchange.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;

import org.apache.logging.log4j.core.util.FileUtils;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

public class PdfUtils {
	
	public static final void htmlToPdf(String htmlContent, String filePath) throws Exception {
		FileUtils.mkdir(new File(filePath).getParentFile(), true);
		
		try (OutputStream fileStream = new FileOutputStream(filePath)) {
			ITextRenderer textRenderer = new ITextRenderer();
			ITextFontResolver fontResolver = textRenderer.getFontResolver();

			String agreementBody = htmlContent;
			agreementBody = agreementBody.replace(" ", " ");
			agreementBody = agreementBody.replace("–", "–");
			agreementBody = agreementBody.replace("—", "—");
			agreementBody = agreementBody.replace("‘", "‘"); // left single quotation mark
			agreementBody = agreementBody.replace("’", "’"); // right single quotation mark
			agreementBody = agreementBody.replace("‚", "‚"); // single low-9 quotation mark
			agreementBody = agreementBody.replace("“", "“"); // left double quotation mark
			agreementBody = agreementBody.replace("”", "”"); // right double quotation mark
			agreementBody = agreementBody.replace("„", "„"); // double low-9 quotation mark
			agreementBody = agreementBody.replace("′", "′"); // minutes
			agreementBody = agreementBody.replace("″", "″"); // seconds
			agreementBody = agreementBody.replace("‹", "‹"); // single left angle quotation
			agreementBody = agreementBody.replace("›", "›"); // single right angle quotation
			agreementBody = agreementBody.replace("‾", "‾"); // overline

			fontResolver.addFont("/fonts/simsun.ttc", com.itextpdf.kernel.pdf.PdfName.IdentityH.getValue(), false);
			textRenderer.setDocumentFromString(agreementBody, null);
			textRenderer.layout();
			textRenderer.createPDF(fileStream, true);
		} 
	}
}

membership.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>会员资格证书</title>
  <style>
        @page { 
              size: 10.42in 7.42in; 
              margin: 0; 
              content: counter(page);
              width: 100%; 
              height: 100%; 
        } /*不能随意修改这里 hongwei.lian*/
        
        * {
            margin:0;
            padding:0;
        }
        
        html, body {
            font-family:'SimSun';
            font-size:14pt;
            width: 100%;
	        height: 100%; 
            /*background:url(/data/App/ptoms.cfaoe.local/logo-bg.jpg);*/
        }/*宋五*/
        
	    .vip {
	      position: relative;
	      margin: 0 auto; 
	      width: 1000px;
	      height: 711px; 
	      /* font-family: '宋体'; */
	      background: url(/data/App/ptoms.cfaoe.local/vip_bg.jpg) center center no-repeat;
	    }
	
	    div.vip-item {
	      position: absolute;
	      height: 30px;
	      border: none;
	      font-size: 20px;
	      font-weight: bold;
	      color: #333;
	    }
	
	    .companyname {
	      padding: 0 4px;
	      top: 319px;
	      left: 365px;
	      width: 487px;
	      background: url(/data/App/ptoms.cfaoe.local/vip_input-bg1.jpg);
	    }
	
	    .vipnumber {
	      padding: 0 4px;
	      top: 450px;
	      left: 221px;
	      width: 277px;
	      background: url(/data/App/ptoms.cfaoe.local/vip_input-bg2.jpg);
	    }
	
	    .date {
	      padding: 0 4px;
	      top: 450px;
	      left: 608px;
	      width: 195px;
	      background: url(/data/App/ptoms.cfaoe.local/vip_input-bg3.jpg);
	    }
  </style>
</head>
<body>
  <div class="vip">
    <div class="vip-item companyname">
         ${member.companyName}
    </div>
    <div class="vip-item vipnumber">
         ${member.UserCode}
    </div>
    <div class="vip-item date">
         ${today}
    </div>
  </div>
</body>
</html>

核心的东西就是上面标红的代码和HTMNL页面代码。

具体需要查看VelocityContext和VelocityEngine两个核心类使用和源码

生成效果:

HTML转PDF依赖:

gradle依赖:

//-- velocity

compile ('org.apache.velocity:velocity:1.7')



//-- html to pdf

compile ('com.itextpdf:kernel:7.0.1')

compile ('org.xhtmlrenderer:flying-saucer-core:9.1.1')

compile ('org.xhtmlrenderer:flying-saucer-pdf-itext5:9.1.1')



//-- about

compile ('com.itextpdf:pdfa:7.0.1')

compile ('com.itextpdf:hyph:7.0.1')

compile ('com.itextpdf:sign:7.0.1')

compile ('com.itextpdf:barcodes:7.0.1')

compile ('com.itextpdf:font-asian:7.0.1')

猜你喜欢

转载自blog.csdn.net/erlian1992/article/details/82631290