当前位置:   article > 正文

Java PDF电子发票批量识别信息保存导出excel(亲测已上线使用)_java 实现生成电子发票生成与下载

java 实现生成电子发票生成与下载

发票原图:

首先在系统中根据库表生成一套自己的entity、dao、service、controller、html等一套代码,下面以我自己创建的为例:

Invoiceinfo.java

  1. /**
  2. * Copyright &copy; 2012-2016 <a href="https://github.com/thinkgem/jeesite">JeeSite</a> All rights reserved.
  3. */
  4. package com.thinkgem.jeesite.modules.basis.entity;
  5. import org.hibernate.validator.constraints.Length;
  6. import java.math.BigDecimal;
  7. import java.util.Date;
  8. import java.util.List;
  9. import com.fasterxml.jackson.annotation.JsonFormat;
  10. import com.thinkgem.jeesite.common.persistence.DataEntity;
  11. /**
  12. * 发票信息Entity
  13. * @author hsg
  14. * @version 2024-05-07
  15. */
  16. public class Invoiceinfo extends DataEntity<Invoiceinfo> {
  17. private static final long serialVersionUID = 1L;
  18. private String preparedBy; // 经办人
  19. private String invoiceCode; // 发票代码
  20. private String invoiceNumber; // 发票号码
  21. private String content; // 项目名称
  22. private String company; // 开票公司
  23. private Date invoiceDate; // 开票日期
  24. private Date invoiceEndDate; // 开票结束日期
  25. private Date getDate; // 取得日期
  26. private Date getEndDate; // 取得结束日期
  27. private BigDecimal notaxinclusiveAmount; // 金额
  28. private BigDecimal taxAmount; // 税额
  29. private BigDecimal taxinclusiveAmount; // 价税合计
  30. private String inReserve1; // 上传人
  31. private String inReserve2; // 发票类别 专票/普票
  32. private String inReserve3; // 备用3
  33. private String inReserve4; // 备用4
  34. private String type; //发票种类
  35. private String pzh; //凭证号
  36. private String remakes; //备注
  37. private Date rzDate; //入账日期
  38. public Invoiceinfo() {
  39. super();
  40. }
  41. public Invoiceinfo(String id){
  42. super(id);
  43. }
  44. public Date getRzDate() {
  45. return rzDate;
  46. }
  47. public void setRzDate(Date rzDate) {
  48. this.rzDate = rzDate;
  49. }
  50. public String getPzh() {
  51. return pzh;
  52. }
  53. public void setPzh(String pzh) {
  54. this.pzh = pzh;
  55. }
  56. public String getRemakes() {
  57. return remakes;
  58. }
  59. public void setRemakes(String remakes) {
  60. this.remakes = remakes;
  61. }
  62. public String getType() {
  63. return type;
  64. }
  65. public void setType(String type) {
  66. this.type = type;
  67. }
  68. @Length(min=0, max=100, message="经办人长度必须介于 0 和 100 之间")
  69. public String getPreparedBy() {
  70. return preparedBy;
  71. }
  72. public void setPreparedBy(String preparedBy) {
  73. this.preparedBy = preparedBy;
  74. }
  75. @Length(min=0, max=100, message="发票代码长度必须介于 0 和 100 之间")
  76. public String getInvoiceCode() {
  77. return invoiceCode;
  78. }
  79. public void setInvoiceCode(String invoiceCode) {
  80. this.invoiceCode = invoiceCode;
  81. }
  82. @Length(min=0, max=100, message="发票号码长度必须介于 0 和 100 之间")
  83. public String getInvoiceNumber() {
  84. return invoiceNumber;
  85. }
  86. public void setInvoiceNumber(String invoiceNumber) {
  87. this.invoiceNumber = invoiceNumber;
  88. }
  89. @Length(min=0, max=500, message="开票内容长度必须介于 0 和 500 之间")
  90. public String getContent() {
  91. return content;
  92. }
  93. public void setContent(String content) {
  94. this.content = content;
  95. }
  96. @Length(min=0, max=100, message="开票公司长度必须介于 0 和 100 之间")
  97. public String getCompany() {
  98. return company;
  99. }
  100. public void setCompany(String company) {
  101. this.company = company;
  102. }
  103. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  104. public Date getInvoiceDate() {
  105. return invoiceDate;
  106. }
  107. public void setInvoiceDate(Date invoiceDate) {
  108. this.invoiceDate = invoiceDate;
  109. }
  110. @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  111. public Date getGetDate() {
  112. return getDate;
  113. }
  114. public void setGetDate(Date getDate) {
  115. this.getDate = getDate;
  116. }
  117. public BigDecimal getNotaxinclusiveAmount() {
  118. return notaxinclusiveAmount;
  119. }
  120. public void setNotaxinclusiveAmount(BigDecimal notaxinclusiveAmount) {
  121. this.notaxinclusiveAmount = notaxinclusiveAmount;
  122. }
  123. public BigDecimal getTaxAmount() {
  124. return taxAmount;
  125. }
  126. public void setTaxAmount(BigDecimal taxAmount) {
  127. this.taxAmount = taxAmount;
  128. }
  129. public BigDecimal getTaxinclusiveAmount() {
  130. return taxinclusiveAmount;
  131. }
  132. public void setTaxinclusiveAmount(BigDecimal taxinclusiveAmount) {
  133. this.taxinclusiveAmount = taxinclusiveAmount;
  134. }
  135. @Length(min=0, max=100, message="备用1长度必须介于 0 和 100 之间")
  136. public String getInReserve1() {
  137. return inReserve1;
  138. }
  139. public void setInReserve1(String inReserve1) {
  140. this.inReserve1 = inReserve1;
  141. }
  142. @Length(min=0, max=100, message="备用2长度必须介于 0 和 100 之间")
  143. public String getInReserve2() {
  144. return inReserve2;
  145. }
  146. public void setInReserve2(String inReserve2) {
  147. this.inReserve2 = inReserve2;
  148. }
  149. @Length(min=0, max=100, message="备用3长度必须介于 0 和 100 之间")
  150. public String getInReserve3() {
  151. return inReserve3;
  152. }
  153. public void setInReserve3(String inReserve3) {
  154. this.inReserve3 = inReserve3;
  155. }
  156. @Length(min=0, max=100, message="备用4长度必须介于 0 和 100 之间")
  157. public String getInReserve4() {
  158. return inReserve4;
  159. }
  160. public void setInReserve4(String inReserve4) {
  161. this.inReserve4 = inReserve4;
  162. }
  163. public Date getInvoiceEndDate() {
  164. return invoiceEndDate;
  165. }
  166. public void setInvoiceEndDate(Date invoiceEndDate) {
  167. this.invoiceEndDate = invoiceEndDate;
  168. }
  169. public Date getGetEndDate() {
  170. return getEndDate;
  171. }
  172. public void setGetEndDate(Date getEndDate) {
  173. this.getEndDate = getEndDate;
  174. }
  175. }

前端调用:

controller调用service:

  1. private static final String UPLOAD_DIR = "D:\\Program Files\\发票票据\\";
  2. @RequiresPermissions("basis:invoiceinfo:edit")
  3. @RequestMapping(value = "invoiceInput")
  4. public String invoiceinfoInput(Invoiceinfo invoiceinfo, @RequestParam("ListFile") MultipartFile[] ListFile, RedirectAttributes redirectAttributes,HttpServletRequest request,Model model){
  5. if (ListFile.length == 0) {
  6. addMessage(redirectAttributes, "上传失败!失败信息:请选择要上传的文件!");
  7. return "redirect:"+Global.getAdminPath()+"/basis/invoiceinfo/?repage";
  8. }
  9. String userName = UserUtils.getUser().getLoginName();
  10. String success = invoiceinfoService.inputInvoice(userName, ListFile, UPLOAD_DIR);
  11. addMessage(redirectAttributes, success);
  12. return "redirect:"+Global.getAdminPath()+"/basis/invoiceinfo/?repage";
  13. }

service实现方法:

调用方法参考如图文件

  1. @Transactional(readOnly = false)
  2. public String inputInvoice(String userName, MultipartFile[] ListFile, String UPLOAD_DIR) {
  3. List<Invoiceinfo> infoList = new ArrayList<Invoiceinfo>();
  4. String success = "导入数据成功!";
  5. String dateFormat = "yyyy-MM-dd";
  6. SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
  7. for (MultipartFile file : ListFile) {
  8. if (file.isEmpty()) {
  9. continue;
  10. }
  11. String fileName = file.getOriginalFilename();
  12. try {
  13. if(fileName.endsWith("pdf")) {
  14. Invoiceinfo invoiceinfo = new Invoiceinfo();
  15. File uploadDir = new File(UPLOAD_DIR + userName +"/");
  16. if (!uploadDir.exists()) {
  17. uploadDir.mkdir();
  18. }
  19. // 构造文件保存路径(文件名使用原始文件名,防止重名可以添加UUID等)
  20. Path targetLocation = Paths.get(UPLOAD_DIR + userName + "/" + fileName);
  21. // 保存文件
  22. Files.write(targetLocation, file.getBytes());
  23. NewInvoice newInvoice = NewInvoiceExtractor.newPdfProcessInvoicesInFile(targetLocation.toAbsolutePath().toString());
  24. if(StringUtils.isNotBlank(newInvoice.getNumber())) {//新版发票
  25. invoiceinfo.setInvoiceNumber(newInvoice.getNumber());
  26. List<Invoiceinfo> list = findList1(invoiceinfo);
  27. if(list.size() > 0) {
  28. success = "导入数据失败!系统已存在"+fileName+"编号的发票!";
  29. }else {
  30. int index = fileName.indexOf("-");
  31. invoiceinfo.setPreparedBy(fileName.substring(0, index));
  32. invoiceinfo.setContent(newInvoice.getContent());
  33. invoiceinfo.setCompany(newInvoice.getSellerName());
  34. invoiceinfo.setInvoiceDate(sdf.parse(newInvoice.getDate()));
  35. invoiceinfo.setNotaxinclusiveAmount(newInvoice.getAmount());
  36. invoiceinfo.setTaxAmount(newInvoice.getTaxAmount());
  37. invoiceinfo.setTaxinclusiveAmount(newInvoice.getTotalAmount());
  38. invoiceinfo.setGetDate(new Date());
  39. invoiceinfo.setInReserve1(userName);
  40. invoiceinfo.setInReserve2(newInvoice.getInReserve2());
  41. invoiceinfo.setInReserve3(targetLocation.toString());
  42. invoiceinfo.setType("数电发票");
  43. infoList.add(invoiceinfo);
  44. }
  45. }else {//老版发票
  46. Invoice invoice = InvoiceExtractor.newPdfProcessInvoicesInFile(targetLocation.toAbsolutePath().toString());
  47. invoiceinfo.setInvoiceNumber(invoice.getNumber());
  48. List<Invoiceinfo> list = findList1(invoiceinfo);
  49. if(list.size() > 0) {
  50. success = "导入数据失败!系统已存在"+fileName+"编号的发票!";
  51. }else {
  52. int index = fileName.indexOf("-");
  53. invoiceinfo.setPreparedBy(fileName.substring(0, index));
  54. invoiceinfo.setInvoiceCode(invoice.getCode());
  55. invoiceinfo.setContent(invoice.getContent());
  56. invoiceinfo.setCompany(invoice.getSellerName());
  57. invoiceinfo.setInvoiceDate(sdf.parse(invoice.getDate()));
  58. invoiceinfo.setNotaxinclusiveAmount(invoice.getAmount());
  59. invoiceinfo.setTaxAmount(invoice.getTaxAmount());
  60. invoiceinfo.setTaxinclusiveAmount(invoice.getTotalAmount());
  61. invoiceinfo.setInvoiceNumber(invoice.getNumber());
  62. invoiceinfo.setGetDate(new Date());
  63. invoiceinfo.setInReserve1(userName);
  64. invoiceinfo.setInReserve2(invoice.getInReserve2());
  65. invoiceinfo.setInReserve3(targetLocation.toString());
  66. invoiceinfo.setType("电子发票");
  67. infoList.add(invoiceinfo);
  68. }
  69. }
  70. }
  71. }catch (Exception e) {
  72. success = "导入数据失败!失败信息:"+e.getMessage();
  73. e.printStackTrace();
  74. }
  75. }
  76. if(success.equals("导入数据成功!")) {
  77. saveInfoList(infoList);
  78. }
  79. return success;
  80. }
  81. private void saveInfoList(List<Invoiceinfo> infoList) {
  82. for(Invoiceinfo invoiceinfo : infoList)
  83. save(invoiceinfo);
  84. }

