电子发票识别与解析 java

2024-04-15 18:28
文章标签 java 解析 电子 识别 发票

本文主要是介绍电子发票识别与解析 java,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

处理电子发票的业务

public class PdfInvoiceExtractor {public static Invoice extract(File file) throws IOException {Invoice invoice = new Invoice();PDDocument doc = PDDocument.load(file);PDPage firstPage = doc.getPage(0);int pageWidth = Math.round(firstPage.getCropBox().getWidth());PDFTextStripper textStripper = new PDFTextStripper();textStripper.setSortByPosition(true);String fullText = textStripper.getText(doc);if (firstPage.getRotation() != 0) {pageWidth = Math.round(firstPage.getCropBox().getHeight());}String allText = replace(fullText).replaceAll("(", "(").replaceAll(")", ")").replaceAll("¥", "¥");{String reg = "机器编号:(?<machineNumber>\\d{12})|发票代码:(?<code>\\d{12})|发票号码:(?<number>\\d{8})|:(?<date>\\d{4}年\\d{2}月\\d{2}日)"+ "|校验码:(?<checksum>\\d{20}|\\S{4,})";Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(allText);while (matcher.find()) {if (matcher.group("machineNumber") != null) {invoice.setMachineNumber(matcher.group("machineNumber"));} else if (matcher.group("code") != null) {invoice.setCode(matcher.group("code"));} else if (matcher.group("number") != null) {invoice.setNumber(matcher.group("number"));} else if (matcher.group("date") != null) {invoice.setDate(matcher.group("date"));} else if (matcher.group("checksum") != null) {invoice.setChecksum(matcher.group("checksum"));}}}{String reg = "合计¥?(?<amount>[^ \\f\\n\\r\\t\\v\\*]*)(?:¥?(?<taxAmount>\\S*)|\\*+)\\s";Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(allText);if (matcher.find()) {try {invoice.setAmount(new BigDecimal(matcher.group("amount")));} catch (Exception e) {}try {invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));} catch (Exception e) {invoice.setTaxAmount(new BigDecimal(0));}}}if (null == invoice.getAmount()) {String reg = "合\\u0020*计\\u0020*¥?(?<amount>[^ ]*)\\u0020+¥?(?:(?<taxAmount>\\S*)|\\*+)\\s";Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(fullText);if (matcher.find()) {try {invoice.setAmount(new BigDecimal(matcher.group("amount")));} catch (Exception e) {invoice.setAmount(new BigDecimal(0));}try {invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));} catch (Exception e) {invoice.setTaxAmount(new BigDecimal(0));}}}{String reg = "价税合计\\u0028大写\\u0029(?<amountString>\\S*)\\u0028小写\\u0029¥?(?<amount>\\S*)\\s";Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(allText);if (matcher.find()) {invoice.setTotalAmountString(matcher.group("amountString"));try {invoice.setTotalAmount(new BigDecimal(matcher.group("amount")));} catch (Exception e) {invoice.setTotalAmount(new BigDecimal(0));}}}{String reg = "收款人:(?<payee>\\S*)复核:(?<reviewer>\\S*)开票人:(?<drawer>\\S*)销售方";Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(allText);if (matcher.find()) {invoice.setPayee(matcher.group("payee"));invoice.setReviewer(matcher.group("reviewer"));invoice.setDrawer(matcher.group("drawer"));}if (allText.indexOf("通行费") > 0 && allText.indexOf("车牌号") > 0) {invoice.setType("通行费");}Pattern type00Pattern = Pattern.compile("(?<p>\\S*)通发票");Matcher m00 = type00Pattern.matcher(allText);if (m00.find()) {invoice.setTitle(m00.group("p").replaceAll("(?:国|统|一|发|票|监|制)", "") + "通发票");if (null == invoice.getType()) {invoice.setType("普通发票");}} else {Pattern type01Pattern = Pattern.compile("(?<p>\\S*)用发票");Matcher m01 = type01Pattern.matcher(allText);if (m01.find()) {invoice.setTitle(m01.group("p").replaceAll("(?:国|统|一|发|票|监|制)", "") + "用发票");if (null == invoice.getType()) {invoice.setType("专用发票");}}}}PDFKeyWordPosition kwp = new PDFKeyWordPosition();Map<String, List<Position>> positionListMap = kwp.getCoordinate(Arrays.asList("机器编号", "税率", "价税合计", "合计", "开票日期", "规格型号", "车牌号", "开户行及账号", "密", "码", "区"), doc);PDFTextStripperByArea stripper = new PDFTextStripperByArea();stripper.setSortByPosition(true);PDFTextStripperByArea detailStripper = new PDFTextStripperByArea();detailStripper.setSortByPosition(true);{Position machineNumber;if (positionListMap.get("机器编号").size() > 0) {machineNumber = positionListMap.get("机器编号").get(0);} else {machineNumber = positionListMap.get("开票日期").get(0);machineNumber.setY(machineNumber.getY() + 30);}Position taxRate = positionListMap.get("税率").get(0);Position totalAmount = positionListMap.get("价税合计").get(0);Position amount = positionListMap.get("合计").get(0);Position model = null;if (!positionListMap.get("规格型号").isEmpty()) {model = positionListMap.get("规格型号").get(0);} else {model = positionListMap.get("车牌号").get(0);model.setX(model.getX() - 15);}List<Position> account = positionListMap.get("开户行及账号");Position buyer;Position seller;if (account.size() < 2) {buyer = new Position(51, 122);seller = new Position(51, 341);} else {buyer = account.get(0);seller = account.get(1);}int maqX = 370;List<Position> mi = positionListMap.get("密");List<Position> ma = positionListMap.get("码");List<Position> qu = positionListMap.get("区");for (int i = 0; i < mi.size(); i++) {float x1 = mi.get(i).getX();for (int j = 0; j < ma.size(); j++) {float x2 = ma.get(j).getX();if (Math.abs(x1 - x2) < 5) {for (int k = 0; k < qu.size(); k++) {float x3 = qu.get(k).getX();if (Math.abs(x2 - x3) < 5) {maqX = Math.round((x1 + x2 + x3) / 3);}}}}}{int x = Math.round(model.getX()) - 13;int y = Math.round(taxRate.getY()) + 5; // 用税率的y坐标作参考int h = Math.round(amount.getY()) - Math.round(taxRate.getY()) - 25; // 价税合计的y坐标减去税率的y坐标detailStripper.addRegion("detail", new Rectangle(0, y, pageWidth, h));stripper.addRegion("detailName", new Rectangle(0, y, x, h));stripper.addRegion("detailPrice", new Rectangle(x, y, pageWidth, h));}{int x = maqX + 10;int y = Math.round(machineNumber.getY()) + 10;int w = pageWidth - maqX - 10;int h = Math.round(taxRate.getY() - 5) - y;stripper.addRegion("password", new Rectangle(x, y, w, h));}{int x = Math.round(buyer.getX()) - 15; // 开户行及账号的x为参考int y = Math.round(machineNumber.getY()) + 10; // 机器编号的y坐标为参考int w = maqX - x - 5; // 密码区x坐标为参考int h = Math.round(buyer.getY()) - y + 20; // 开户行及账号的y坐标为参考stripper.addRegion("buyer", new Rectangle(x, y, w, h));}{int x = Math.round(seller.getX()) - 15; // 开户行及账号为x参考int y = Math.round(totalAmount.getY()) + 10; // 价税合计的y坐标为参考int w = maqX - x - 5; // 密码区的x为参考int h = Math.round(seller.getY()) - y + 20; // 开户行及账号的y为参考stripper.addRegion("seller", new Rectangle(x, y, w, h));}}stripper.extractRegions(firstPage);detailStripper.extractRegions(firstPage);doc.close();invoice.setPassword(StringUtils.trim(stripper.getTextForRegion("password")));String reg = "名称:(?<name>\\S*)|纳税人识别号:(?<code>\\S*)|地址、电话:(?<address>\\S*)|开户行及账号:(?<account>\\S*)|电子支付标识:(?<account2>\\S*)";{String buyer = replace(stripper.getTextForRegion("buyer"));Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(buyer);while (matcher.find()) {if (matcher.group("name") != null) {invoice.setBuyerName(matcher.group("name"));} else if (matcher.group("code") != null) {invoice.setBuyerCode(matcher.group("code"));} else if (matcher.group("address") != null) {invoice.setBuyerAddress(matcher.group("address"));} else if (matcher.group("account") != null) {invoice.setBuyerAccount(matcher.group("account"));} else if (matcher.group("account2") != null) {invoice.setBuyerAccount(matcher.group("account2"));}}}{String seller = replace(stripper.getTextForRegion("seller"));Pattern pattern = Pattern.compile(reg);Matcher matcher = pattern.matcher(seller);while (matcher.find()) {if (matcher.group("name") != null) {invoice.setSellerName(matcher.group("name"));} else if (matcher.group("code") != null) {invoice.setSellerCode(matcher.group("code"));} else if (matcher.group("address") != null) {invoice.setSellerAddress(matcher.group("address"));} else if (matcher.group("account") != null) {invoice.setSellerAccount(matcher.group("account"));}}}{List<String> skipList = new ArrayList<>();List<Detail> detailList = new ArrayList<>();String[] detailPriceStringArray = stripper.getTextForRegion("detailPrice").replaceAll(" ", " ").replaceAll(" ", " ").replaceAll("\r", "").split("\\n");for (String detailString : detailPriceStringArray) {Detail detail = new Detail();detail.setName("");String[] itemArray = StringUtils.split(detailString, " ");if (2 == itemArray.length) {detail.setAmount(new BigDecimal(itemArray[0]));detail.setTaxAmount(new BigDecimal(itemArray[1]));detailList.add(detail);} else if (2 < itemArray.length) {detail.setAmount(new BigDecimal(itemArray[itemArray.length - 3]));String taxRate = itemArray[itemArray.length - 2];if (taxRate.indexOf("免税") > 0 || taxRate.indexOf("不征税") > 0 || taxRate.indexOf("出口零税率") > 0|| taxRate.indexOf("普通零税率") > 0 || taxRate.indexOf("%") < 0) {detail.setTaxRate(new BigDecimal(0));detail.setTaxAmount(new BigDecimal(0));} else {BigDecimal rate = new BigDecimal(Integer.parseInt(taxRate.replaceAll("%", "")));detail.setTaxRate(rate.divide(new BigDecimal(100)));detail.setTaxAmount(new BigDecimal(itemArray[itemArray.length - 1]));}for (int j = 0; j < itemArray.length - 3; j++) {if (itemArray[j].matches("^(-?\\d+)(\\.\\d+)?$")) {if (null == detail.getCount()) {detail.setCount(new BigDecimal(itemArray[j]));} else {detail.setPrice(new BigDecimal(itemArray[j]));}} else {if (itemArray.length >= j + 1 && !itemArray[j + 1].matches("^(-?\\d+)(\\.\\d+)?$")) {detail.setUnit(itemArray[j + 1]);detail.setModel(itemArray[j]);j++;} else if (itemArray[j].length() > 2) {detail.setModel(itemArray[j]);} else {detail.setUnit(itemArray[j]);}}}detailList.add(detail);} else {skipList.add(detailString);}}String[] detailNameStringArray = stripper.getTextForRegion("detailName").replaceAll(" ", " ").replaceAll(" ", " ").replaceAll("\r", "").split("\\n");String[] detailStringArray = replace(detailStripper.getTextForRegion("detail")).replaceAll("\r", "").split("\\n");int i = 0, j = 0, h = 0, m = 0;Detail lastDetail = null;for (String detailString : detailStringArray) {if (m < detailNameStringArray.length) {if (detailString.matches("\\S+\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*")&& !detailString.matches("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*")&& detailString.matches("\\S+\\d+%[\\-\\d]+\\S*")|| detailStringArray.length > i + 1&& detailStringArray[i + 1].matches("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*")) {if (j < detailList.size()) {lastDetail = detailList.get(j);lastDetail.setName(detailNameStringArray[m]);}j++;} else if (null != lastDetail && StringUtils.isNotBlank(detailNameStringArray[m])) {if (skipList.size() > h) {String skip = skipList.get(h);if (detailString.endsWith(skip)) {if (detailString.equals(skip)) {m--;} else {lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);}lastDetail.setModel(lastDetail.getModel() + skip);h++;} else {lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);}} else {lastDetail.setName(lastDetail.getName() + detailNameStringArray[m]);}}}i++;m++;}invoice.setDetailList(detailList);}return invoice;}public static String replace(String str) {return str.replaceAll(" ", "").replaceAll(" ", "").replaceAll(":", ":").replaceAll(" ", "");}
}

发票内容坐标

public class PdfKeyWordPosition extends PDFTextStripper {private List<String> keywordList;private Map<String, List<Position>> positionListMap;public PdfKeyWordPosition() throws IOException {super();}// 获取坐标信息public Map<String, List<Position>> getCoordinate(List<String> keywordList, PDDocument document) throws IOException {super.setSortByPosition(true);this.keywordList = keywordList;this.positionListMap = new HashMap<>();super.setStartPage(1);super.setEndPage(1);Writer dummy = new OutputStreamWriter(new ByteArrayOutputStream());super.writeText(document, dummy);return positionListMap;}@Overrideprotected void writeString(String string, List<TextPosition> textPositions) throws IOException {for (String keyword : keywordList) {Integer foundIndex = 0;List<Position> positionList = positionListMap.computeIfAbsent(keyword, k -> new ArrayList<>());for (int i = 0; i < textPositions.size(); i++) {TextPosition textPosition = textPositions.get(i);String str = textPosition.getUnicode();if (0 < str.length() && str.charAt(0) == keyword.charAt(foundIndex)) {foundIndex++;int count = foundIndex;for (int j = foundIndex; j < keyword.length(); j++) {if (i + j >= textPositions.size()) {break;} else {String s = textPositions.get(i + j).getUnicode();if (0 < s.length() && s.charAt(0) == keyword.charAt(j)) {count++;}}}if (count == keyword.length()) {foundIndex = 0;Position position = new Position();position.setX(textPosition.getX());position.setY(textPosition.getY());positionList.add(position);positionListMap.put(keyword, positionList);}}}}}}class Position {public Position() {}public Position(float x, float y) {super();this.x = x;this.y = y;}float x;float y;/*** @return the x*/public float getX() {return x;}/*** @param x*            the x to set*/public void setX(float x) {this.x = x;}/*** @return the y*/public float getY() {return y;}/*** @param y*            the y to set*/public void setY(float y) {this.y = y;}@Overridepublic String toString() {return "Position [x=" + x + ", y=" + y + "]";}
}

OFD格式解析

public class OfdInvoiceExtractor {public static Invoice extract(File file) throws IOException, DocumentException {ZipFile zipFile = new ZipFile(file);ZipEntry entry = zipFile.getEntry("Doc_0/Attachs/original_invoice.xml");ZipEntry entry1 = zipFile.getEntry("Doc_0/Pages/Page_0/Content.xml");InputStream input = zipFile.getInputStream(entry);InputStream input1 = zipFile.getInputStream(entry1);String body = StreamUtils.copyToString(input, Charset.forName("utf-8"));String content = StreamUtils.copyToString(input1, Charset.forName("utf-8"));zipFile.close();Document document = DocumentHelper.parseText(body);Element root = document.getRootElement();Invoice invoice = new Invoice();invoice.setMachineNumber(root.elementTextTrim("MachineNo"));invoice.setCode(root.elementTextTrim("InvoiceCode"));invoice.setNumber(root.elementTextTrim("InvoiceNo"));invoice.setDate(root.elementTextTrim("IssueDate"));invoice.setChecksum(root.elementTextTrim("InvoiceCheckCode"));invoice.setAmount(new BigDecimal(root.elementTextTrim("TaxExclusiveTotalAmount")));invoice.setTaxAmount(new BigDecimal(root.elementTextTrim("TaxTotalAmount")));int ind = content.indexOf("圆整</ofd:TextCode>");invoice.setTotalAmountString(content.substring(content.lastIndexOf(">", ind) + 1, ind + 2));invoice.setTotalAmount(new BigDecimal(root.elementTextTrim("TaxInclusiveTotalAmount")));invoice.setPayee(root.elementTextTrim("Payee"));invoice.setReviewer(root.elementTextTrim("Checker"));invoice.setDrawer(root.elementTextTrim("InvoiceClerk"));int index = content.indexOf("</ofd:TextCode>");invoice.setTitle(content.substring(content.lastIndexOf(">", index) + 1, index));invoice.setType("普通发票");if (invoice.getTitle().contains("专用发票")) {invoice.setType("专用发票");} else if (invoice.getTitle().contains("通行费")) {invoice.setType("通行费");}invoice.setPassword(root.elementText("TaxControlCode"));Element buyer = root.element("Buyer");{invoice.setBuyerName(buyer.elementTextTrim("BuyerName"));invoice.setBuyerCode(buyer.elementTextTrim("BuyerTaxID"));invoice.setBuyerAddress(buyer.elementTextTrim("BuyerAddrTel"));invoice.setBuyerAccount(buyer.elementTextTrim("BuyerFinancialAccount"));}Element seller = root.element("Seller");{invoice.setSellerName(seller.elementTextTrim("SellerName"));invoice.setSellerCode(seller.elementTextTrim("SellerTaxID"));invoice.setSellerAddress(seller.elementTextTrim("SellerAddrTel"));invoice.setSellerAccount(seller.elementTextTrim("SellerFinancialAccount"));}Element details = root.element("GoodsInfos");{List<Detail> detailList = new ArrayList<>();List<Element> elements = details.elements();for (Element element : elements) {Detail detail = new Detail();detail.setName(element.elementTextTrim("Item"));detail.setAmount(new BigDecimal(element.elementTextTrim("Amount")));detail.setTaxAmount(new BigDecimal(element.elementTextTrim("TaxAmount")));detail.setCount(new BigDecimal(element.elementTextTrim("Quantity")));detail.setPrice(new BigDecimal(element.elementTextTrim("Price")));detail.setUnit(element.elementTextTrim("MeasurementDimension"));detail.setModel(element.elementTextTrim("Specification"));detail.setTaxRate(new BigDecimal(element.elementTextTrim("TaxScheme").replace("%", "")).divide(new BigDecimal(100)));detailList.add(detail);}invoice.setDetailList(detailList);}return invoice;}
}

发票信息

public class Invoice {private String title;private String machineNumber;private String code;private String number;private String date;private String checksum;private String buyerName;private String buyerCode;private String buyerAddress;private String buyerAccount;private String password;private BigDecimal amount;private BigDecimal taxAmount;private String totalAmountString;private BigDecimal totalAmount;private String sellerName;private String sellerCode;private String sellerAddress;private String sellerAccount;private String payee;private String reviewer;private String drawer;private String type;private List<Detail> detailList;/*** @return the title*/public String getTitle() {return title;}/*** @param title*            the title to set*/public void setTitle(String title) {this.title = title;}/*** @return the machineNumber*/public String getMachineNumber() {return machineNumber;}/*** @param machineNumber*            the machineNumber to set*/public void setMachineNumber(String machineNumber) {this.machineNumber = machineNumber;}/*** @return the code*/public String getCode() {return code;}/*** @param code*            the code to set*/public void setCode(String code) {this.code = code;}/*** @return the number*/public String getNumber() {return number;}/*** @param number*            the number to set*/public void setNumber(String number) {this.number = number;}/*** @return the date*/public String getDate() {return date;}/*** @param date*            the date to set*/public void setDate(String date) {this.date = date;}/*** @return the checksum*/public String getChecksum() {return checksum;}/*** @param checksum*            the checksum to set*/public void setChecksum(String checksum) {this.checksum = checksum;}/*** @return the buyerName*/public String getBuyerName() {return buyerName;}/*** @param buyerName*            the buyerName to set*/public void setBuyerName(String buyerName) {this.buyerName = buyerName;}/*** @return the buyerInvoiceCode*/public String getBuyerCode() {return buyerCode;}/*** @param buyerCode*            the buyerCode to set*/public void setBuyerCode(String buyerCode) {this.buyerCode = buyerCode;}/*** @return the buyerAddress*/public String getBuyerAddress() {return buyerAddress;}/*** @param buyerAddress*            the buyerAddress to set*/public void setBuyerAddress(String buyerAddress) {this.buyerAddress = buyerAddress;}/*** @return the buyerAccount*/public String getBuyerAccount() {return buyerAccount;}/*** @param buyerAccount*            the buyerAccount to set*/public void setBuyerAccount(String buyerAccount) {this.buyerAccount = buyerAccount;}/*** @return the password*/public String getPassword() {return password;}/*** @param password*            the password to set*/public void setPassword(String password) {this.password = password;}/*** @return the amount*/public BigDecimal getAmount() {return amount;}/*** @param amount*            the amount to set*/public void setAmount(BigDecimal amount) {this.amount = amount;}/*** @return the taxAmount*/public BigDecimal getTaxAmount() {return taxAmount;}/*** @param taxAmount*            the taxAmount to set*/public void setTaxAmount(BigDecimal taxAmount) {this.taxAmount = taxAmount;}/*** @return the totalAmountString*/public String getTotalAmountString() {return totalAmountString;}/*** @param totalAmountString*            the totalAmountString to set*/public void setTotalAmountString(String totalAmountString) {this.totalAmountString = totalAmountString;}/*** @return the totalAmount*/public BigDecimal getTotalAmount() {return totalAmount;}/*** @param totalAmount*            the totalAmount to set*/public void setTotalAmount(BigDecimal totalAmount) {this.totalAmount = totalAmount;}/*** @return the sellerName*/public String getSellerName() {return sellerName;}/*** @param sellerName*            the sellerName to set*/public void setSellerName(String sellerName) {this.sellerName = sellerName;}/*** @return the sellerCode*/public String getSellerCode() {return sellerCode;}/*** @param sellerCode*            the sellerCode to set*/public void setSellerCode(String sellerCode) {this.sellerCode = sellerCode;}/*** @return the sellerAddress*/public String getSellerAddress() {return sellerAddress;}/*** @param sellerAddress*            the sellerAddress to set*/public void setSellerAddress(String sellerAddress) {this.sellerAddress = sellerAddress;}/*** @return the sellerAccount*/public String getSellerAccount() {return sellerAccount;}/*** @param sellerAccount*            the sellerAccount to set*/public void setSellerAccount(String sellerAccount) {this.sellerAccount = sellerAccount;}/*** @return the payee*/public String getPayee() {return payee;}/*** @param payee*            the payee to set*/public void setPayee(String payee) {this.payee = payee;}/*** @return the reviewer*/public String getReviewer() {return reviewer;}/*** @param reviewer*            the reviewer to set*/public void setReviewer(String reviewer) {this.reviewer = reviewer;}/*** @return the drawer*/public String getDrawer() {return drawer;}/*** @param drawer*            the drawer to set*/public void setDrawer(String drawer) {this.drawer = drawer;}/*** @return the type*/public String getType() {return type;}/*** @param type*            the type to set*/public void setType(String type) {this.type = type;}/*** @return the detailList*/public List<Detail> getDetailList() {return detailList;}/*** @param detailList*            the detailList to set*/public void setDetailList(List<Detail> detailList) {this.detailList = detailList;}@Overridepublic String toString() {return "Invoice [title=" + title + ", machineNumber=" + machineNumber + ", code=" + code + ", number=" + number+ ", date=" + date + ", checksum=" + checksum + ", buyerName=" + buyerName + ", buyerCode=" + buyerCode+ ", buyerAddress=" + buyerAddress + ", buyerAccount=" + buyerAccount + ", password=" + password + ", amount="+ amount + ", taxAmount=" + taxAmount + ", totalAmountString=" + totalAmountString + ", totalAmount="+ totalAmount + ", sellerName=" + sellerName + ", sellerCode=" + sellerCode + ", sellerAddress=" + sellerAddress+ ", sellerAccount=" + sellerAccount + ", payee=" + payee + ", reviewer=" + reviewer + ", drawer=" + drawer+ ", type=" + type + ", detailList=" + detailList + "]";}
}class Detail {private String name;private String model;private String unit;private BigDecimal count;private BigDecimal price;private BigDecimal amount;private BigDecimal taxRate;private BigDecimal taxAmount;/*** @return the name*/public String getName() {return name;}/*** @param name*            the name to set*/public void setName(String name) {this.name = name;}/*** @return the model*/public String getModel() {return model;}/*** @param model*            the model to set*/public void setModel(String model) {this.model = model;}/*** @return the unit*/public String getUnit() {return unit;}/*** @param unit*            the unit to set*/public void setUnit(String unit) {this.unit = unit;}/*** @return the count*/public BigDecimal getCount() {return count;}/*** @param count*            the count to set*/public void setCount(BigDecimal count) {this.count = count;}/*** @return the price*/public BigDecimal getPrice() {return price;}/*** @param price*            the price to set*/public void setPrice(BigDecimal price) {this.price = price;}/*** @return the amount*/public BigDecimal getAmount() {return amount;}/*** @param amount*            the amount to set*/public void setAmount(BigDecimal amount) {this.amount = amount;}/*** @return the taxRate*/public BigDecimal getTaxRate() {return taxRate;}/*** @param taxRate*            the taxRate to set*/public void setTaxRate(BigDecimal taxRate) {this.taxRate = taxRate;}/*** @return the taxAmount*/public BigDecimal getTaxAmount() {return taxAmount;}/*** @param taxAmount*            the taxAmount to set*/public void setTaxAmount(BigDecimal taxAmount) {this.taxAmount = taxAmount;}@Overridepublic String toString() {return "Detail [name=" + name + ", model=" + model + ", unit=" + unit + ", count=" + count + ", price=" + price+ ", amount=" + amount + ", taxRate=" + taxRate + ", taxAmount=" + taxAmount + "]";}
}

这篇关于电子发票识别与解析 java的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/906579

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听