java(优化四) 自动生成pdf文件并保存到本地

本文详细介绍了如何使用Java实现根据特定模板和数据生成PDF文件的过程,包括服务接口设计、配置注入、模板文件内容解析及生成逻辑。重点阐述了如何通过模板配置和数据模型来动态生成PDF文件,并提供了具体接口实现和模板示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 测试:

private static final String PDF_KEY = "GENERATEPDF";
FileGenerator pdfGenServ = (FileGenerator) getBean("pdfGenServ");
Result result = pdfGenServ.genFile(PDF_KEY, pdfModelVo);

二  操作步骤:

2.1 实体类 

实体类:PdfModelVo 自己添加get()和set();属性名称如下:
 
public class PdfModelVo implements Serializable {

	private static final long serialVersionUID = 1645865443L;

	/** 用户名(出借方/投资人) */
	private String invest_username;

	/** 用户身份证号(出借方/投资人) */
	private String invest_useridcard;

	/** 借款方真实姓名 **/
	private String loan_username;

	/** 组织机构代码 **/
	private String org_code;

	/** 地址 **/
	private String contact_address;

	/** 法人姓名 **/
	private String legal_username;

	/** 项目编号 **/
	private String project_code;

	/** 借款总额(显示万元) **/
	private String loan_funds;

	/** 借款总额(显示大写万元) **/
	private String loan_big_funds;

	/** 项目开始时间 (年) **/
	private String gmt_start_year;

	/** 项目开始时间 (月) **/
	private String gmt_start_month;

	/** 项目开始时间 (日) **/
	private String gmt_start_day;

	/** 项目结束时间(年) **/
	private String gmt_end_year;

	/** 项目结束时间 (月) **/
	private String gmt_end_month;

	/** 项目结束时间 (日) **/
	private String gmt_end_day;

	/** 还款期数 **/
	private Long repay_order;

	/** 借款用途 **/
	private String loan_use_name;

	/** 担保物 **/
	private String assure_goods;

	/** 担保方式 **/
	private String assure_type_name;

	/** 付息日 **/
	private Long pay_day;

	/** 借款利率 **/
	private BigDecimal loan_apr;
}

2.2 service层接口

public interface FileGenerator<T> {
	/**
	 * 根据模板key和数据model生成文件
	 * 
	 * 1.	根据模板key找到模板文件,并加载文件
	 * 2.	调用Itext的生成对应类型的文件,并将该文件在服务器上落地
	 * 3.	返回服务器上的存放地址
	 * 
	 * @param templateKey 模板key
	 * @param model
	 * @return
	 */
	public Result genFile(String templateKey,T model);
}

2.3 service层接口实现类

@Service("pdfGenServ")
@Transactional
public class PdfGenServImpl implements FileGenerator<Serializable>{
	
	/** 记录日志的接口 */
	private Logger log = Logger.getLogger(getClass());
	private String templetPrefix;
	private String templetSuffix;
	private String genFileSuffix;
	private String templetDirPath;
	private String genFileDir;
	private String logoPath;
	private String fontPath;
	private String fontPath_hei;
	private FileRootPathServ fileRootPathServ;
	