************以下代码可识别新版和老版的专票、普票************

Detail.java

  1. package com.thinkgem.jeesite.modules.pdfServices.entity;
  2. import java.math.BigDecimal;
  3. /**
  4. * @author b16mt
  5. * @version v1.0
  6. */
  7. public class Detail {
  8. /**
  9. * 商品名称
  10. */
  11. private String name;
  12. /**
  13. * 商品规格型号
  14. */
  15. private String model;
  16. /**
  17. * 商品单位
  18. */
  19. private String unit;
  20. /**
  21. * 商品数量
  22. */
  23. private BigDecimal count;
  24. /**
  25. * 商品单价
  26. */
  27. private BigDecimal price;
  28. /**
  29. * 商品总金额
  30. */
  31. private BigDecimal amount;
  32. /**
  33. * 商品税率
  34. */
  35. private BigDecimal taxRate;
  36. /**
  37. * 商品税额
  38. */
  39. private BigDecimal taxAmount;
  40. public String getName() {
  41. return name;
  42. }
  43. public void setName(String name) {
  44. this.name = name;
  45. }
  46. public String getModel() {
  47. return model;
  48. }
  49. public void setModel(String model) {
  50. this.model = model;
  51. }
  52. public String getUnit() {
  53. return unit;
  54. }
  55. public void setUnit(String unit) {
  56. this.unit = unit;
  57. }
  58. public BigDecimal getCount() {
  59. return count;
  60. }
  61. public void setCount(BigDecimal count) {
  62. this.count = count;
  63. }
  64. public BigDecimal getPrice() {
  65. return price;
  66. }
  67. public void setPrice(BigDecimal price) {
  68. this.price = price;
  69. }
  70. public BigDecimal getAmount() {
  71. return amount;
  72. }
  73. public void setAmount(BigDecimal amount) {
  74. this.amount = amount;
  75. }
  76. public BigDecimal getTaxRate() {
  77. return taxRate;
  78. }
  79. public void setTaxRate(BigDecimal taxRate) {
  80. this.taxRate = taxRate;
  81. }
  82. public BigDecimal getTaxAmount() {
  83. return taxAmount;
  84. }
  85. public void setTaxAmount(BigDecimal taxAmount) {
  86. this.taxAmount = taxAmount;
  87. }
  88. }

----------------------------------------------------------------

Invoice.java

  1. package com.thinkgem.jeesite.modules.pdfServices.entity;
  2. import java.math.BigDecimal;
  3. import java.util.List;
  4.  
  5.  
  6. public class Invoice {
  7.  
  8.     /**
  9.      * 文件绝对路径
  10.      */
  11.     private String fileAbsolutePath;
  12.  
  13.     /**
  14.      * 发票标题
  15.      */
  16.     private String title;
  17.  
  18.     /**
  19.      * 机器编号
  20.      */
  21.     private String machineNumber;
  22.  
  23.     /**
  24.      * 发票代码
  25.      */
  26.     private String code;
  27.  
  28.     /**
  29.      * 发票号码
  30.      */
  31.     private String number;
  32.  
  33.     /**
  34.      * 开票日期
  35.      */
  36.     private String date;
  37.  
  38.     /**
  39.      * 校验码
  40.      */
  41.     private String checksum;
  42.  
  43.     /**
  44.      * 购买方名称
  45.      */
  46.     private String buyerName;
  47.  
  48.     /**
  49.      * 购买方纳税人识别号
  50.      */
  51.     private String buyerCode;
  52.  
  53.     /**
  54.      * 购买方地址
  55.      */
  56.     private String buyerAddress;
  57.  
  58.     /**
  59.      * 购买方银行账号
  60.      */
  61.     private String buyerAccount;
  62.  
  63.     /**
  64.      * 密码区
  65.      */
  66.     private String password;
  67.  
  68.     /**
  69.      * 合计金额
  70.      */
  71.     private BigDecimal amount;
  72.  
  73.     /**
  74.      * 合计税额
  75.      */
  76.     private BigDecimal taxAmount;
  77.  
  78.     /**
  79.      * 价税合计大写字符串
  80.      */
  81.     private String totalAmountString;
  82.  
  83.     /**
  84.      * 价税合计金额
  85.      */
  86.     private BigDecimal totalAmount;
  87.  
  88.     /**
  89.      * 销售方名称
  90.      */
  91.     private String sellerName;
  92.  
  93.     /**
  94.      * 销售方纳税人识别号
  95.      */
  96.     private String sellerCode;
  97.  
  98.     /**
  99.      * 销售方地址
  100.      */
  101.     private String sellerAddress;
  102.  
  103.     /**
  104.      * 销售方银行账号
  105.      */
  106.     private String sellerAccount;
  107.  
  108.     /**
  109.      * 收款人
  110.      */
  111.     private String payee;
  112.  
  113.     /**
  114.      * 复核人
  115.      */
  116.     private String reviewer;
  117.  
  118.     /**
  119.      * 开票人
  120.      */
  121.     private String drawer;
  122.  
  123.     /**
  124.      * 发票类型
  125.      */
  126.     private String type;
  127.  
  128.     /**
  129.      * 发票明细列表
  130.      */
  131.     private List<Detail> detailList;
  132.     private String content;        // 开票内容
  133.     private String inReserve2;        // 发票类别 专票/普票
  134.     
  135.     
  136.     public String getInReserve2() {
  137.         return inReserve2;
  138.     }
  139.     public void setInReserve2(String inReserve2) {
  140.         this.inReserve2 = inReserve2;
  141.     }
  142.  
  143.     public String getContent() {
  144.         return content;
  145.     }
  146.     public void setContent(String content) {
  147.         this.content = content;
  148.     }
  149.     /**
  150.      * 获取文件绝对路径
  151.      * @return 文件绝对路径
  152.      */
  153.     public String getFileAbsolutePath() {
  154.         return fileAbsolutePath;
  155.     }
  156.  
  157.     /**
  158.      * 设置文件绝对路径
  159.      * @param fileAbsolutePath 文件绝对路径
  160.      */
  161.     public void setFileAbsolutePath(String fileAbsolutePath) {
  162.         this.fileAbsolutePath = fileAbsolutePath;
  163.     }
  164.  
  165.     /**
  166.      * 获取标题
  167.      * @return 标题
  168.      */
  169.     public String getTitle() {
  170.         return title;
  171.     }
  172.  
  173.     /**
  174.      * 设置标题
  175.      * @param title 标题
  176.      */
  177.     public void setTitle(String title) {
  178.         this.title = title;
  179.     }
  180.  
  181.     /**
  182.      * 获取机器编号
  183.      * @return 机器编号
  184.      */
  185.     public String getMachineNumber() {
  186.         return machineNumber;
  187.     }
  188.  
  189.     /**
  190.      * 设置机器编号
  191.      * @param machineNumber 机器编号
  192.      */
  193.     public void setMachineNumber(String machineNumber) {
  194.         this.machineNumber = machineNumber;
  195.     }
  196.  
  197.     /**
  198.      * 获取发票代码
  199.      * @return 发票代码
  200.      */
  201.     public String getCode() {
  202.         return code;
  203.     }
  204.  
  205.     /**
  206.      * 设置发票代码
  207.      * @param code 发票代码
  208.      */
  209.     public void setCode(String code) {
  210.         this.code = code;
  211.     }
  212.  
  213.     /**
  214.      * 获取发票号码
  215.      * @return 发票号码
  216.      */
  217.     public String getNumber() {
  218.         return number;
  219.     }
  220.  
  221.     /**
  222.      * 设置发票号码
  223.      * @param number 发票号码
  224.      */
  225.     public void setNumber(String number) {
  226.         this.number = number;
  227.     }
  228.  
  229.     /**
  230.      * 获取日期
  231.      * @return 日期
  232.      */
  233.     public String getDate() {
  234.         return date;
  235.     }
  236.  
  237.     /**
  238.      * 设置日期
  239.      * @param date 日期
  240.      */
  241.     public void setDate(String date) {
  242.         this.date = date;
  243.     }
  244.  
  245.     /**
  246.      * 获取校验码
  247.      * @return 校验码
  248.      */
  249.     public String getChecksum() {
  250.         return checksum;
  251.     }
  252.  
  253.     /**
  254.      * 设置校验码
  255.      * @param checksum 校验码
  256.      */
  257.     public void setChecksum(String checksum) {
  258.         this.checksum = checksum;
  259.     }
  260.  
  261.     /**
  262.      * 获取购买方名称
  263.      * @return 购买方名称
  264.      */
  265.     public String getBuyerName() {
  266.         return buyerName;
  267.     }
  268.  
  269.     /**
  270.      * 设置购买方名称
  271.      * @param buyerName 购买方名称
  272.      */
  273.     public void setBuyerName(String buyerName) {
  274.         this.buyerName = buyerName;
  275.     }
  276.  
  277.     /**
  278.      * 获取购买方发票代码
  279.      * @return 购买方发票代码
  280.      */
  281.     public String getBuyerCode() {
  282.         return buyerCode;
  283.     }
  284.  
  285.     /**
  286.      * 设置购买方发票代码
  287.      * @param buyerCode 购买方发票代码
  288.      */
  289.     public void setBuyerCode(String buyerCode) {
  290.         this.buyerCode = buyerCode;
  291.     }
  292.  
  293.     /**
  294.      * 获取购买方地址
  295.      * @return 购买方地址
  296.      */
  297.     public String getBuyerAddress() {
  298.         return buyerAddress;
  299.     }
  300.  
  301.     /**
  302.      * 设置购买方地址
  303.      * @param buyerAddress 购买方地址
  304.      */
  305.     public void setBuyerAddress(String buyerAddress) {
  306.         this.buyerAddress = buyerAddress;
  307.     }
  308.  
  309.     /**
  310.      * 获取购买方账号
  311.      * @return 购买方账号
  312.      */
  313.     public String getBuyerAccount() {
  314.         return buyerAccount;
  315.     }
  316.  
  317.     /**
  318.      * 设置购买方账号
  319.      * @param buyerAccount 购买方账号
  320.      */
  321.     public void setBuyerAccount(String buyerAccount) {
  322.         this.buyerAccount = buyerAccount;
  323.     }
  324.  
  325.     /**
  326.      * 获取密码
  327.      * @return 密码
  328.      */
  329.     public String getPassword() {
  330.         return password;
  331.     }
  332.  
  333.     /**
  334.      * 设置密码
  335.      * @param password 密码
  336.      */
  337.     public void setPassword(String password) {
  338.         this.password = password;
  339.     }
  340.  
  341.     /**
  342.      * 获取金额
  343.      * @return 金额
  344.      */
  345.     public BigDecimal getAmount() {
  346.         return amount;
  347.     }
  348.  
  349.     /**
  350.      * 设置金额
  351.      * @param amount 金额
  352.      */
  353.     public void setAmount(BigDecimal amount) {
  354.         this.amount = amount;
  355.     }
  356.  
  357.     /**
  358.      * 获取税额
  359.      * @return 税额
  360.      */
  361.     public BigDecimal getTaxAmount() {
  362.         return taxAmount;
  363.     }
  364.  
  365.     /**
  366.      * 设置税额
  367.      * @param taxAmount 税额
  368.      */
  369.     public void setTaxAmount(BigDecimal taxAmount) {
  370.         this.taxAmount = taxAmount;
  371.     }
  372.  
  373.     /**
  374.      * 获取价税合计(大写)
  375.      * @return 价税合计(大写)
  376.      */
  377.     public String getTotalAmountString() {
  378.         return totalAmountString;
  379.     }
  380.  
  381.     /**
  382.      * 设置价税合计(大写)
  383.      * @param totalAmountString 价税合计(大写)
  384.      */
  385.     public void setTotalAmountString(String totalAmountString) {
  386.         this.totalAmountString = totalAmountString;
  387.     }
  388.  
  389.     /**
  390.      * 获取价税合计
  391.      * @return 价税合计
  392.      */
  393.     public BigDecimal getTotalAmount() {
  394.         return totalAmount;
  395.     }
  396.  
  397.     /**
  398.      * 设置价税合计
  399.      * @param totalAmount 价税合计
  400.      */
  401.     public void setTotalAmount(BigDecimal totalAmount) {
  402.         this.totalAmount = totalAmount;
  403.     }
  404.  
  405.     /**
  406.      * 获取销售方名称
  407.      * @return 销售方名称
  408.      */
  409.     public String getSellerName() {
  410.         return sellerName;
  411.     }
  412.  
  413.     /**
  414.      * 设置销售方名称
  415.      * @param sellerName 销售方名称
  416.      */
  417.     public void setSellerName(String sellerName) {
  418.         this.sellerName = sellerName;
  419.     }
  420.  
  421.     /**
  422.      * 获取销售方发票代码
  423.      * @return 销售方发票代码
  424.      */
  425.     public String getSellerCode() {
  426.         return sellerCode;
  427.     }
  428.  
  429.     /**
  430.      * 设置销售方发票代码
  431.      * @param sellerCode 销售方发票代码
  432.      */
  433.     public void setSellerCode(String sellerCode) {
  434.         this.sellerCode = sellerCode;
  435.     }
  436.  
  437.     /**
  438.      * 获取卖方地址。
  439.      * @return 卖方地址
  440.      */
  441.     public String getSellerAddress() {
  442.         return sellerAddress;
  443.     }
  444.  
  445.     /**
  446.      * 设置卖方地址。
  447.      * @param sellerAddress 要设置的卖方地址
  448.      */
  449.     public void setSellerAddress(String sellerAddress) {
  450.         this.sellerAddress = sellerAddress;
  451.     }
  452.  
  453.     /**
  454.      * 获取卖方账号。
  455.      * @return 卖方账号
  456.      */
  457.     public String getSellerAccount() {
  458.         return sellerAccount;
  459.     }
  460.  
  461.     /**
  462.      * 设置卖方账号。
  463.      * @param sellerAccount 要设置的卖方账号
  464.      */
  465.     public void setSellerAccount(String sellerAccount) {
  466.         this.sellerAccount = sellerAccount;
  467.     }
  468.  
  469.     /**
  470.      * 获取收款人信息。
  471.      * @return 收款人信息
  472.      */
  473.     public String getPayee() {
  474.         return payee;
  475.     }
  476.  
  477.     /**
  478.      * 设置收款人信息。
  479.      * @param payee 要设置的收款人信息
  480.      */
  481.     public void setPayee(String payee) {
  482.         this.payee = payee;
  483.     }
  484.  
  485.     /**
  486.      * 获取复核人信息。
  487.      * @return 复核人信息
  488.      */
  489.     public String getReviewer() {
  490.         return reviewer;
  491.     }
  492.  
  493.     /**
  494.      * 设置复核人信息。
  495.      * @param reviewer 要设置的复核人信息
  496.      */
  497.     public void setReviewer(String reviewer) {
  498.         this.reviewer = reviewer;
  499.     }
  500.  
  501.     /**
  502.      * 获取开票人信息。
  503.      * @return 开票人信息
  504.      */
  505.     public String getDrawer() {
  506.         return drawer;
  507.     }
  508.  
  509.     /**
  510.      * 设置开票人信息。
  511.      * @param drawer 要设置的开票人信息
  512.      */
  513.     public void setDrawer(String drawer) {
  514.         this.drawer = drawer;
  515.     }
  516.  
  517.     /**
  518.      * 获取发票类型。
  519.      * @return 发票类型
  520.      */
  521.     public String getType() {
  522.         return type;
  523.     }
  524.  
  525.     /**
  526.      * 设置发票类型。
  527.      * @param type 要设置的发票类型
  528.      */
  529.     public void setType(String type) {
  530.         this.type = type;
  531.     }
  532.  
  533.     /**
  534.      * 获取发票明细列表。
  535.      * @return 发票明细列表
  536.      */
  537.     public List<Detail> getDetailList() {
  538.         return detailList;
  539.     }
  540.  
  541.     /**
  542.      * 设置发票明细列表。
  543.      * @param detailList 要设置的发票明细列表
  544.      */
  545.     public void setDetailList(List<Detail> detailList) {
  546.         this.detailList = detailList;
  547.     }
  548.  
  549.  
  550.     @Override
  551.     public String toString() {
  552.         return "Invoice [title=" + title + ", machineNumber=" + machineNumber + ", code=" + code + ", number=" + number
  553.                 + ", date=" + date + ", checksum=" + checksum + ", buyerName=" + buyerName + ", buyerCode=" + buyerCode
  554.                 + ", buyerAddress=" + buyerAddress + ", buyerAccount=" + buyerAccount + ", password=" + password + ", amount="
  555.                 + amount + ", taxAmount=" + taxAmount + ", totalAmountString=" + totalAmountString + ", totalAmount="
  556.                 + totalAmount + ", sellerName=" + sellerName + ", sellerCode=" + sellerCode + ", sellerAddress=" + sellerAddress
  557.                 + ", sellerAccount=" + sellerAccount + ", payee=" + payee + ", reviewer=" + reviewer + ", drawer=" + drawer
  558.                 + ", type=" + type + ", detailList=" + detailList + "]";
  559.     }
  560. }


