package space.anyi.amountVerification; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.read.listener.PageReadListener; import javafx.application.Application; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Alert; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.Label; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.control.ProgressBar; import javafx.scene.control.TextField; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; import javafx.stage.DirectoryChooser; import javafx.stage.FileChooser; import javafx.stage.Stage; import org.apache.pdfbox.Loader; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.text.PDFTextStripper; import space.anyi.amountVerification.model.InputModel; import space.anyi.amountVerification.model.OutputModel; import java.io.File; import java.io.IOException; import java.math.BigDecimal; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @ProjectName: amount-verification * @FileName: Application * @Author: 杨逸 * @Data:2025/11/27 18:33 * @Description: */ public class App extends Application { private Stage primaryStage; /** * 文件 * @see TextField */ private TextField fileField; /**文件夹 * @see TextField */ private TextField folderField; /** * excel输入数据 * @see List */ private List inputModelList; /** * excel输出数据 * @see List */ private List outputModelList; /** * IMEI码与PDF文件映射 * @see Map */ private Map pdfFileMap; /** * 进度条控件 * @see ProgressBar */ private ProgressBar progressBar; /** * 进度标签 * @see Label */ private Label progressLabel; /** * 匹配金额使用的正则表达式对象 * @see Pattern */ private Pattern pattern; { /** * 代码快初始化匹配金额的正则表达式对象 */ String regex = "理赔金额合计:¥(?\\d+\\.\\d{2})"; this.pattern = Pattern.compile(regex); } public static void main(String[] args) { Application.launch(App.class, args); } @Override public void start(Stage primaryStage) throws Exception { this.primaryStage = primaryStage; primaryStage.setTitle("金额验证工具"); primaryStage.setResizable(false); // 设置窗口关闭事件处理 primaryStage.setOnCloseRequest(event -> { event.consume(); // 阻止默认关闭行为 showCloseConfirmation(primaryStage); }); // 创建主布局 BorderPane mainLayout = new BorderPane(); // 创建菜单栏 MenuBar menuBar = createMenuBar(); mainLayout.setTop(menuBar); // 创建内容区域 VBox contentLayout = new VBox(20); contentLayout.setPadding(new Insets(20)); contentLayout.setAlignment(Pos.CENTER); // 创建网格布局用于表单 GridPane gridPane = new GridPane(); gridPane.setHgap(10); gridPane.setVgap(10); gridPane.setAlignment(Pos.CENTER); // 文件选择组件 Label fileLabel = new Label("选择文件:"); fileField = new TextField(); fileField.setPromptText("请选择文件..."); fileField.setPrefWidth(300); Button fileButton = new Button("浏览"); // 文件夹选择组件 Label folderLabel = new Label("选择文件夹:"); folderField = new TextField(); folderField.setPromptText("请选择文件夹..."); folderField.setPrefWidth(300); Button folderButton = new Button("浏览"); // 进度条组件 progressBar = new ProgressBar(0); progressBar.setPrefWidth(300); progressBar.setVisible(false); // 进度标签 progressLabel = new Label("准备开始..."); progressLabel.setVisible(false); // 开始按钮 Button startButton = new Button("开始验证"); startButton.setPrefWidth(150); startButton.setPrefHeight(40); // 设置按钮事件 fileButton.setOnAction(e -> chooseFile()); folderButton.setOnAction(e -> chooseFolder()); startButton.setOnAction(e -> startVerification()); // 添加到网格布局 gridPane.add(fileLabel, 0, 0); gridPane.add(fileField, 1, 0); gridPane.add(fileButton, 2, 0); gridPane.add(folderLabel, 0, 1); gridPane.add(folderField, 1, 1); gridPane.add(folderButton, 2, 1); // 添加到内容布局 contentLayout.getChildren().addAll(gridPane, progressLabel, progressBar, startButton); mainLayout.setCenter(contentLayout); // 创建场景并显示 Scene scene = new Scene(mainLayout, 500, 400); primaryStage.setScene(scene); primaryStage.show(); } private MenuBar createMenuBar() { MenuBar menuBar = new MenuBar(); // 创建帮助菜单 Menu helpMenu = new Menu("帮助"); // 创建关于菜单项 MenuItem aboutMenuItem = new MenuItem("关于"); aboutMenuItem.setOnAction(e -> showAboutDialog()); helpMenu.getItems().add(aboutMenuItem); menuBar.getMenus().add(helpMenu); return menuBar; } private void showAboutDialog() { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("关于"); alert.setHeaderText("金额验证工具"); alert.setContentText("作者: 杨逸\n" + "联系方式: huanglve2004@163.com\n\n" + "版本: 1.0.0\n" + "描述: 用于金额验证的桌面应用程序"); alert.showAndWait(); } private void showCloseConfirmation(Stage stage) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("确认关闭"); alert.setHeaderText("您确定要关闭应用程序吗?"); alert.setContentText("如果正在执行验证操作,关闭将中断该过程。"); Optional result = alert.showAndWait(); if (result.isPresent() && result.get() == ButtonType.OK) { stage.close(); } } private void chooseFile() { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("选择文件"); // 添加文件过滤器,只允许选择xlsx文件 FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter( "Excel文件 (*.xlsx)", "*.xlsx"); fileChooser.getExtensionFilters().add(extFilter); File selectedFile = fileChooser.showOpenDialog(null); if (selectedFile != null) { fileField.setText(selectedFile.getAbsolutePath()); } } private void chooseFolder() { DirectoryChooser directoryChooser = new DirectoryChooser(); directoryChooser.setTitle("选择文件夹"); File selectedFolder = directoryChooser.showDialog(null); if (selectedFolder != null) { folderField.setText(selectedFolder.getAbsolutePath()); } } /** * 更新进度条和进度标签 * @param message 进度消息 * @param progress 进度值 (0.0 - 1.0) */ private void updateProgress(String message, double progress) { javafx.application.Platform.runLater(() -> { progressLabel.setText(message); progressBar.setProgress(progress); }); } private void startVerification() { String filePath = fileField.getText(); String folderPath = folderField.getText(); System.out.println("filePath = " + filePath); System.out.println(folderPath); if (filePath.isEmpty() || folderPath.isEmpty()) { Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("请选择文件和文件夹"); alert.showAndWait(); return; } // 初始化进度条 progressBar.setProgress(0); progressBar.setVisible(true); progressLabel.setVisible(true); updateProgress("准备开始验证...", 0); inputModelList = new ArrayList<>(); outputModelList = new ArrayList<>(); pdfFileMap = new HashMap<>(); List errorImeiList = new ArrayList<>(); // 读取excel updateProgress("正在读取Excel文件...", 0.1); EasyExcel.read(filePath, InputModel.class, new PageReadListener(dataList -> { for (InputModel inputModel : dataList) { inputModelList.add(inputModel); } })).sheet().doRead(); updateProgress("Excel文件读取完成,正在扫描文件夹...", 0.25); //读取文件夹 File folder = new File(folderPath); File[] files = folder.listFiles(); // 扫描文件夹并建立IMEI-PDF映射 int totalFolders = files.length; int processedFolders = 0; for (File file : files) { if (file.isFile()) { continue; } File[] listFiles = file.listFiles(); String imei = file.getName().split("-")[2]; //拿到文件夹里的pdf for (File pdfFile : listFiles) { if (pdfFile.getName().endsWith(".pdf")) { if (pdfFileMap.containsKey(imei)) { //出现重复的imei Alert alert = new Alert(Alert.AlertType.ERROR); alert.setHeaderText("出现重复的imei"); alert.setContentText("请检查文件夹中是否出现重复的imei:" + imei); alert.showAndWait(); return; } pdfFileMap.put(imei, pdfFile); break; } } processedFolders++; double progress = 0.25 + (0.25 * processedFolders / totalFolders); updateProgress("正在扫描文件夹: " + processedFolders + "/" + totalFolders, progress); } updateProgress("文件夹扫描完成,开始解析PDF文件...", 0.5); // 解析PDF文件 int totalPDFs = inputModelList.size(); int processedPDFs = 0; for (InputModel inputModel : inputModelList) { OutputModel outputModel = new OutputModel(inputModel); String imei = inputModel.getImei(); //找到对应pdf的文件路径 File pdfFile = pdfFileMap.getOrDefault(imei, null); if (Objects.isNull(pdfFile)) { errorImeiList.add(imei); processedPDFs++; double progress = 0.5 + (0.4 * processedPDFs / totalPDFs); updateProgress("解析PDF文件: " + processedPDFs + "/" + totalPDFs + " (IMEI未找到: " + imei + ")", progress); continue; } //解析pdf String text = ""; try (PDDocument pdDocument = Loader.loadPDF(pdfFile)) { PDFTextStripper textStripper = new PDFTextStripper(); //提取文本 text = textStripper.getText(pdDocument); //解析金额 Matcher matcher = pattern.matcher(text); if (matcher.find()) { String money = matcher.group("money"); // 获取命名分组 "money" //System.out.println("金额: " + money); // 输出: 金额 BigDecimal amount1 = new BigDecimal(inputModel.getAmount()); BigDecimal amount2 = new BigDecimal(money); outputModel.setPdfAmount(amount2.doubleValue()); outputModel.setMargin(amount1.subtract(amount2).doubleValue()); } else { System.out.println("未匹配到金额"); errorImeiList.add(imei); } } catch (IOException | NumberFormatException e) { e.printStackTrace(); errorImeiList.add(imei); } outputModelList.add(outputModel); processedPDFs++; double progress = 0.5 + (0.4 * processedPDFs / totalPDFs); updateProgress("解析PDF文件: " + processedPDFs + "/" + totalPDFs, progress); } updateProgress("PDF文件解析完成,正在生成输出文件...", 0.9); //输出最终文件 String outputFileName = filePath.substring(0, filePath.lastIndexOf(".")) + "_" + System.currentTimeMillis() + "_output.xlsx"; EasyExcel.write(outputFileName, OutputModel.class).sheet("模板").doWrite(outputModelList); updateProgress("验证完成!输出文件: " + outputFileName, 1.0); // 显示完成信息 javafx.application.Platform.runLater(() -> { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle("验证完成"); alert.setHeaderText("金额验证已完成"); alert.setContentText("输出文件已生成: " + outputFileName + (errorImeiList.isEmpty() ? "" : "\n\n以下IMEI处理失败: " + String.join(", ", errorImeiList))); alert.showAndWait(); // 隐藏进度条 progressBar.setVisible(false); progressLabel.setVisible(false); }); inputModelList = null; outputModelList = null; pdfFileMap = null; } }