	/**
	 * 创建文件所需数据.
	 *
	 * @param model 生成文件所需的数据对象
	 * @param templateKey 模板key
	 * @return 返回生成结果
	 */
	@Override
	public Result genFile(String templateKey,Serializable model) {
		Result result = new Result();

		if (null == model) {
			result.setSuccess(false);
			result.setMessage("数据对象为空,不能下载");
			return result;
		}

		if (StringUtils.isBlank(templateKey)) {
			result.setSuccess(false);
			result.setMessage("模板KEY为空,不能下载");
			return result;
		}

		templateKey = templateKey.trim();
		/* 创建配置 */
		Configuration cfg = new Configuration();
		Map<String, Serializable> rootMap = new HashMap<String, Serializable>();
		rootMap.put("model", model);
		CharArrayWriter writer = null;
		OutputStream outputStream = null;
		
		/* 指定模板存放的路径 */
		try {
			cfg.setDirectoryForTemplateLoading(new File(templetDirPath));
			/* 创建数据模型 */
			cfg.setObjectWrapper(ObjectWrapper.BEANS_WRAPPER);

			/* 从上面指定的模板目录中加载对应的模板文件 */
			Template template = cfg.getTemplate(genTempletFileName(templateKey), "UTF-8");
			File file = new File(genFileDir);

			if (!file.exists()) {
				file.mkdirs();
			}

			String pdfAbsolutePath = getGenFilePath(templateKey);
			ITextRenderer renderer = new ITextRenderer();
			writer = new CharArrayWriter();
			outputStream = new FileOutputStream(new File(pdfAbsolutePath));
			template.process(rootMap, writer);
		    
			renderer.setDocumentFromString(writer.toString());
			// 解决图片路径问题
			renderer.getSharedContext().setBaseURL("file:" + logoPath);
			// 解决中文问题
			renderer.getFontResolver().addFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			renderer.getFontResolver().addFont(fontPath_hei, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			renderer.layout();
			renderer.createPDF(outputStream);
			renderer.finishPDF();
			result.setValue("pdfAbsolutePath", pdfAbsolutePath);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			result.setSuccess(false);
			result.setMessage("生成PDF失败");
		} finally {
			if(null != writer) {
				writer.flush();
				writer.close();
			}
			
			if(null != outputStream) {
				try {
					outputStream.flush();
					outputStream.close();
				} catch (IOException e) {
					log.error(e.getMessage(), e);
					result.setSuccess(false);
					result.setMessage("生成PDF失败");
				}
			}
		}
		return result;
	}

	/**
	 * 获取pdf配置目录
	 * @param templateKey
	 * @return
	 */
	private String getGenFilePath(String templateKey) {
		if(genFileDir.endsWith("/")) {
			return genFileDir + "GEN_" + fileRootPathServ.getTemplateName(templateKey) + genFileSuffix;
		}
		
		return genFileDir + "/"+ "GEN_" + fileRootPathServ.getTemplateName(templateKey) + genFileSuffix;
	}
	
	/**
	 * 获取模板配置名称
	 * @param templateKey
	 * @return
	 */
	private String genTempletFileName(String templateKey) {
		return templetPrefix + fileRootPathServ.getTemplateName(templateKey) + templetSuffix;
	}
	
	public void setTempletDirPath(String templetDirPath) {
		this.templetDirPath = templetDirPath;
	}

	public void setTempletSuffix(String templetSuffix) {
		this.templetSuffix = templetSuffix;
	}

	public void setGenFileSuffix(String genFileSuffix) {
		this.genFileSuffix = genFileSuffix;
	}

	public void setGenFileDir(String genFileDir) {
		this.genFileDir = genFileDir;
	}

	public void setTempletPrefix(String templetPrefix) {
		this.templetPrefix = templetPrefix;
	}

	public void setLogoPath(String logoPath) {
		this.logoPath = logoPath;
	}

	public void setFontPath(String fontPath) {
		this.fontPath = fontPath;
	}

	public void setFontPath_hei(String fontPath_hei) {
		this.fontPath_hei = fontPath_hei;
	}

	public void setFileRootPathServ(FileRootPathServ fileRootPathServ) {
		this.fileRootPathServ = fileRootPathServ;
	}
}

2.4 其他接口(共用)

接口: FileRootPathServ
public interface FileRootPathServ {
	
	/**
	 * 获取文件根目录路径.
	 *
	 * @param saveFolder 文件夹名
	 * @return 根目录路径
	 */
	public String getRealPath(String saveFolder);
	
	public String getCwbbRootPath();
	
	public String getTemplateName(String templateKey);
	
}

接口实现类:FileRootPathServImpl
@Service("fileRootPathServ")
@Transactional
public class FileRootPathServImpl implements FileRootPathServ {
	private String uploadRootPath;
	private String cwbbRootPath;
	private Map<String, String> templateMap;
	
	/**
	 * 获取文件根目录路径.
	 *
	 * @param saveFolder 文件夹名
	 * @return 根目录路径
	 */
	public String getRealPath(String saveFolder) {
		if(StringUtils.isBlank(saveFolder)) {
			return uploadRootPath;
		} else {
			saveFolder = saveFolder.trim();
			
			if(saveFolder.startsWith("/")) {
				return uploadRootPath + saveFolder;
			} else {
				return uploadRootPath + "/" + saveFolder;
			}
		}
	}
	
	public String getTemplateName(String templateKey) {
		if(StringUtils.isBlank(templateKey)) {
			return null;
		} 
		
		return templateMap.get(templateKey);
	}
	
	public String getCwbbRootPath() {
		return cwbbRootPath;
	}

	public void setCwbbRootPath(String cwbbRootPath) {
		this.cwbbRootPath = cwbbRootPath;
	}

	public void setUploadRootPath(String uploadRootPath) {
		this.uploadRootPath = uploadRootPath;
	}