-------------------------------------------------------------------------

InvoiceRegexEnum.java

  1. package com.thinkgem.jeesite.modules.pdfServices.entity;
  2. public enum InvoiceRegexEnum {
  3. /**
  4. * 机器编码、发票代码、发票号码、开票日期和校验码的提取正则
  5. */
  6. REGULAR_A("机器编号:(?<machineNumber>\\d{12})|发票代码:(?<code>\\d{12})|发票号码:(?<number>\\d{8})|:(?<date>\\d{4}年\\d{2}月\\d{2}日)|校验码:(?<checksum>\\d{20}|\\S{4,})"),
  7. /**
  8. * 新版发票的机器编码、发票代码、发票号码、开票日期和校验码的提取正则
  9. */
  10. REGULAR_A_NEW("发票号码:(?<number>\\d{20})|:(?<date>\\d{4}年\\d{2}月\\d{2}日)|(售名称|销名称):(?<name>\\S*)"),
  11. /**
  12. * 发票号码备用提取正则
  13. */
  14. REGULAR_A_1("(国制|制普通发票)(?<number>\\d{8})"),
  15. /**
  16. * 发票号码跨行提取正则
  17. */
  18. REGULAR_A_1R("发票号码:(?<number>\\d{7})[\\s\\S]*?(\\d+)"),
  19. /**
  20. * 开票日期备用提取正则
  21. */
  22. REGULAR_A_2("开票日期:(?<date>\\d{4}\\d{2}月\\d{2}日)"),
  23. /**
  24. * 发票代码备用提取正则
  25. */
  26. REGULAR_A_3("发票代码(?<code>\\d{12})"),
  27. /**
  28. * 发票代码跨行提取正则
  29. */
  30. REGULAR_A_3R("发票代码:(?<code>\\d{10})[\\s\\S]*?(\\d+)"),
  31. /**
  32. * 金额、税额提取正则,匹配形如 "合计¥?金额¥?税额" 的文本
  33. */
  34. REGULAR_B("合计¥?(?<amount>[^ \\f\\n\\r\\t\\v*]*)(¥?(?<taxAmount>\\S*)|\\*+)\\s"),
  35. /**
  36. * 金额提取正则,用于匹配结果有误的修正
  37. */
  38. REGULAR_BR("合计¥(?<amount>\\d+\\.\\d+)"),
  39. /**
  40. * 金额、税额备用提取正则
  41. */
  42. REGULAR_B_1("合\\u0020*计\\u0020*¥?(?<amount>[^ ]*)\\u0020+¥?(?:(?<taxAmount>\\S*)|\\*+)\\s"),
  43. /**
  44. * 第一条发票类别
  45. */
  46. REGULAR_B_C("\\*.*?\\*([^\\s]+)\\s"),
  47. /**
  48. * 价税合计提取正则,匹配“价税合计(大写)XXX(小写)¥YYY”格式的文本
  49. */
  50. REGULAR_C("价税合计\\u0028大写\\u0029(?<amountString>\\S*)\\u0028小写\\u0029¥?(?<amount>\\S*)\\s"),
  51. /**
  52. * 收款人、复核、开票人、销售方提取正则,匹配格式为“收款人:xxx复核:xxx开票人:xxx销售方”的字符串
  53. */
  54. REGULAR_D("收款人:(?<payee>\\S*)复核:(?<reviewer>\\S*)开票人:(?<drawer>\\S*)销售方"),
  55. /**
  56. * 发票类型提取正则,匹配"xxx通发票"格式的发票类型
  57. */
  58. REGULAR_E("(?<p>\\S*)普通"),
  59. /**
  60. * 发票类型提取正则,匹配"xxx用发票"格式的发票类型
  61. */
  62. REGULAR_E_1("(?<p>\\S*)专用"),
  63. /**
  64. * 发票类型提取 - 辅助正则
  65. */
  66. REGULAR_E_AUX("(?:国|统|一|发|票|监|制)"),
  67. /**
  68. * 购买方信息提取正则
  69. */
  70. REGULAR_F("名称:(?<name>\\S*)|纳税人识别号:(?<code>\\S*)|地址、电话:(?<address>\\S*)|开户行及账号:(?<account>\\S*)|电子支付标识:(?<account2>\\S*)"),
  71. /**
  72. * 针对深圳发票的销售方名称提取正则
  73. */
  74. REGULAR_FR("名称:(?<name>\\S*)"),
  75. /**
  76. * 处理除了金额和税额之外的其他文本元素正则
  77. */
  78. REGULAR_G("^(-?\\d+)(\\.\\d+)?$"),
  79. /**
  80. * 检查当前详细项字符串是否符合特定条件正则
  81. */
  82. REGULAR_H("\\S+\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*"),
  83. REGULAR_H_1("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*"),
  84. REGULAR_H_2("\\S+\\d+%[\\-\\d]+\\S*"),
  85. REGULAR_H_3("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*");
  86. private final String regex;
  87. InvoiceRegexEnum(String regex) {
  88. this.regex = regex;
  89. }
  90. public String getRegex() {
  91. return regex;
  92. }
  93. }

