1.本文使用工具类为Jacob 来操作word文档, 优点是功能强大, 直接操作word, 方便控制样式,缺点是配置复杂,只能用在windows平台,需要电脑上有wps或office
2.首先下载Jacob压缩包,将其中的 jacob-1.17-M2-x64.dll 文件放在 %JAVA_HOME%/jre/bin目录下 ,win7放在System32 目录下。(如果win7是32位系统,则放在 System64目录下,有点诡异)
3.在项目的resource目录下新建lib文件夹,将Jacob.jar 放在lib目录下
4.引入pom依赖
<dependency>
<groupId>com.jacob</groupId>
<artifactId>jacob</artifactId>
<version>1.17</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/jacob.jar</systemPath>
</dependency>
5.打开要操作的word,其中要填充的数据位使用占位符填充,格式为 {{变量名}},此处变量名需要与java中相应的变量名一致
6.在数据库中取出想要的数据,创建一个相对应的map
/**
* 生成收据
*/
@GetMapping("/contract")
public AjaxResult Contract() {
String fileName = DateUtils.timechuo() + ".docx"; //根据模板生成的文件名
String templateFilePath = null;
String printerName = null; //打印机的名字,也可以不指定
//从数据库中查询订单信息
/通过你自己的service在数据库中查询想要的数据
for (Object o : jsonArray) { //如果是多条数据 使用循环遍历 根据业务进行修改
JSONObject ob = (JSONObject) o;
String houseid = ob.getString("houseid");
String amount = ob.getString("shouldamount");
String outtradeno = ob.getString("outtradeno");
String houseNo = getHouseNo(houseid);
//创建一个map 将数据库中的数据写进去
Map<String,String> map = new HashMap<>();
//map的键必须与word中的占位符一致, 如word中{{houseid}}则map键名为 "houseid"
map.put("houseid",houseid);
map.put("Amount",amountUp);
map.put("outtradeno",outtradeno);
String path1 = "D:/模板.docx"; //模板word路径
String outFilePath = "D:/" + fileName; //生成的word文件输出路径
templateFilePath = path1; //模板word路径
//调用接口生成收据
try {
//可以指定打印机
// insertAndOutFile2(templateFilePath,outFilePath,map,printerName);
//不指定打印机会选择默认打印机)
insertAndOutFile2(templateFilePath,outFilePath,map);
//修改打印状态
ob.put("status",1);
//这里调用你自己的service修改状态就可以了
}catch (Exception e){
System.out.println(e.getMessage());
}
}
return AjaxResult.success();
}
/**
* 生成一个新的收据
* @param templateFilePath word模板文件路径
* @param outFilePath 填充后输出文件路径
* @param map key:word中的占位标签,value对应标签要替换的值。
* @throws IOException
*/
public void insertAndOutFile2(String templateFilePath, String outFilePath, Map<String,String> map, String printerName) throws Exception {
// Map<String,Object> data = new HashMap<String, Object>();
// data.put("title", "Poi-tl 模板引擎");//添加数据,键是 模板中的{{title}},值在渲染的时候会替换掉对应的标签
XWPFTemplate template = XWPFTemplate.compile(templateFilePath).render(map); //编译模板,把数据塞入模板中,找到对应标签替换
FileOutputStream out = new FileOutputStream(outFilePath);//新建导出文件
template.write(out); //输出到流
out.flush();
out.close();
template.close();
PrintWordUtiil.printWord(outFilePath,printerName);
}
//重载 不需要传打印机名字的方法
public void insertAndOutFile2(String templateFilePath, String outFilePath, Map<String,String> map) throws Exception {
// Map<String,Object> data = new HashMap<String, Object>();
// data.put("title", "Poi-tl 模板引擎");//添加数据,键是 模板中的{{title}},值在渲染的时候会替换掉对应的标签
XWPFTemplate template = XWPFTemplate.compile(templateFilePath).render(map); //编译模板,把数据塞入模板中,找到对应标签替换
FileOutputStream out = new FileOutputStream(outFilePath);//新建导出文件
template.write(out); //输出到流
out.flush();
out.close();
template.close();
PrintWordUtiil.printWord(outFilePath);
}
//下边两个方法是生成文件夹和命名的 可用可不用
/**
* 以当前日期为名,创建新文件夹
*
* @return
*/
private static String createNewDir() {
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
return fmt.format(new Date());
}
/**
* 为文件重新命名,命名规则为当前系统时间毫秒数
*
* @return string
*/
private static String getFileNameNew() {
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmssSSS");
return fmt.format(new Date());
}
7.打印工具类,核心,需要打印的文件只需要调用 PrintWordUtil.printWord()方法,传入相应参数就可以了
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.standard.Sides;
import java.awt.print.*;
import java.io.File;
import java.io.IOException;
public class PrintWordUtiil {
//这个方法是需要传打印机名字的(即指定打印机) 下边有个重载的方法不需要传打印机名字
public static void printWord(String filePath,String printerName) throws PrinterException {
// 初始化线程
ComThread.InitSTA();
ActiveXComponent word = new ActiveXComponent("Word.Application");
//设置打印机名称
if (printerName == null && printerName == ""){
//如果打印机的名字为空,则默认机器首个打印机
// 创建一个PrinterJob对象
PrinterJob printerJob = PrinterJob.getPrinterJob();
// 设置打印机
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
printerJob.setPrintService(printService);
printerName = printService.getName();
System.out.println("发现的打印机名名称为:"+printerName);
}
word.setProperty("ActivePrinter", new Variant(printerName));
// 这里Visible是控制文档打开后是可见还是不可见,若是静默打印,那么第三个参数就设为false就好了
Dispatch.put(word, "Visible", new Variant(false));
// 获取文档属性
Dispatch document = word.getProperty("Documents").toDispatch();
// 打开激活文挡
Dispatch doc=Dispatch.call(document, "Open", filePath).toDispatch();
//Dispatch doc = Dispatch.invoke(document, "Open", Dispatch.Method,
// new Object[] { filePath }, new int[1]).toDispatch();
try{
Dispatch.callN(doc, "PrintOut");
System.out.println("打印成功!");
}catch (Exception e){
e.printStackTrace();
System.out.println("打印失败");
}finally {
try {
if (doc != null) {
Dispatch.call(doc, "Close", new Variant(0));//word文档关闭
}
} catch (Exception e2) {
e2.printStackTrace();
}
//退出
word.invoke("Quit", new Variant[0]);
//释放资源
ComThread.Release();
ComThread.quitMainSTA();
}
}
public static void printWord(String filePath) throws PrinterException {
// 初始化线程
ComThread.InitSTA();
ActiveXComponent word = new ActiveXComponent("Word.Application");
//设置打印机名称
PrinterJob printerJob = PrinterJob.getPrinterJob();
// 设置打印机
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
printerJob.setPrintService(printService);
String printerName = printService.getName();
System.out.println("发现的打印机名名称为:"+printerName);
printWord(filePath,printerName);
}
}