	public void setTemplateMap(Map<String, String> templateMap) {
		this.templateMap = templateMap;
	}
}

spring配置:
<span style="white-space:pre">	</span><bean id="fileRootPathServ" class="com.yht.wxt.facade.impl.file.generator.FileRootPathServImpl">
		<property name="uploadRootPath" value="${uploadFilePath}" />
		<property name="cwbbRootPath" value="${templateDirPath}${cwbbTempletDirName}" />
		<property name="templateMap">
			<map>
				<entry key="RECHARGE" value="RECHARGE" />
				<entry key="CASH" value="CASH" />
				<entry key="RECASH" value="RECASH" />
				<entry key="INTEREST" value="INTEREST" />
				<entry key="ACCOUNT" value="ACCOUNT" />
				<entry key="GENERATEPDF" value="GENERATEPDF" />
			</map>
		</property>
	</bean>

<!-- 生成PDF文件 -->
	<bean id="pdfGenServ" class="com.yht.wxt.facade.impl.file.generator.PdfGenServImpl" >
		<property name="templetPrefix" value="PDF_" />
		<property name="templetSuffix" value=".ftl" /> 
		<property name="genFileSuffix" value=".pdf" />
		<property name="templetDirPath" value="${templateDirPath}${pdfTempletDirName}" />
		<property name="genFileDir" value="${genTempDirPath}${pdfGenFileDirName}" />
		<property name="logoPath" value="${logoPath}" />
		<property name="fontPath" value="${fontPath}" />
		<property name="fontPath_hei" value="${fontPath_hei}" />
	</bean>


maven配置: pom.xml 


<!-- 文件下载参数配置开始 -->
<logoPath><![CDATA[F:/conf/download/wxt_dev/templet/img/]]></logoPath>
<fontPath><![CDATA[F:/conf/download/wxt_dev/templet/font/SIMSUN.TTC]]></fontPath>
<fontPath_hei><![CDATA[F:/conf/download/wxt_dev/templet/font/SimHei.ttf]]></fontPath_hei>
				
<!-- 下载文件模板目录 -->
<templateDirPath><![CDATA[F:/conf/download/wxt_dev/templet/]]></templateDirPath>
				
<!-- 下载文件目录 -->
<genTempDirPath><![CDATA[F:/conf/download/wxt_dev/temp/]]></genTempDirPath>
<previewGenFileDir><![CDATA[F:/conf/tomcat/wxt/jsp/temp/preview]]></previewGenFileDir>

<!--模板配置信息-->
<previewTempletDirName>HTMLModel</previewTempletDirName>
<pdfTempletDirName>PDFModel</pdfTempletDirName>
<wordTempletDirName>WordModel</wordTempletDirName>
<excelTempletDirName>ExcelModel</excelTempletDirName>
<wordGenFileDirName>word</wordGenFileDirName>
<qrCodeGenFileDirName>qrCode</qrCodeGenFileDirName>
<snapshotGenFileDirName>snapshot</snapshotGenFileDirName>
<excelGenFileDirName>excel</excelGenFileDirName>
<pdfGenFileDirName>pdf</pdfGenFileDirName>


2.5 模板配置

目录: F:\conf\download\wxt_dev\templet\PDFModel\PDF_GENERATEPDF.ftl

注: ${(model.project_code)!""}中project_code必须是PdfModelVo的属性。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>title</title>
<style>
body {
    PADDING-BOTTOM: 0px;
    LINE-HEIGHT: 14px;
    BACKGROUND-COLOR: #fff;
    MARGIN: 0px;
    PADDING-LEFT: 0px;
    WIDTH: 100%;
    PADDING-RIGHT: 0px;
    FONT-FAMILY: SimSun;
    HEIGHT: 100%;
    COLOR: #000;
    FONT-SIZE: 10px;
    FONT-WEIGHT: 400;
    PADDING-TOP: 0px
}
span{
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    font-size: 100%;
    vertical-align: baseline;
    background: transparent;
    }
.mainbody {
    PADDING-BOTTOM: 10px;
    BACKGROUND-COLOR: #fff;
    PADDING-LEFT: 10px;
    WIDth: 650px;
    PADDING-RIGHT: 10px;
    HEIGHT: 100%;
    MARGIN-LEFT: auto;
    MARGIN-RIGHT: auto;
    PADDING-TOP: 10px
}

.head_top {
    margin-top: 20px;
}
.head_top2{
    margin-top: 80px;
    }
.head_middle {
    margin-top: 250px;
}

.page_one {
    width: 650px;
    line-height: 24px;
    height: 1000px;
}

.page_two {
    line-height: 24px;
    width: 650px;
    height: 900px;
}

.page_three {
    line-height: 24px;
    width: 650px;
    height: 1000px;
}

.two_myhead {
    margin: 0 auto;
    width: 650px;
    text-align: center;
}
.f_size_14 {
    font-size: 14px;
}
.f_size_16 {
    font-size: 16px;
}
.f_size_18 {
    font-size: 18px;
}
.f_size_20 {
    font-size: 20px;
}

.f_size_24 {
    font-size: 24px;
}

.f_size_36 {
    font-size: 36px;
}

.f_size_48 {
    font-size: 48px;
}

.f_size_60 {
    font-size: 60px;
}

.f_bold {
    font-weight: bold;
}

.f_family_song {
   font-family: SimSun;
}

.f_family_hei {
    font-family: SimHei;
}

.f_color_blue {
    color: blue;
}
.f_color_red {
    color: red;
}

.footer {
    TEXT-ALIGN: center; WIDth: 100%; HEIGHT: 100px
}
.fn_fl{
    height:50px;
    float:left;
    }
    /* 清理浮动 */
.fn-clear:after {
    visibility:hidden;
    display:block;
    font-size:0;
    content:" ";
    clear:both;
    height:0;
}
.ui_hr{
    width="100%"
    margin-top:0px;
    border:1px solid #0070C0;
    }
.ui_underline{
    text-decoration:underline;
    }
</style>
</head>

<body>
<div class='mainbody'>
    <div class="page_one">
        <div class="two_myhead">
            <p><span class="f_size_24 f_family_hei f_bold">借 款 合 同</span></p>
        </div>
        <p>
        <span class="f_size_14">合同编号:</span>
        <span class="f_size_14 "> ${(model.project_code)!""} </span>
        </p>
        <p><span class="f_size_14 f_bold">甲方(出借方):</span>
        <span class="f_size_14 "> ${(model.invest_username)!""} </span>  </p>
        <p><span class="f_size_14 f_bold">身份证号:</span><span class="f_size_14 "> ${(model.invest_useridcard)!""} </span></p>
        <p><span class="f_size_14 f_bold">乙方(借款方):</span>
        <span class="f_size_14 "> ${(model.loan_username)!""} </span>  </p>
        <p><span class="f_size_14 f_bold">地    址:</span><span class="f_size_14 "> ${(model.contact_address)!""} </span>  </p>
        <p><span class="f_size_14 f_bold">组织机构代码证:</span><span class="f_size_14 "> ${(model.org_code)!""} </span></p>
        <p><span class="f_size_14 f_bold">法定代表人:</span><span class="f_size_14 ">${(model.legal_username)!""}</span>  </p>
        <p><span class="f_size_14 f_bold f_color_red">甲、乙双方经“信义仓”平台撮合,根据有关法律、法规,在平等、自愿的基础上,经充分协商一致签订</span>
        <span class="f_size_14 f_bold f_color_red">本线上借款合同共同遵守。</span>
        </p>
        <p><span class="f_size_14 f_bold f_family_hei">第一条  借款金额</span></p>
        <p><span class="f_size_14">人民币(大写):</span><span class="f_size_14 ">【 ${(model.loan_big_funds)!""} 】</span><span class="f_size_14">,(小写)¥:</span><span class="f_size_14 ">【 ${(model.loan_funds)!""} 】</span><span class="f_size_14">万元。</span></p>
            <p><span class="f_size_14 f_bold f_family_hei">第二条  借款期限</span></p>
              <p>
              <!--代码压缩片段-->
                <span class="f_size_14">借款期限为</span><span class="f_size_14 ">【 ${(model.repay_order)!""} 】</span><span class="f_size_14">个月,自</span><span class="f_size_14 ">【 ${(model.gmt_start_year)!""} 】</span><span class="f_size_14">年</span><span class="f_size_14 ">【 ${(model.gmt_start_month)!""} 】</span><span class="f_size_14">月</span><span class="f_size_14 ">【 ${(model.gmt_start_day)!""} 】</span><span class="f_size_14">日起至</span><span class="f_size_14 ">【 ${(model.gmt_end_year)!""} 】</span><span class="f_size_14">年</span><span class="f_size_14 ">【 ${(model.gmt_end_month)!""} 】</span><span class="f_size_14">月</span><span class="f_size_14 ">【 ${(model.gmt_end_day)!""} 】</span><span class="f_size_14">日止</span><span class="f_size_14">,</span><span class="f_size_14">用</span><span class="f_size_14">途</span><span class="f_size_14 ">【 ${(model.loan_use_name)!""} 】。</span><span class="f_size_14">实</span><span class="f_size_14">际</span><span class="f_size_14">借</span><span class="f_size_14">款</span><span class="f_size_14">日</span><span class="f_size_14">期</span><span class="f_size_14">与</span><span class="f_size_14">上</span><span class="f_size_14">述</span><span class="f_size_14">约</span><span class="f_size_14">定</span><span class="f_size_14">不</span><span class="f_size_14">一</span><span class="f_size_14">致</span><span class="f_size_14">的</span><span class="f_size_14">,</span><span class="f_size_14">以</span><span class="f_size_14">借</span><span class="f_size_14">款</span><span class="f_size_14">到</span><span class="f_size_14">账</span><span class="f_size_14">日</span><span class="f_size_14">或</span><span class="f_size_14">借</span><span class="f_size_14">款</span><span class="f_size_14">借</span><span class="f_size_14">据</span><span class="f_size_14">为</span><span class="f_size_14">准</span><span class="f_size_14">。</span>
                <!--代码压缩片段-->
            </p>
            <p><span class="f_size_14 f_bold f_family_hei">第三条  借款利率</span></p>
            <p>
                <span class="f_size_14">本合同执行利率为年利率</span>
                <span class="f_size_14 ">【 ${(model.loan_apr)!""} 】</span>
                <span class="f_size_14">%。</span>
            </p>
            <p><span class="f_size_14 f_bold f_family_hei">第四条 还款方式</span></p>
            <p><span class="f_size_14">1、还款和付息方式按以下第【 1 】项</span></p>
            <p>
            <span class="f_size_14">(1)每月的</span>
            <span class="f_size_14 ">【 ${(model.pay_day)!""} 】</span>
             <span class="f_size_14">   日为付息日,最后一个月利息和借款本金至借款期限届满时一次性归还。</span></p>
      <p><span class="f_size_14">(2)到期一次性归还全部本息。</span></p>
            <p><span class="f_size_14">2、乙方在本合同约定的还款、付息日<span class="f_size_14 ">【 24 】</span>时前将相应本金、利息归还给甲方。</span></p>
            <p><span class="f_size_14 f_bold f_family_hei">第五条 乙方的权利和义务</span></p>
            <p><span class="f_size_14">1、向“信义仓”平台提供有关证照、证明和其他材料,并对所提供的材料真实性、合法性负责;</span></p>
            <p><span class="f_size_14">2、保证借款用途真实,严禁用于非法活动;</span></p>
            <p><span class="f_size_14">3、按照约定取得借款本金,按时偿还借款本息及相关费用。</span></p> 
    </div>
    <div class="page_two">
       