---------------------------------------------------------------------

 InvoiceSubset.java

  1. package com.thinkgem.jeesite.modules.pdfServices.entity;
  2. import java.math.BigDecimal;
  3. public class InvoiceSubset {
  4. /**
  5. * 文件绝对路径
  6. */
  7. //private String fileAbsolutePath;
  8. /**
  9. * 发票代码
  10. */
  11. private String code;
  12. /**
  13. * 发票号码
  14. */
  15. private String number;
  16. /**
  17. * 新版发票号码
  18. */
  19. private String newNumber;
  20. /**
  21. * 开票日期
  22. */
  23. private String date;
  24. /**
  25. * 校验码
  26. */
  27. private String checksum;
  28. /**
  29. * 销售方名称
  30. */
  31. private String sellerName;
  32. /**
  33. * 合计金额
  34. */
  35. private BigDecimal amount;
  36. /**
  37. * 合计税额
  38. */
  39. private BigDecimal taxAmount;
  40. /**
  41. * 价税合计金额
  42. */
  43. private BigDecimal totalAmount;
  44. public String getCode() {
  45. return code;
  46. }
  47. public void setCode(String code) {
  48. this.code = code;
  49. }
  50. public String getNumber() {
  51. return number;
  52. }
  53. public void setNumber(String number) {
  54. this.number = number;
  55. }
  56. public String getNewNumber() {
  57. return newNumber;
  58. }
  59. public void setNewNumber(String newNumber) {
  60. this.newNumber = newNumber;
  61. }
  62. public String getDate() {
  63. return date;
  64. }
  65. public void setDate(String date) {
  66. this.date = date;
  67. }
  68. public String getChecksum() {
  69. return checksum;
  70. }
  71. public void setChecksum(String checksum) {
  72. this.checksum = checksum;
  73. }
  74. public String getSellerName() {
  75. return sellerName;
  76. }
  77. public void setSellerName(String sellerName) {
  78. this.sellerName = sellerName;
  79. }
  80. public BigDecimal getAmount() {
  81. return amount;
  82. }
  83. public void setAmount(BigDecimal amount) {
  84. this.amount = amount;
  85. }
  86. public BigDecimal getTaxAmount() {
  87. return taxAmount;
  88. }
  89. public void setTaxAmount(BigDecimal taxAmount) {
  90. this.taxAmount = taxAmount;
  91. }
  92. public BigDecimal getTotalAmount() {
  93. return totalAmount;
  94. }
  95. public void setTotalAmount(BigDecimal totalAmount) {
  96. this.totalAmount = totalAmount;
  97. }
  98. }

 ----------------------------------------------------------------
 

NewInvoice.java

  1. package com.thinkgem.jeesite.modules.pdfServices.entity;
  2. import java.math.BigDecimal;
  3. public class NewInvoice {
  4. /**
  5. * 文件绝对路径
  6. */
  7. private String fileAbsolutePath;
  8. /**
  9. * 发票号码
  10. */
  11. private String number;
  12. /**
  13. * 开票日期
  14. */
  15. private String date;
  16. /**
  17. * 销售方名称
  18. */
  19. private String sellerName;
  20. /**
  21. * 合计金额
  22. */
  23. private BigDecimal amount;
  24. /**
  25. * 合计税额
  26. */
  27. private BigDecimal taxAmount;
  28. /**
  29. * 价税合计金额
  30. */
  31. private BigDecimal totalAmount;
  32. private String content; // 开票内容
  33. private String inReserve2; // 发票类别 专票/普票
  34. public String getInReserve2() {
  35. return inReserve2;
  36. }
  37. public void setInReserve2(String inReserve2) {
  38. this.inReserve2 = inReserve2;
  39. }
  40. public String getContent() {
  41. return content;
  42. }
  43. public void setContent(String content) {
  44. this.content = content;
  45. }
  46. /**
  47. * 获取文件绝对路径
  48. * @return 文件绝对路径
  49. */
  50. public String getFileAbsolutePath() {
  51. return fileAbsolutePath;
  52. }
  53. /**
  54. * 设置文件绝对路径
  55. * @param fileAbsolutePath 文件绝对路径
  56. */
  57. public void setFileAbsolutePath(String fileAbsolutePath) {
  58. this.fileAbsolutePath = fileAbsolutePath;
  59. }
  60. /**
  61. * 获取发票号码
  62. * @return 发票号码
  63. */
  64. public String getNumber() {
  65. return number;
  66. }
  67. /**
  68. * 设置发票号码
  69. * @param number 发票号码
  70. */
  71. public void setNumber(String number) {
  72. this.number = number;
  73. }
  74. /**
  75. * 获取日期
  76. * @return 日期
  77. */
  78. public String getDate() {
  79. return date;
  80. }
  81. /**
  82. * 设置日期
  83. * @param date 日期
  84. */
  85. public void setDate(String date) {
  86. this.date = date;
  87. }
  88. /**
  89. * 获取金额
  90. * @return 金额
  91. */
  92. public BigDecimal getAmount() {
  93. return amount;
  94. }
  95. /**
  96. * 设置金额
  97. * @param amount 金额
  98. */
  99. public void setAmount(BigDecimal amount) {
  100. this.amount = amount;
  101. }
  102. /**
  103. * 获取税额
  104. * @return 税额
  105. */
  106. public BigDecimal getTaxAmount() {
  107. return taxAmount;
  108. }
  109. /**
  110. * 设置税额
  111. * @param taxAmount 税额
  112. */
  113. public void setTaxAmount(BigDecimal taxAmount) {
  114. this.taxAmount = taxAmount;
  115. }
  116. /**
  117. * 获取价税合计
  118. * @return 价税合计
  119. */
  120. public BigDecimal getTotalAmount() {
  121. return totalAmount;
  122. }
  123. /**
  124. * 设置价税合计
  125. * @param totalAmount 价税合计
  126. */
  127. public void setTotalAmount(BigDecimal totalAmount) {
  128. this.totalAmount = totalAmount;
  129. }
  130. /**
  131. * 获取销售方名称
  132. * @return 销售方名称
  133. */
  134. public String getSellerName() {
  135. return sellerName;
  136. }
  137. /**
  138. * 设置销售方名称
  139. * @param sellerName 销售方名称
  140. */
  141. public void setSellerName(String sellerName) {
  142. this.sellerName = sellerName;
  143. }
  144. @Override
  145. public String toString() {
  146. return "NewInvoice{" +
  147. "number='" + number + '\'' +
  148. ", date='" + date + '\'' +
  149. ", amount=" + amount +
  150. ", taxAmount=" + taxAmount +
  151. ", totalAmount=" + totalAmount +
  152. ", sellerName='" + sellerName + '\'' +
  153. '}';
  154. }
  155. }

--------------------------------------------------------

InvoiceExtractor.java

  1. package com.thinkgem.jeesite.modules.pdfServices.utils;
  2.  
  3.  
  4. import java.io.File;
  5. import java.math.BigDecimal;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. import com.thinkgem.jeesite.modules.pdfServices.entity.Detail;
  9. import com.thinkgem.jeesite.modules.pdfServices.entity.Invoice;
  10.  
  11. public class InvoiceExtractor {
  12.  
  13. //    public static Logger log = Logger.getLogger(Runnable.class);
  14.     
  15.     private static final String PDF_EXTENSION = ".pdf";
  16.  
  17.  
  18.     /**
  19.      * 处理指定文件夹中的PDF发票文件
  20.      * @param folderPath 文件夹路径
  21.      * @return 包含提取信息的 Invoice 列表
  22.      */
  23.     public static List<Invoice> pdfProcessInvoicesInFolder(String folderPath) {
  24.         File folder = new File(folderPath);
  25.         File[] files = folder.listFiles();
  26.         List<Invoice> resultList = new ArrayList<>();
  27.  
  28.         if (files != null) {
  29.             for (File file : files) {
  30.                 if (isPdfFile(file)) {
  31.                     Invoice result = extractInvoice(file.getAbsolutePath());
  32.  
  33.                     if (result != null) {
  34.                         Invoice returnResult = createProcessedInvoice(result);
  35.                         resultList.add(returnResult);
  36.                     } else {
  37.                         handleExtractionError(file);
  38.                     }
  39.                 }
  40.             }
  41.         }
  42.         return resultList;
  43.     }
  44.  
  45.     /**
  46.      * 处理指定的PDF发票文件
  47.      * @param filePath 文件路径
  48.      * @return 包含提取信息的 NewInvoice 列表
  49.      */
  50.     public static Invoice newPdfProcessInvoicesInFile(String filePath) {
  51.         File file = new File(filePath);
  52.         Invoice returnResult = new Invoice();
  53.         if (isPdfFile(file)) {
  54.             Invoice result = extractInvoice(file.getAbsolutePath());
  55.  
  56.             if (result != null) {
  57.                 returnResult = createProcessedInvoice(result);
  58.  
  59.             } else {
  60.                 handleExtractionError(file);
  61.             }
  62.         }
  63.  
  64.         return returnResult;
  65.     }
  66.  
  67.     /**
  68.      * 输出发票提取内容
  69.      * @param invoiceList 发票提取结果集合
  70.      */
  71.     public static void printListInvoice(List<Invoice> invoiceList, String type){
  72.         int sum = 0;
  73.         for (Invoice invoice : invoiceList) {
  74.             sum++;
  75.             if ("String".equals(type) || "string".equals(type)){
  76.                 System.out.println("\n文件绝对路径:" + invoice.getFileAbsolutePath() +
  77.                                    "\n发票代码: " + invoice.getCode() +
  78.                                    "\n发票号码: " + invoice.getNumber() +
  79.                                    "\n开票日期: " + invoice.getDate() +
  80.                                    "\n校验码后六位: " + invoice.getChecksum() +
  81.                                    "\n总价: " + invoice.getTotalAmount() +
  82.                                    "\n金额: " + invoice.getAmount() +
  83.                                    "\n税额: " + invoice.getTaxAmount() +
  84.                                    "\n销售方名称: " + invoice.getSellerName());
  85.             } else if ("List".equals(type) || "list".equals(type)) {
  86.                 System.out.println(invoice);
  87.             } else {
  88.                 System.out.println(invoice);
  89.             }
  90.         }
  91.         System.out.println("\nTotal:" + sum);
  92.     }
  93.  
  94.  
  95.     /**
  96.      * 检查文件是否为PDF文件
  97.      * @param file 要检查的文件
  98.      * @return 如果是PDF文件,返回 true,否则返回 false
  99.      */
  100.     private static boolean isPdfFile(File file) {
  101.         return file.isFile() && file.getName().toLowerCase().endsWith(PDF_EXTENSION);
  102.     }
  103.  
  104.     /**
  105.      * 创建一个处理后的 Invoice 对象
  106.      * @param result 原始的 Invoice 对象
  107.      * @return 处理后的 Invoice 对象
  108.      */
  109.     private static Invoice createProcessedInvoice(Invoice result) {
  110.         Invoice returnResult = new Invoice();
  111.  
  112.         String checksum = result.getChecksum();
  113.  
  114.         if (checksum != null) {
  115.             checksum = (checksum.length() > 6) ? checksum.substring(checksum.length() - 6) : checksum;
  116.         } else {
  117.             System.out.println("未提取到校验码~");
  118.         }
  119.  
  120.         BigDecimal amount = (result.getAmount().compareTo(BigDecimal.ZERO) == 0) ? getAmountFromDetailList(result) : result.getAmount();
  121.         BigDecimal taxAmount = (result.getTaxAmount().compareTo(BigDecimal.ZERO) == 0) ? getTaxAmountFromDetailList(result) : result.getTaxAmount();
  122.  
  123.         returnResult.setFileAbsolutePath(result.getFileAbsolutePath());
  124.         returnResult.setCode(result.getCode());
  125.         returnResult.setNumber(result.getNumber());
  126.         returnResult.setDate(result.getDate());
  127.         returnResult.setChecksum(checksum);
  128.         returnResult.setTotalAmount(result.getTotalAmount());
  129.         returnResult.setAmount(amount);
  130.         returnResult.setTaxAmount(taxAmount);
  131.         returnResult.setSellerName(result.getSellerName());
  132.         returnResult.setContent(result.getContent());
  133.         returnResult.setInReserve2(result.getInReserve2());
  134.         return returnResult;
  135.     }
  136.  
  137.     /**
  138.      * 从发票的 detailList 中获取金额
  139.      * @param result 原始的 Invoice 对象
  140.      * @return 从 detailList 中获取的金额,如果 detailList 为空则返回 BigDecimal.ZERO
  141.      */
  142.     private static BigDecimal getAmountFromDetailList(Invoice result) {
  143.         List<Detail> detailList = result.getDetailList();
  144.         return (!detailList.isEmpty()) ? detailList.get(0).getAmount() : BigDecimal.ZERO;
  145.     }
  146.  
  147.     /**
  148.      * 从发票的 detailList 中获取税额
  149.      * @param result 原始的 Invoice 对象
  150.      * @return 从 detailList 中获取的税额,如果 detailList 为空则返回 BigDecimal.ZERO
  151.      */
  152.     private static BigDecimal getTaxAmountFromDetailList(Invoice result) {
  153.         List<Detail> detailList = result.getDetailList();
  154.         return (!detailList.isEmpty()) ? detailList.get(0).getTaxAmount() : BigDecimal.ZERO;
  155.     }
  156.  
  157.     /**
  158.      * 处理提取失败的情况,输出错误信息
  159.      * @param file 提取失败的文件
  160.      */
  161.     private static void handleExtractionError(File file) {
  162. //        log.debug("文件: {}\t提取失败~~~\n"+ file.getName());
  163.         System.out.println("文件: {}\t提取失败~~~\n"+ file.getName());
  164.     }
  165.  
  166.  
  167.     /**
  168.      * 从本地文件或URL中提取发票信息。
  169.      * @param filePath 本地文件路径或发票的URL。
  170.      * @return 包含提取信息的 Invoice 对象。
  171.      */
  172.     private static Invoice extractInvoice(String filePath) {
  173.         File sourceFile = new File(filePath);
  174.  
  175.         if (!sourceFile.exists()) {
  176. //            log.debug("指定的源文件不存在");
  177.             System.out.println("指定的源文件不存在");
  178.             //throw new IllegalArgumentException("指定的源文件不存在");
  179.         }
  180.  
  181.         Invoice result = null;
  182.  
  183.         try {
  184.             result = PdfInvoiceExtractor.extract(sourceFile);
  185.             result.setFileAbsolutePath(sourceFile.getAbsolutePath());
  186.         } catch (Exception e) {
  187.             e.printStackTrace();
  188.             result = new Invoice();
  189.             result.setTitle("error");
  190.         }
  191.         return result;
  192.     }
  193. }

-----------------------------------------------------------------

NewInvoiceExtractor.java

  1. package com.thinkgem.jeesite.modules.pdfServices.utils;
  2.  
  3. import java.io.File;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. import com.thinkgem.jeesite.modules.pdfServices.entity.NewInvoice;
  7.  
  8. public class NewInvoiceExtractor {
  9.     
  10. //    public static Logger log = Logger.getLogger(Runnable.class);
  11.  
  12.     private static final String PDF_EXTENSION = ".pdf";
  13.  
  14.  
  15.     /**
  16.      * 处理指定文件夹中的PDF发票文件
  17.      * @param folderPath 文件夹路径
  18.      * @return 包含提取信息的 NewInvoice 列表
  19.      */
  20.     public static List<NewInvoice> newPdfProcessInvoicesInFolder(String folderPath) {
  21.         File folder = new File(folderPath);
  22.  
  23.         File[] files = folder.listFiles();
  24.  
  25.         List<NewInvoice> resultList = new ArrayList<>();
  26.  
  27.         if (files != null) {
  28.             for (File file : files) {
  29.                 if (isPdfFile(file)) {
  30.                     NewInvoice result = extractInvoice(file.getAbsolutePath());
  31.  
  32.                     if (result != null) {
  33.                         NewInvoice returnResult = createProcessedInvoice(result);
  34.                         resultList.add(returnResult);
  35.                     } else {
  36.                         handleExtractionError(file);
  37.                     }
  38.                 }
  39.             }
  40.         }
  41.  
  42.         return resultList;
  43.     }
  44.  
  45.  
  46.     /**
  47.      * 处理指定的PDF发票文件
  48.      * @param filePath 文件路径
  49.      * @return 包含提取信息的 NewInvoice 列表
  50.      */
  51.     public static NewInvoice newPdfProcessInvoicesInFile(String filePath) {
  52.         File file = new File(filePath);
  53.         NewInvoice returnResult = new NewInvoice();
  54.         if (isPdfFile(file)) {
  55.             NewInvoice result = extractInvoice(file.getAbsolutePath());
  56.  
  57.             if (result != null) {
  58.                 returnResult = createProcessedInvoice(result);
  59.  
  60.             } else {
  61.                 handleExtractionError(file);
  62.             }
  63.         }
  64.  
  65.         return returnResult;
  66.     }
  67.  
  68.  
  69.     /**
  70.      * 输出发票提取内容
  71.      * @param invoiceList 发票提取结果集合
  72.      */
  73.     public static void newPrintListInvoice(List<NewInvoice> invoiceList, String type){
  74.         int sum = 0;
  75.         for (NewInvoice invoice : invoiceList) {
  76.             sum++;
  77.             if ("String".equals(type) || "string".equals(type)){
  78.                 System.out.println("\n文件绝对路径: " + invoice.getFileAbsolutePath() +
  79.                                    "\n发票号码: " + invoice.getNumber() +
  80.                                    "\n开票日期: " + invoice.getDate() +
  81.                                    "\n总价: " + invoice.getTotalAmount() +
  82.                                    "\n金额: " + invoice.getAmount() +
  83.                                    "\n税额: " + invoice.getTaxAmount() +
  84.                                    "\n销售方名称: " + invoice.getSellerName());
  85.             } else if ("List".equals(type) || "list".equals(type)) {
  86.                 System.out.println(invoice);
  87.             } else {
  88.                 System.out.println(invoice);
  89.             }
  90.         }
  91.         System.out.println("\nTotal:" + sum);
  92.     }
  93.  
  94.  
  95.     /**
  96.      * 检查文件是否为PDF文件
  97.      * @param file 要检查的文件
  98.      * @return 如果是PDF文件,返回 true,否则返回 false
  99.      */
  100.     private static boolean isPdfFile(File file) {
  101.         return file.isFile() && file.getName().toLowerCase().endsWith(PDF_EXTENSION);
  102.     }
  103.  
  104.     /**
  105.      * 创建一个处理后的 NewInvoice 对象
  106.      * @param result 原始的 NewInvoice 对象
  107.      * @return 处理后的 NewInvoice 对象
  108.      */
  109.     private static NewInvoice createProcessedInvoice(NewInvoice result) {
  110.         NewInvoice returnResult = new NewInvoice();
  111.         returnResult.setFileAbsolutePath(result.getFileAbsolutePath());
  112.         returnResult.setNumber(result.getNumber());
  113.         returnResult.setDate(result.getDate());
  114.         returnResult.setContent(result.getContent());
  115.         returnResult.setTotalAmount(result.getTotalAmount());
  116.         returnResult.setAmount(result.getAmount());
  117.         returnResult.setTaxAmount(result.getTaxAmount());
  118.         returnResult.setSellerName(result.getSellerName());
  119.         returnResult.setInReserve2(result.getInReserve2());
  120.         return returnResult;
  121.     }
  122.  
  123.  
  124.     /**
  125.      * 处理提取失败的情况,输出错误信息
  126.      * @param file 提取失败的文件
  127.      */
  128.     private static void handleExtractionError(File file) {
  129. //        log.debug("文件: {}\t提取失败~~~\n"+ file.getName());
  130.         System.out.println("文件: {}\t提取失败~~~\n"+ file.getName());
  131.     }
  132.  
  133.  
  134.     /**
  135.      * 从本地文件或URL中提取发票信息。
  136.      * @param filePath 本地文件路径或发票的URL。
  137.      * @return 包含提取信息的 NewInvoice 对象。
  138.      */
  139.     private static NewInvoice extractInvoice(String filePath) {
  140.         File sourceFile = new File(filePath);
  141.  
  142.         if (!sourceFile.exists()) {
  143. //            log.error("指定的源文件不存在");
  144.             System.out.println("指定的源文件不存在");
  145.             //throw new IllegalArgumentException("指定的源文件不存在");
  146.         }
  147.  
  148.         NewInvoice result = null;
  149.  
  150.         try {
  151.             result = NewPdfInvoiceExtractor.extract(sourceFile);
  152.             result.setFileAbsolutePath(sourceFile.getAbsolutePath());
  153.         } catch (Exception e) {
  154.             e.printStackTrace();
  155.             result = new NewInvoice();
  156.         }
  157.         return result;
  158.     }
  159. }

------------------------------------------------------------------