    <p><span class="f_size_14 f_bold f_family_hei">第六条 甲方的权利和义务</span></p>
            <p><span class="f_size_14">1、有权对乙方在“信义仓”平台上提供的信息进行查询和核实;</span></p>
            <p><span class="f_size_14">2、按照本协议约定发放借款及按期收回本金、利息。</span></p>
            <p><span class="f_size_14 f_bold f_family_hei">第七条 担保</span></p>
      <p>
                <span class="f_size_14"> 1、本合同项下的借款本息及其他一切相关费用由</span>
                <span class="f_size_14 ">【   】</span>
<span class="f_size_14">(</span><span class="f_size_14">保</span><span class="f_size_14">证</span><span class="f_size_14">人</span><span class="f_size_14">)</span><span class="f_size_14">提</span><span class="f_size_14">供</span><span class="f_size_14">连</span><span class="f_size_14">带</span><span class="f_size_14">责</span><span class="f_size_14">任</span><span class="f_size_14">担</span><span class="f_size_14">保</span><span class="f_size_14">,</span><span class="f_size_14">该</span><span class="f_size_14">保</span><span class="f_size_14">证</span><span class="f_size_14">人</span><span class="f_size_14">另</span><span class="f_size_14">行</span><span class="f_size_14">出</span><span class="f_size_14">具</span><span class="f_size_14">《</span><span class="f_size_14">担</span><span class="f_size_14">保</span><span class="f_size_14">函</span><span class="f_size_14">》</span><span class="f_size_14">。</span>
            </p>
            <p>
             <!--代码压缩片段-->
                <span class="f_size_14">2、本合同项下的借款本息及其他一切相关费用由</span><span class="f_size_14 ">【   】</span><span class="f_size_14">(</span><span class="f_size_14">出</span><span class="f_size_14">质</span><span class="f_size_14">人</span><span class="f_size_14">)</span><span class="f_size_14">以</span><span class="f_size_14">其</span><span class="f_size_14">所</span><span class="f_size_14">有</span><span class="f_size_14">或</span><span class="f_size_14">依</span><span class="f_size_14">法</span><span class="f_size_14">有</span><span class="f_size_14">权</span><span class="f_size_14">处</span><span class="f_size_14">分</span><span class="f_size_14">的</span><span class="f_size_14 ">【 ${(model.assure_goods)!""} 】</span><span class="f_size_14">作</span><span class="f_size_14">质</span><span class="f_size_14">押</span><span class="f_size_14">,</span><span class="f_size_14">出</span><span class="f_size_14">质</span><span class="f_size_14">人</span><span class="f_size_14">另</span><span class="f_size_14">行</span><span class="f_size_14">出</span><span class="f_size_14">具</span><span class="f_size_14">《</span><span class="f_size_14">质</span><span class="f_size_14">押</span><span class="f_size_14">担</span><span class="f_size_14">保</span><span class="f_size_14">函</span><span class="f_size_14">》</span><span class="f_size_14">或</span><span class="f_size_14">签</span><span class="f_size_14">订</span><span class="f_size_14">《</span><span class="f_size_14">质</span><span class="f_size_14">押</span><span class="f_size_14">合</span><span class="f_size_14">同</span><span class="f_size_14">》</span><span class="f_size_14">。</span>
             <!--代码压缩片段-->
            </p>
            <p>
                <span class="f_size_14">3、其他担保方式:</span>
                <span class="f_size_14 ">【 ${(model.assure_type_name)!""} 】</span>
            </p>
            <p><span class="f_size_14">4、担保范围为本合同项下的借款本金、利息、逾期利息、违约金以及实现债权的所有费用。</span></p>
            <p><span class="f_size_14 f_bold f_family_hei">第八条 违约责任</span></p>
            <p><span class="f_size_14">乙方未能按本合同约定足额偿还借款本息的,每日另行按未清偿本金部分万分之五支付违约金。</span></p>
           