NewPdfInvoiceExtractor.java

  1. package com.thinkgem.jeesite.modules.pdfServices.utils;
  2. import org.apache.pdfbox.pdmodel.PDDocument;
  3. import org.apache.pdfbox.text.PDFTextStripper;
  4. import com.thinkgem.jeesite.common.utils.StringUtils;
  5. import com.thinkgem.jeesite.modules.pdfServices.entity.InvoiceRegexEnum;
  6. import com.thinkgem.jeesite.modules.pdfServices.entity.NewInvoice;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.math.BigDecimal;
  10. import java.text.ParseException;
  11. import java.text.SimpleDateFormat;
  12. import java.util.*;
  13. import java.util.regex.Matcher;
  14. import java.util.regex.Pattern;
  15.  
  16.  
  17.  
  18. /**
  19.  * 处理电子发票识别类
  20.  * @author b16mt
  21.  */
  22. public class NewPdfInvoiceExtractor {
  23.     public static NewInvoice extract(File file) throws IOException {
  24.         NewInvoice invoice = new NewInvoice();
  25.         PDDocument doc = PDDocument.load(file);
  26. //        PDPage firstPage = doc.getPage(0);
  27.  
  28. //        int pageWidth = Math.round(firstPage.getCropBox().getWidth());
  29.  
  30.         PDFTextStripper textStripper = new PDFTextStripper();
  31.         textStripper.setSortByPosition(true);
  32.  
  33.         String fullText = textStripper.getText(doc);
  34.  
  35. //        if (firstPage.getRotation() != 0) {
  36. //            pageWidth = Math.round(firstPage.getCropBox().getHeight());
  37. //        }
  38.  
  39.         String allText = replace(fullText).replaceAll("(", "(").replaceAll(")", ")").replaceAll("¥", "¥");
  40.  
  41.         {
  42.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_A_NEW.getRegex());
  43.             Pattern patternNumber = Pattern.compile(InvoiceRegexEnum.REGULAR_A_1.getRegex());
  44.             Pattern patternDate = Pattern.compile(InvoiceRegexEnum.REGULAR_A_2.getRegex());
  45.             Matcher matcher = pattern.matcher(allText);
  46.             while (matcher.find()) {
  47.                 if (matcher.group("number") != null) {
  48.                     invoice.setNumber(matcher.group("number"));
  49.                 } else if (matcher.group("date") != null) {
  50.                     String rawDate = matcher.group("date");
  51.                     try {
  52.                         SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
  53.                         SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  54.  
  55.                         Date parsedDate = inputDateFormat.parse(rawDate);
  56.                         String formattedDate = outputDateFormat.format(parsedDate);
  57.                         invoice.setDate(formattedDate);
  58.                     } catch (ParseException e) {
  59.                         System.out.println("无法解析日期:" + rawDate);
  60.                     }
  61.                 } else if (matcher.group("name") != null){
  62.                     invoice.setSellerName(matcher.group("name"));
  63.                 }
  64.  
  65.                 if (matcher.group("number") == null){
  66.                     Matcher matcher2 = patternNumber.matcher(allText);
  67.                     if (matcher2.find()) {
  68.                         invoice.setNumber(matcher2.group("number"));
  69.                     }
  70.                 }
  71.                 if (matcher.group("date") == null){
  72.                     Matcher matcher3 = patternDate.matcher(allText);
  73.                     if (matcher3.find()) {
  74.                         String rawDate = matcher3.group("date");
  75.                         try {
  76.                             SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyyMM月dd日");
  77.                             SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  78.  
  79.                             Date parsedDate = inputDateFormat.parse(rawDate);
  80.                             String formattedDate = outputDateFormat.format(parsedDate);
  81.  
  82.                             invoice.setDate(formattedDate);
  83.                         } catch (Exception e) {
  84.                             System.out.println("无法解析日期:" + rawDate);
  85.                         }
  86.                     }
  87.                 }
  88.             }
  89.         }
  90.         //获取不到发票号码按照老版发票处理
  91.         if(StringUtils.isBlank(invoice.getNumber())){
  92.             return null;
  93.         }
  94.         
  95.         {
  96.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B.getRegex());
  97.             Matcher matcher = pattern.matcher(allText);
  98.             if (matcher.find()) {
  99.                 try {
  100.                     invoice.setAmount(new BigDecimal(matcher.group("amount")));
  101.                 } catch (Exception e) {
  102.                     // 不处理
  103.                 }
  104.                 try {
  105.                     invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
  106.                 } catch (Exception e) {
  107.                     invoice.setTaxAmount(new BigDecimal(0));
  108.                 }
  109.             }
  110.         }
  111.  
  112.         if (null == invoice.getAmount()) {
  113.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B_1.getRegex());
  114.             Matcher matcher = pattern.matcher(fullText);
  115.             if (matcher.find()) {
  116.                 try {
  117.                     invoice.setAmount(new BigDecimal(matcher.group("amount")));
  118.                 } catch (Exception e) {
  119.                     invoice.setAmount(new BigDecimal(0));
  120.                 }
  121.                 try {
  122.                     invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
  123.                 } catch (Exception e) {
  124.                     invoice.setTaxAmount(new BigDecimal(0));
  125.                 }
  126.             }
  127.         }
  128.         invoice.setTotalAmount(invoice.getAmount().add(invoice.getTaxAmount()));
  129.         
  130.         if (null == invoice.getInReserve2()) {
  131.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_E.getRegex());
  132.             Matcher matcher = pattern.matcher(fullText);
  133.             if (matcher.find()) {
  134.                 try {
  135.                     invoice.setInReserve2("普票");
  136.                 } catch (Exception e) {
  137.                     System.out.println("无法解析日期:" + matcher.group("p"));
  138.                 }
  139.             }else {
  140.                 Pattern pattern1 = Pattern.compile(InvoiceRegexEnum.REGULAR_E_1.getRegex());
  141.                 Matcher matcher1 = pattern1.matcher(fullText);
  142.                 if (matcher1.find()) {
  143.                     try {
  144.                         invoice.setInReserve2("专票");
  145.                     } catch (Exception e) {
  146.                         System.out.println("无法解析日期:" + matcher1.group("p"));
  147.                     }
  148.                 }
  149.             }
  150.         }
  151.         
  152.         if (null == invoice.getContent()) {
  153.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B_C.getRegex());
  154.             Matcher matcher = pattern.matcher(fullText);
  155.             if (matcher.find()) {
  156.                 try {
  157.                     invoice.setContent(matcher.group(1));
  158.                 } catch (Exception e) {
  159.                     invoice.setContent(null);
  160.                 }
  161.             }
  162.         }
  163.         return invoice;
  164.  
  165.     }
  166.  
  167.     /**
  168.      * 替换字符串中的空格、全角空格、冒号和特殊空白字符为标准字符。
  169.      * @param str 要进行替换的字符串
  170.      * @return 替换后的字符串
  171.      */
  172.     private static String replace(String str) {
  173.         return str.replaceAll(" ", "").replaceAll(" ", "").replaceAll(":", ":").replaceAll(" ", "");
  174.     }
  175. }

-------------------------------------------------------

PdfInvoiceExtractor.java

  1. package com.thinkgem.jeesite.modules.pdfServices.utils;
  2. import org.apache.commons.lang3.StringUtils;
  3. import org.apache.pdfbox.pdmodel.PDDocument;
  4. import org.apache.pdfbox.pdmodel.PDPage;
  5. import org.apache.pdfbox.text.PDFTextStripper;
  6. import org.apache.pdfbox.text.PDFTextStripperByArea;
  7. import com.thinkgem.jeesite.modules.pdfServices.entity.Detail;
  8. import com.thinkgem.jeesite.modules.pdfServices.entity.Invoice;
  9. import com.thinkgem.jeesite.modules.pdfServices.entity.InvoiceRegexEnum;
  10. import java.awt.*;
  11. import java.io.File;
  12. import java.io.IOException;
  13. import java.math.BigDecimal;
  14. import java.text.ParseException;
  15. import java.text.SimpleDateFormat;
  16. import java.util.List;
  17. import java.util.*;
  18. import java.util.regex.Matcher;
  19. import java.util.regex.Pattern;
  20.  
  21.  
  22.  
  23. /**
  24.  * 处理电子发票识别类
  25.  */
  26. public class PdfInvoiceExtractor {
  27.     public static Invoice extract(File file) throws IOException {
  28.         // 创建一个新的发票对象
  29.         Invoice invoice = new Invoice();
  30.  
  31.         // 加载 PDF 文件并获取第一页
  32.         PDDocument doc = PDDocument.load(file);
  33.         PDPage firstPage = doc.getPage(0);
  34.  
  35.         // 获取页面宽度
  36.         int pageWidth = Math.round(firstPage.getCropBox().getWidth());
  37.  
  38.         // 创建 PDF 文本提取工具
  39.         PDFTextStripper textStripper = new PDFTextStripper();
  40.         textStripper.setSortByPosition(true);
  41.  
  42.         // 提取整个 PDF 文本内容
  43.         String fullText = textStripper.getText(doc);
  44.  
  45.         // 如果页面旋转了,重新计算页面宽度
  46.         if (firstPage.getRotation() != 0) {
  47.             pageWidth = Math.round(firstPage.getCropBox().getHeight());
  48.         }
  49.  
  50.         // 替换文本中的全角字符为半角字符
  51.         String allText = replace(fullText).replaceAll("(", "(").replaceAll(")", ")").replaceAll("¥", "¥");
  52.  
  53.         // 使用正则表达式匹配和提取发票信息
  54.         {
  55.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_A.getRegex());
  56.             Pattern patternNumber = Pattern.compile(InvoiceRegexEnum.REGULAR_A_1.getRegex());
  57.             Pattern patternNumberReplace = Pattern.compile(InvoiceRegexEnum.REGULAR_A_1R.getRegex());
  58.             Pattern patternDate = Pattern.compile(InvoiceRegexEnum.REGULAR_A_2.getRegex());
  59.             Pattern patternCode = Pattern.compile(InvoiceRegexEnum.REGULAR_A_3.getRegex());
  60.             Pattern patternCodeReplace = Pattern.compile(InvoiceRegexEnum.REGULAR_A_3R.getRegex());
  61.  
  62.             Matcher matcher = pattern.matcher(allText);
  63.             while (matcher.find()) {
  64.                 if (matcher.group("machineNumber") != null) {
  65.                     invoice.setMachineNumber(matcher.group("machineNumber"));
  66.                 } else if (matcher.group("code") != null) {
  67.                     invoice.setCode(matcher.group("code"));
  68.                 } else if (matcher.group("number") != null) {
  69.                     invoice.setNumber(matcher.group("number"));
  70.                 } else if (matcher.group("date") != null) {
  71.                     String rawDate = matcher.group("date");
  72.                     try {
  73.                         SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
  74.                         SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  75.  
  76.                         Date parsedDate = inputDateFormat.parse(rawDate);
  77.                         String formattedDate = outputDateFormat.format(parsedDate);
  78.                         invoice.setDate(formattedDate);
  79.                     } catch (ParseException e) {
  80.                         System.out.println("无法解析日期:" + rawDate);
  81.                     }
  82.                 } else if (matcher.group("checksum") != null) {
  83.                     invoice.setChecksum(matcher.group("checksum"));
  84.                 }
  85.  
  86.                 if (invoice.getNumber() == null){
  87.                     Matcher matcher2 = patternNumber.matcher(allText);
  88.                     if (matcher2.find()) {
  89.                         invoice.setNumber(matcher2.group("number"));
  90.                     }
  91.                     if (invoice.getNumber() == null){
  92.                         Matcher matcher2Replace = patternNumberReplace.matcher(allText);
  93.                         while (matcher2Replace.find()) {
  94.                             String firstNumber = matcher2Replace.group("number");
  95.                             String secondNumber = matcher2Replace.group(2);
  96.                             invoice.setNumber(firstNumber + secondNumber);
  97.                         }
  98.                     }
  99.                 }
  100.  
  101.                 if (invoice.getDate() == null){
  102.                     Matcher matcher3 = patternDate.matcher(allText);
  103.                     if (matcher3.find()) {
  104.                         String rawDate = matcher3.group("date");
  105.  
  106.                         try {
  107.                             SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyyMM月dd日");
  108.                             SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");
  109.  
  110.                             Date parsedDate = inputDateFormat.parse(rawDate);
  111.                             String formattedDate = outputDateFormat.format(parsedDate);
  112.  
  113.                             invoice.setDate(formattedDate);
  114.                         } catch (Exception e) {
  115.                             System.out.println("无法解析日期:" + rawDate);
  116.                         }
  117.                     }
  118.                 }
  119.  
  120.                 if (invoice.getCode() == null){
  121.                     Matcher matcher4 = patternCode.matcher(allText);
  122.                     if (matcher4.find()) {
  123.                         invoice.setCode(matcher4.group("code"));
  124.                     }
  125.                     if (invoice.getCode() == null){
  126.                         Matcher matcher4Replace = patternCodeReplace.matcher(allText);
  127.                         while (matcher4Replace.find()) {
  128.                             String firstCode = matcher4Replace.group("code");
  129.                             String secondCode = matcher4Replace.group(2);
  130.                             invoice.setCode(secondCode + firstCode);
  131.                         }
  132.                     }
  133.                 }
  134.             }
  135.         }
  136.  
  137.         {
  138.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B.getRegex());
  139.  
  140.             Matcher matcher = pattern.matcher(allText);
  141.  
  142.             if (matcher.find()) {
  143.                 try {
  144.                     invoice.setAmount(new BigDecimal(matcher.group("amount")));
  145.                 } catch (Exception e) {
  146.                     // 不处理
  147.                 }
  148.                 try {
  149.                     invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
  150.                 } catch (Exception e) {
  151.                     invoice.setTaxAmount(new BigDecimal(0));
  152.                 }
  153.             }
  154.         }
  155.  
  156.         if (null == invoice.getAmount()) {
  157.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B_1.getRegex());
  158.  
  159.             Matcher matcher = pattern.matcher(fullText);
  160.  
  161.             if (matcher.find()) {
  162.                 try {
  163.                     invoice.setAmount(new BigDecimal(matcher.group("amount")));
  164.                 } catch (Exception e) {
  165.                     invoice.setAmount(new BigDecimal(0));
  166.                 }
  167.                 try {
  168.                     invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));
  169.                 } catch (Exception e) {
  170.                     invoice.setTaxAmount(new BigDecimal(0));
  171.                 }
  172.             }
  173.         }
  174.  
  175.         if (null == invoice.getContent()) {
  176.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_B_C.getRegex());
  177.             Matcher matcher = pattern.matcher(fullText);
  178.             while (matcher.find()) {
  179.                 try {
  180.                     invoice.setContent(matcher.group(1));
  181.                 } catch (Exception e) {
  182.                     invoice.setContent(null);
  183.                 }
  184.             }
  185.         }
  186.         
  187.         {
  188.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_C.getRegex());
  189.  
  190.             Matcher matcher = pattern.matcher(allText);
  191.  
  192.             if (matcher.find()) {
  193.                 invoice.setTotalAmountString(matcher.group("amountString"));
  194.  
  195.                 try {
  196.                     invoice.setTotalAmount(new BigDecimal(matcher.group("amount")));
  197.                 } catch (Exception e) {
  198.                     invoice.setTotalAmount(new BigDecimal(0));
  199.                 }
  200.             }
  201.         }
  202.  
  203.         {
  204.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_D.getRegex());
  205.             Matcher matcher = pattern.matcher(allText);
  206.  
  207.             if (matcher.find()) {
  208.                 invoice.setPayee(matcher.group("payee"));
  209.                 invoice.setReviewer(matcher.group("reviewer"));
  210.                 invoice.setDrawer(matcher.group("drawer"));
  211.             }
  212.  
  213.             if (allText.indexOf("通行费") > 0 && allText.indexOf("车牌号") > 0) {
  214.                 invoice.setType("通行费");
  215.             }
  216.         }
  217.  
  218.         {
  219.             Pattern type00Pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_E.getRegex());
  220.             Matcher m00 = type00Pattern.matcher(allText);
  221.             if (m00.find()) {
  222. //                invoice.setTitle(m00.group("p").replaceAll(InvoiceRegexEnum.REGULAR_E_AUX.getRegex(), "") + "通发票");
  223.                 if (null == invoice.getInReserve2()) {
  224.                     invoice.setInReserve2("普票");
  225.                 }
  226.             } else {
  227.                 Pattern type01Pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_E_1.getRegex());
  228.                 Matcher m01 = type01Pattern.matcher(allText);
  229.                 if (m01.find()) {
  230. //                    invoice.setTitle(m01.group("p").replaceAll(InvoiceRegexEnum.REGULAR_E_AUX.getRegex(), "") + "用发票");
  231.                     if (null == invoice.getInReserve2()) {
  232.                         invoice.setInReserve2("专票");
  233.                     }
  234.                 }
  235.             }
  236.         }
  237.  
  238.         PDFKeyWordPosition kwp = new PDFKeyWordPosition();
  239.  
  240.         Map<String, List<Position>> positionListMap = kwp.getCoordinate(Arrays.asList("机器编号", "税率", "价税合计", "合计", "开票日期", "规格型号", "车牌号", "开户行及账号", "密", "码", "区"), doc);
  241.  
  242.         PDFTextStripperByArea stripper = new PDFTextStripperByArea();
  243.         stripper.setSortByPosition(true);
  244.  
  245.         PDFTextStripperByArea detailStripper = new PDFTextStripperByArea();
  246.         detailStripper.setSortByPosition(true);
  247.         {
  248.             Position machineNumber;
  249.             if (positionListMap.get("机器编号").size() > 0) {
  250.                 machineNumber = positionListMap.get("机器编号").get(0);
  251.             } else {
  252.                 machineNumber = positionListMap.get("开票日期").get(0);
  253.                 machineNumber.setY(machineNumber.getY() + 30);
  254.             }
  255.             Position taxRate = positionListMap.get("税率").get(0);
  256.             Position totalAmount = positionListMap.get("价税合计").get(0);
  257.             Position amount = positionListMap.get("合计").get(0);
  258.  
  259.             Position model = null;
  260.  
  261.             if (!positionListMap.get("规格型号").isEmpty()) {
  262.                 model = positionListMap.get("规格型号").get(0);
  263.             } else {
  264.                 model = positionListMap.get("车牌号").get(0);
  265.                 model.setX(model.getX() - 15);
  266.             }
  267.  
  268.             List<Position> account = positionListMap.get("开户行及账号");
  269.  
  270.             Position buyer;
  271.             Position seller;
  272.  
  273.             if (account.size() < 2) {
  274.                 buyer = new Position(51, 122);
  275.                 seller = new Position(51, 341);
  276.             } else {
  277.                 buyer = account.get(0);
  278.                 seller = account.get(1);
  279.             }
  280.  
  281.             int maqX = 370;
  282.  
  283.             List<Position> mi = positionListMap.get("密");
  284.             List<Position> ma = positionListMap.get("码");
  285.             List<Position> qu = positionListMap.get("区");
  286.  
  287.             for (Position position : mi) {
  288.                 float x1 = position.getX();
  289.                 for (Position value : ma) {
  290.                     float x2 = value.getX();
  291.                     if (Math.abs(x1 - x2) < 5) {
  292.                         for (Position item : qu) {
  293.                             float x3 = item.getX();
  294.                             if (Math.abs(x2 - x3) < 5) {
  295.                                 maqX = Math.round((x1 + x2 + x3) / 3);
  296.                             }
  297.                         }
  298.                     }
  299.                 }
  300.             }
  301.  
  302.             {
  303.             int x = Math.round(model.getX()) - 13;
  304.             int y = Math.round(taxRate.getY()) + 5;
  305.             int h = Math.round(amount.getY()) - Math.round(taxRate.getY()) - 25;
  306.  
  307.             detailStripper.addRegion("detail", new Rectangle(0, y, pageWidth, h));
  308.             stripper.addRegion("detailName", new Rectangle(0, y, x, h));
  309.             stripper.addRegion("detailPrice", new Rectangle(x, y, pageWidth, h));
  310.             }
  311.  
  312.             {
  313.                 int x = maqX + 10;
  314.                 int y = Math.round(machineNumber.getY()) + 10;
  315.                 int w = pageWidth - maqX - 10;
  316.                 int h = Math.round(taxRate.getY() - 5) - y;
  317.  
  318.                 stripper.addRegion("password", new Rectangle(x, y, w, h));
  319.             }
  320.  
  321.             {
  322.                 int x = Math.round(buyer.getX()) - 15;
  323.                 int y = Math.round(machineNumber.getY()) + 10;
  324.                 int w = maqX - x - 5;
  325.                 int h = Math.round(buyer.getY()) - y + 20;
  326.  
  327.                 stripper.addRegion("buyer", new Rectangle(x, y, w, h));
  328.             }
  329.  
  330.             {
  331.                 int x = Math.round(seller.getX()) - 15;
  332.                 int y = Math.round(totalAmount.getY()) + 10;
  333.                 int w = maqX - x - 5;
  334.                 int h = Math.round(seller.getY()) - y + 20;
  335.  
  336.                 stripper.addRegion("seller", new Rectangle(x, y, w, h));
  337.             }
  338.         }
  339.  
  340.         stripper.extractRegions(firstPage);
  341.         detailStripper.extractRegions(firstPage);
  342.  
  343.         doc.close();
  344.  
  345.         invoice.setPassword(StringUtils.trim(stripper.getTextForRegion("password")));
  346.  
  347.         {
  348.             String buyer = replace(stripper.getTextForRegion("buyer"));
  349.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_F.getRegex());
  350.  
  351.             Matcher matcher = pattern.matcher(buyer);
  352.  
  353.             while (matcher.find()) {
  354.                 if (matcher.group("name") != null) {
  355.                     invoice.setBuyerName(matcher.group("name"));
  356.                 }
  357.                 else if (matcher.group("code") != null) {
  358.                     invoice.setBuyerCode(matcher.group("code"));
  359.                 }
  360.                 else if (matcher.group("address") != null) {
  361.                     invoice.setBuyerAddress(matcher.group("address"));
  362.                 }
  363.                 else if (matcher.group("account") != null) {
  364.                     invoice.setBuyerAccount(matcher.group("account"));
  365.                 }
  366.                 else if (matcher.group("account2") != null) {
  367.                     invoice.setBuyerAccount(matcher.group("account2"));
  368.                 }
  369.             }
  370.         }
  371.  
  372.         {
  373.             String seller = replace(stripper.getTextForRegion("seller"));
  374.  
  375.             Pattern pattern = Pattern.compile(InvoiceRegexEnum.REGULAR_F.getRegex());
  376.  
  377.             Matcher matcher = pattern.matcher(seller);
  378.  
  379.             while (matcher.find()) {
  380.                 if (matcher.group("name") != null) {
  381.                     if (matcher.group("name").contains("出有限公司")){
  382.                         String replace = matcher.group("name").replace("出有限公司", "出版社有限公司");
  383.                         invoice.setSellerName(replace);
  384.                     } else if (matcher.group("name").contains("贸有公司")) {
  385.                         String replace = matcher.group("name").replace("贸有公司", "贸易有限公司");
  386.                         invoice.setSellerName(replace);
  387.                     } else {
  388.                         invoice.setSellerName(matcher.group("name"));
  389.                     }
  390.                 }
  391.                 else if (matcher.group("code") != null) {
  392.                     invoice.setSellerCode(matcher.group("code"));
  393.                 }
  394.                 else if (matcher.group("address") != null) {
  395.                     invoice.setSellerAddress(matcher.group("address"));
  396.                 }
  397.                 else if (matcher.group("account") != null) {
  398.                     invoice.setSellerAccount(matcher.group("account"));
  399.                 }
  400.             }
  401.         }
  402.         if (invoice.getSellerName() == null){
  403.             Pattern patternReplace = Pattern.compile(InvoiceRegexEnum.REGULAR_FR.getRegex());
  404.  
  405.             Matcher matcherReplace = patternReplace.matcher(allText);
  406.  
  407.             while (matcherReplace.find()) {
  408.                 if (matcherReplace.group("name") != null) {
  409.                     if (!matcherReplace.group("name").contains("学院") || !matcherReplace.group("name").contains("大学")){
  410.                         if (matcherReplace.group("name").contains("出有限公司")){
  411.                             String replace = matcherReplace.group("name").replace("出有限公司", "出版社有限公司");
  412.                             invoice.setSellerName(replace);
  413.                         } else if (matcherReplace.group("name").contains("贸有公司")) {
  414.                             String replace = matcherReplace.group("name").replace("贸有公司", "贸易有限公司");
  415.                             invoice.setSellerName(replace);
  416.                         } else {
  417.                             invoice.setSellerName(matcherReplace.group("name"));
  418.                         }
  419.                     }
  420.                 }
  421.             }
  422.         }
  423.  
  424.         {
  425.             List<String> skipList = new ArrayList<>();
  426.  
  427.             List<Detail> detailList = new ArrayList<>();
  428.  
  429.             String[] detailPriceStringArray = stripper.getTextForRegion("detailPrice")
  430.                     .replaceAll(" ", " ").replaceAll(" ", " ").replaceAll("\r", "").split("\\n");
  431.  
  432.             for (String detailString : detailPriceStringArray) {
  433.                 Detail detail = new Detail();
  434.  
  435.                 detail.setName("");
  436.  
  437.                 String[] itemArray = StringUtils.split(detailString, " ");
  438.  
  439.                 if (2 == itemArray.length) {
  440.                     detail.setAmount(new BigDecimal(itemArray[0]));
  441.                     detail.setTaxAmount(new BigDecimal(itemArray[1]));
  442.  
  443.                     detailList.add(detail);
  444.                 }
  445.                 else if (2 < itemArray.length) {
  446.                     detail.setAmount(new BigDecimal(itemArray[itemArray.length - 3]));
  447.  
  448.                     String taxRate = itemArray[itemArray.length - 2];
  449.  
  450.                     if (taxRate.indexOf("免税") > 0 || taxRate.indexOf("不征税") > 0 || taxRate.indexOf("出口零税率") > 0
  451.                             || taxRate.indexOf("普通零税率") > 0 || !taxRate.contains("%")) {
  452.                         detail.setTaxRate(new BigDecimal(0));
  453.                         detail.setTaxAmount(new BigDecimal(0));
  454.                     } else {
  455.                         BigDecimal rate = new BigDecimal(Integer.parseInt(taxRate.replaceAll("%", "")));
  456.                         detail.setTaxRate(rate.divide(new BigDecimal(100)));
  457.                         detail.setTaxAmount(new BigDecimal(itemArray[itemArray.length - 1]));
  458.                     }
  459.  
  460.                     for (int j = 0; j < itemArray.length - 3; j++) {
  461.                         if (itemArray[j].matches(InvoiceRegexEnum.REGULAR_G.getRegex())) {
  462.                             if (null == detail.getCount()) {
  463.                                 detail.setCount(new BigDecimal(itemArray[j]));
  464.                             } else {
  465.                                 detail.setPrice(new BigDecimal(itemArray[j]));
  466.                             }
  467.                         } else {
  468.                             if (itemArray.length >= j + 1 && !itemArray[j + 1].matches(InvoiceRegexEnum.REGULAR_G.getRegex())) {
  469.                                 detail.setUnit(itemArray[j + 1]);
  470.                                 detail.setModel(itemArray[j]);
  471.                                 j++;
  472.                             } else if (itemArray[j].length() > 2) {
  473.                                 detail.setModel(itemArray[j]);
  474.                             } else {
  475.                                 detail.setUnit(itemArray[j]);
  476.                             }
  477.                         }
  478.                     }
  479.                     detailList.add(detail);
  480.                 } else {
  481.                     skipList.add(detailString);
  482.                 }
  483.             }
  484.  
  485.             String[] detailNameStringArray = stripper.getTextForRegion("detailName").replaceAll(" ", " ").replaceAll(" ", " ")
  486.                     .replaceAll("\r", "").split("\\n");
  487.             String[] detailStringArray = replace(detailStripper.getTextForRegion("detail")).replaceAll("\r", "").split("\\n");
  488.             int i = 0, j = 0, h = 0, m = 0;
  489.             Detail lastDetail = null;
  490.  
  491.             for (String detailString : detailStringArray) {
  492.                 if (m < detailNameStringArray.length) {
  493.                     if (detailString.matches(InvoiceRegexEnum.REGULAR_H.getRegex())
  494.                             && !detailString.matches(InvoiceRegexEnum.REGULAR_H_1.getRegex())
  495.                             && detailString.matches(InvoiceRegexEnum.REGULAR_H_2.getRegex())
  496.                             || detailStringArray.length > i + 1
  497.                             && detailStringArray[i + 1].matches(InvoiceRegexEnum.REGULAR_H_3.getRegex())) {
  498.                         if (j < detailList.size()) {
  499.                             lastDetail = detailList.get(j);
  500.                             lastDetail.setName(detailNameStringArray[m]);
  501.                         }
  502.                         j++;
  503.                     } else if (null != lastDetail && StringUtils.isNotBlank(detailNameStringArray[m])) {
  504.                         if (skipList.size() > h) {
  505.                             String skip = skipList.get(h);
  506.                             if (detailString.endsWith(skip)) {
  507.                                 if (detailString.equals(skip)) {
  508.                                     m--;
  509.                                 } else {
  510.                                     lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
  511.                                 }
  512.                                 lastDetail.setModel(lastDetail.getModel() + skip);
  513.                                 h++;
  514.                             } else {
  515.                                 lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
  516.                             }
  517.                         } else {
  518.                             lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);
  519.                         }
  520.                     }
  521.                 }
  522.                 i++;
  523.                 m++;
  524.             }
  525.  
  526.             invoice.setDetailList(detailList);
  527.  
  528.             if (invoice.getAmount().add(invoice.getTaxAmount()).compareTo(invoice.getTotalAmount()) != 0){
  529.                 Pattern patternReplace = Pattern.compile(InvoiceRegexEnum.REGULAR_BR.getRegex());
  530.  
  531.                 Matcher matcherReplace = patternReplace.matcher(allText);
  532.  
  533.                 if (matcherReplace.find()) {
  534.                     try {
  535.                         invoice.setAmount(new BigDecimal(matcherReplace.group("amount")));
  536.                         invoice.setTaxAmount(invoice.getTotalAmount().subtract(invoice.getAmount()));
  537.                     } catch (Exception e) {
  538.                         // 不处理
  539.                     }
  540.                 }
  541.             }
  542.  
  543.  
  544.             if (invoice.getTotalAmount().compareTo(BigDecimal.ZERO) == 0){
  545.                 if (invoice.getAmount().compareTo(BigDecimal.ZERO) == 0){
  546.                     invoice.setAmount((!detailList.isEmpty()) ? detailList.get(0).getAmount() : BigDecimal.ZERO);
  547.                     invoice.setTaxAmount((!detailList.isEmpty()) ? detailList.get(0).getTaxAmount() : BigDecimal.ZERO);
  548.                 }
  549.                 invoice.setTotalAmount(invoice.getAmount().add(invoice.getTaxAmount()));
  550.             }
  551.  
  552.         }
  553.         return invoice;
  554.  
  555.     }
  556.  
  557.     /**
  558.      * 替换字符串中的空格、全角空格、冒号和特殊空白字符为标准字符。
  559.      * @param str 要进行替换的字符串
  560.      * @return 替换后的字符串
  561.      */
  562.     private static String replace(String str) {
  563.         return str.replaceAll(" ", "").replaceAll(" ", "").replaceAll(":", ":").replaceAll(" ", "");
  564.     }
  565. }