            <p><span class="f_size_14 f_bold f_family_hei">第九条  合同成立及生效</span></p>
            
            <p><span class="f_size_14 ">甲方在“信义仓”平台网站或手机APP本协议网页点击“同意”,本合同成立。
    </span></p>
      <p><span class="f_size_14 ">甲方借款资金进入乙方指定账户后本合同生效,一经生效即不可撤销。
    </span></p>
            <p><span class="f_size_14 f_bold f_family_hei">第十条 <strong>争议解决</strong></span>                    </p>
            <p>
              <span class="f_size_14">凡由本合同引起的或与本合同有关的一切争议和纠纷,各方应当协商解决;若协商不成,应向杭州市江干</span>
              <span class="f_size_14">区人民法院提起诉讼。</span>
              </p>
            <p><span class="f_size_14 f_bold f_family_hei">第十一条  其他</span></p>
            <p>
            <span class="f_size_14">各方同意本合同利用互联网信息技术以数据电文形式订立并认同其效力。各方均承诺遵守国家信息安全等</span>
            <span class="f_size_14">级保护的相关规定和标准,遵守国家互联网技术规范和安全规范。本合同线下汇总,形成的书面合同后与</span>
            <span class="f_size_14">互联网上订立的合同具有同等法律效力。</span>
            </p>
    