------------------------------------------------------------

PDFKeyWordPosition.java

  1. package com.thinkgem.jeesite.modules.pdfServices.utils;
  2. import org.apache.pdfbox.pdmodel.PDDocument;
  3. import org.apache.pdfbox.text.PDFTextStripper;
  4. import org.apache.pdfbox.text.TextPosition;
  5.  
  6. import java.io.ByteArrayOutputStream;
  7. import java.io.IOException;
  8. import java.io.OutputStreamWriter;
  9. import java.io.Writer;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.List;
  13. import java.util.Map;
  14.  
  15. public class PDFKeyWordPosition extends PDFTextStripper {
  16.  
  17.     private List<String> keywordList;
  18.     private Map<String, List<Position>> positionListMap;
  19.  
  20.     public PDFKeyWordPosition() throws IOException {
  21.         super();
  22.     }
  23.  
  24.     /**
  25.      * 获取坐标信息
  26.      *
  27.      * @param keywordList 要搜索的关键字列表
  28.      * @param document    PDF 文档
  29.      * @return 关键字的位置信息映射
  30.      * @throws
  31.      */
  32.     public Map<String, List<Position>> getCoordinate(List<String> keywordList, PDDocument document) throws IOException {
  33.         super.setSortByPosition(true);
  34.         this.keywordList = keywordList;
  35.         this.positionListMap = new HashMap<>();
  36.         super.setStartPage(1);
  37.         super.setEndPage(1);
  38.         Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());
  39.         super.writeText(document, dummy);
  40.         return positionListMap;
  41.     }
  42.  
  43.     @Override
  44.     protected void writeString(String string, List<TextPosition> textPositions) throws IOException {
  45.         for (String keyword : keywordList) {
  46.             int foundIndex = 0;
  47.             List<Position> positionList = positionListMap.computeIfAbsent(keyword, k -> new ArrayList<>());
  48.  
  49.             for (int i = 0; i < textPositions.size(); i++) {
  50.                 TextPosition textPosition = textPositions.get(i);
  51.                 String str = textPosition.getUnicode();
  52.  
  53.                 if (0 < str.length() && str.charAt(0) == keyword.charAt(foundIndex)) {
  54.                     foundIndex++;
  55.                     int count = foundIndex;
  56.  
  57.                     for (int j = foundIndex; j < keyword.length(); j++) {
  58.                         if (i + j >= textPositions.size()) {
  59.                             break;
  60.                         } else {
  61.                             String s = textPositions.get(i + j).getUnicode();
  62.  
  63.                             if (0 < s.length() && s.charAt(0) == keyword.charAt(j)) {
  64.                                 count++;
  65.                             }
  66.                         }
  67.                     }
  68.  
  69.                     if (count == keyword.length()) {
  70.                         foundIndex = 0;
  71.                         Position position = new Position();
  72.                         position.setX(textPosition.getX());
  73.                         position.setY(textPosition.getY());
  74.                         positionList.add(position);
  75.                         positionListMap.put(keyword, positionList);
  76.                     }
  77.                 }
  78.             }
  79.         }
  80.     }
  81. }
  82.  
  83.  
  84. class Position {
  85.     public Position() {
  86.     }
  87.  
  88.     public Position(float x, float y) {
  89.         super();
  90.         this.x = x;
  91.         this.y = y;
  92.     }
  93.  
  94.     float x;
  95.     float y;
  96.  
  97.     public float getX() {
  98.         return x;
  99.     }
  100.  
  101.     public void setX(float x) {
  102.         this.x = x;
  103.     }
  104.  
  105.     public float getY() {
  106.         return y;
  107.     }
  108.  
  109.     public void setY(float y) {
  110.         this.y = y;
  111.     }
  112.  
  113.     @Override
  114.     public String toString() {
  115.         return "Position [x=" + x + ", y=" + y + "]";
  116.     }
  117. }

***********代码至此结束,以下是需要导入包*********************************

  1. <!-- pdf识别-->
  2. <dependency>
  3. <groupId>org.apache.pdfbox</groupId>
  4. <artifactId>pdfbox</artifactId>
  5. <version>2.0.21</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.apache.pdfbox</groupId>
  9. <artifactId>fontbox</artifactId>
  10. <version>2.0.21</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.apache.pdfbox</groupId>
  14. <artifactId>jempbox</artifactId>
  15. <version>1.8.13</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.apache.pdfbox</groupId>
  19. <artifactId>xmpbox</artifactId>
  20. <version>2.0.0</version>
  21. </dependency>
  22. <dependency>
  23. <groupId>org.apache.pdfbox</groupId>
  24. <artifactId>preflight</artifactId>
  25. <version>2.0.0</version>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.apache.pdfbox</groupId>
  29. <artifactId>pdfbox-tools</artifactId>
  30. <version>2.0.0</version>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.apache.poi</groupId>
  34. <artifactId>poi</artifactId>
  35. <version>5.0.0</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.apache.poi</groupId>
  39. <artifactId>poi-ooxml</artifactId>
  40. <version>5.0.0</version>
  41. </dependency>
  42. <dependency>
  43. <groupId>com.google.zxing</groupId>
  44. <artifactId>core</artifactId>
  45. <version>3.1.0</version>
  46. </dependency>
  47. <dependency>
  48. <groupId>com.google.zxing</groupId>
  49. <artifactId>javase</artifactId>
  50. <version>3.1.0</version>
  51. </dependency>
  52. <dependency>
  53. <groupId>org.apache.commons</groupId>
  54. <artifactId>commons-lang3</artifactId>
  55. <version>3.12.0</version>
  56. </dependency>
  57. <dependency>
  58. <groupId>commons-io</groupId>
  59. <artifactId>commons-io</artifactId>
  60. <version>2.11.0</version>
  61. </dependency>
  62. <dependency>
  63. <groupId>commons-codec</groupId>
  64. <artifactId>commons-codec</artifactId>
  65. </dependency>
  66. <!-- pdf识别end-->

==========================================================

导出excel效果如图:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/924445
推荐阅读
相关标签
  

闽ICP备14008679号