    </div>        
</div>
</body>
</html>

效果图展示:










<think>我们有一个需求:在Java中导出文件生成zip压缩包。根据提供的引用内容,我们可以提取关键信息:1.引用[1]展示了如何将单个文件压缩为zip的方法,使用`ZipOutputStream`。2.引用[2]提到创建加密压缩包的步骤(但用户没有要求加密,所以暂时不考虑加密)。3.引用[3]提到了使用组合模式实现压缩,但用户需要的是具体实现。4.引用[4]展示了在HTTP响应头中设置下载zip文件。5.引用[5]提到了导出数据到Excel生成ZIP文件的流程。用户的需求是导出文件生成zip压缩包。这里假设我们有两个步骤:1.生成或获取要压缩的文件(可能是多个文件)。2.将这些文件打包成zip提供下载(或保存到服务器)。由于引用中已经给出了部分代码,我们将结合这些内容,提供一个完整的示例。示例包括:-导出多个文件(例如:生成一些临时文件)。-将这些文件压缩成一个zip文件。-如果是在Web环境中,还需要将zip文件发送给用户下载。注意:用户没有明确是Web环境还是桌面环境,但我们从引用[4][5]中可以看出是Web环境(下载)。因此,我们将以Web环境为例,但也会给出保存本地的代码。步骤:1.创建临时文件(模拟导出的文件,比如文本文件、Excel文件等)。2.创建一个zip输出流,将多个文件写入zip。3.在Web应用中,设置HTTP响应头以下载zip文件。示例代码将分为两部分:A.生成多个文件压缩到zip文件(服务端保存或准备输出流)。B.在Web应用中,将生成的zip文件发送给客户端。由于完整代码较长,我们将分步骤展示关键代码。注意:在实际开发中,我们可能需要处理异常、资源关闭以及临时文件的清理。示例:```javaimportjava.io.*;importjava.util.List;importjava.util.ArrayList;importjava.util.zip.*;publicclassZipUtil{//压缩多个文件到一个zip文件保存到服务器指定路径)publicstaticvoidzipFiles(List<File>srcFiles,StringzipFilePath)throwsIOException{//创建输出流try(ZipOutputStreamzos=newZipOutputStream(newFileOutputStream(zipFilePath))){for(FilesrcFile:srcFiles){addToZip(zos,srcFile,"");}}}//递归添加文件夹下的文件(这里简化,只处理文件)privatestaticvoidaddToZip(ZipOutputStreamzos,Filefile,StringbasePath)throwsIOException{StringentryName=basePath+file.getName();if(file.isDirectory()){//如果是目录,则遍历里面的文件for(FilesubFile:file.listFiles()){addToZip(zos,subFile,entryName+"/");}}else{//是文件,则添加到zipbyte[]buffer=newbyte[1024];try(FileInputStreamfis=newFileInputStream(file);BufferedInputStreambis=newBufferedInputStream(fis)){ZipEntryzipEntry=newZipEntry(entryName);zos.putNextEntry(zipEntry);intlength;while((length=bis.read(buffer))>0){zos.write(buffer,0,length);}zos.closeEntry();}}}//在Web环境中,我们通常不会先保存文件,而是直接输出到响应流(避免磁盘IO)//此方法将多个文件直接输出到输出流(zip格式),设置响应头以下载publicstaticvoidzipAndDownload(List<File>srcFiles,HttpServletResponseresponse,StringzipFileName)throwsIOException{response.setContentType("application/zip");response.setHeader("Content-Disposition","attachment;filename="+zipFileName);try(ZipOutputStreamzos=newZipOutputStream(response.getOutputStream())){for(Filefile:srcFiles){addToZip(zos,file,"");}}}}```在Web控制器中,我们可以这样使用:```java@ControllerpublicclassDownloadController{@GetMapping("/downloadFiles")publicvoiddownloadFiles(HttpServletResponseresponse)throwsIOException{//1.生成要导出的文件(这里假设生成了两个临时文件)List<File>filesToZip=newArrayList<>();//创建临时文件1FiletempFile1=File.createTempFile("file1",".txt");//写入一些内容Files.write(tempFile1.toPath(),"Hello,World!".getBytes());filesToZip.add(tempFile1);//创建临时文件2FiletempFile2=File.createTempFile("file2",".txt");Files.write(tempFile2.toPath(),"Anotherfilecontent".getBytes());filesToZip.add(tempFile2);//2.调用工具方法进行压缩下载ZipUtil.zipAndDownload(filesToZip,response,"myfiles.zip");//3.注意:临时文件可以在这里删除,或者在程序退出时删除。但要注意在流关闭后再删除。//但是,由于我们是在方法内部生成临时文件且下载后需要删除,可以在下载完成后删除。//这里要注意,因为zipAndDownload已经将文件写入响应流,所以可以在循环后删除。for(Filefile:filesToZip){file.delete();}}}```注意:-上述代码中,`zipAndDownload`方法直接操作`HttpServletResponse`,这样避免在服务器上存储zip文件。-临时文件在下载后立即删除,避免占用空间。如果用户只需要将文件保存到服务器,则调用`zipFiles`方法。改进点:1.在实际应用中,生成临时文件可能不是最佳方式,特别是大文件时。可以考虑直接生成到内存(如果文件不大)或者使用管道流。2.如果文件很大,应该使用缓冲流,注意内存使用。3.对于文件夹的处理,上面代码提供了递归添加,但测试时注意。如果文件很大,我们可能不能全部放在内存中,上面的代码已经使用了缓冲流,且每次读取1024字节。以上是一个完整的示例,涵盖了生成多个文件、压缩成zip下载的整个过程。相关问题:1.如何在Java中生成临时文件?2.如何将多个文件压缩到zip而不保存到磁盘(直接发送给客户端)?3.如何处理大文件压缩以避免内存溢出?4.如何设置HTTP响应头以下载文件?</think> ### Java导出文件生成ZIP压缩包实现详解 以下是完整的Java实现方案,包含文件导出、ZIP压缩及下载功能: #### 核心方法实现 ```java import java.io.*; import java.util.List; import java.util.zip.*; public class ZipExportUtils { private static final int BUFFER_SIZE = 8192; // 缓冲区大小 /** * 将多个文件压缩为ZIP包(保存本地) * @param filePaths 源文件路径列表 * @param zipPath 生成的ZIP文件路径 */ public static void createZip(List<String> filePaths, String zipPath) { try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) { for (String filePath : filePaths) { addFileToZip(zos, new File(filePath)); } System.out.println("ZIP创建成功:" + zipPath); } catch (IOException e) { throw new RuntimeException("创建ZIP失败", e); } } /** * 添加单个文件到ZIP包 */ private static void addFileToZip(ZipOutputStream zos, File file) throws IOException { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) { ZipEntry zipEntry = new ZipEntry(file.getName()); zos.putNextEntry(zipEntry); byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = bis.read(buffer)) != -1) { zos.write(buffer, 0, bytesRead); } zos.closeEntry(); } } } ``` #### Web环境下下载ZIP文件(Spring Boot示例) ```java import org.springframework.http.HttpHeaders; import javax.servlet.http.HttpServletResponse; import java.util.List; @RestController public class ExportController { @GetMapping("/download/zip") public void downloadZip(HttpServletResponse response) { // 1. 准备要压缩的文件 List<String> filePaths = List.of("/temp/report1.xlsx", "/temp/report2.pdf"); // 2. 生成临时ZIP文件路径 String zipPath = "/temp/export_" + System.currentTimeMillis() + ".zip"; try { // 3. 创建ZIP压缩包 ZipExportUtils.createZip(filePaths, zipPath); // 4. 设置响应头 response.setContentType("application/zip"); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"export_files.zip\""); // 解决中文乱码问题 // 5. 流式传输文件 try (InputStream is = new FileInputStream(zipPath); OutputStream os = response.getOutputStream()) { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } os.flush(); } } catch (Exception e) { throw new RuntimeException("文件下载失败", e); } finally { // 6. 清理临时文件(可选) new File(zipPath).delete(); } } } ``` #### 实现说明 1. **核心流程**: ```mermaid graph TD A[准备要压缩的文件] --> B[创建ZipOutputStream] B --> C{遍历文件列表} C --> D[添加ZipEntry] D --> E[写入文件数据] E --> C C -->|完成| F[关闭资源] F --> G[返回ZIP文件] ``` 2. **关键特性**: - **缓冲区机制**:使用`8192`字节缓冲区提升I/O性能 - **资源管理**:使用`try-with-resources`确保资源关闭 - **内存优化**:流式处理避免大文件内存溢出 - **临时文件清理**:下载后自动删除服务端临时文件 3. **HTTP响应头要点**: ```java response.setContentType("application/zip"); response.setHeader("Content-Disposition", "attachment; filename=\"导出文件.zip\""); // 中文文件名需额外编码处理: String encodedName = URLEncoder.encode("中文名称.zip", StandardCharsets.UTF_8); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName); ``` #### 进阶功能扩展 1. **加密压缩**: ```java // 添加密码保护 zos.setPassword("secret123".toCharArray()); zos.setMethod(ZipOutputStream.DEFLATED); zos.setLevel(Deflater.BEST_COMPRESSION); ``` 2. **内存中直接生成ZIP(避免临时文件)**: ```java public void downloadZipDirect(HttpServletResponse response) throws IOException { try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) { response.setContentType("application/zip"); // 动态生成文件内容直接写入ZIP ZipEntry entry = new ZipEntry("dynamic.txt"); zos.putNextEntry(entry); zos.write("动态生成的内容".getBytes()); zos.closeEntry(); } } ``` 3. **添加目录结构**: ```java // 在文件名前添加目录路径 ZipEntry entry = new ZipEntry("reports/2023/" + file.getName()); ``` [^1]: 文件压缩的核心实现参考 [^2]: ZIP流式处理机制 [^3]: HTTP下载响应头设置规范 [^4]: Spring文件下载最佳实践 [^5]: Java临时文件管理方案 --- ### 相关问题 1. 如何解决ZIP下载时中文文件名乱码问题? 2. 当需要压缩大量文件时(如1000+),如何优化内存使用? 3. 怎样在生成ZIP文件后自动通过邮件发送? 4. 如何为ZIP文件添加分卷压缩功能(拆分为多个文件)? 5. 在分布式环境中,如何实现多服务器文件的集中压缩?
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值