You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fat Jar运行提示找不到主类org.example.Main的问题求助

Fat Jar运行提示找不到主类org.example.Main的问题求助

我用IntelliJ打包了一个Fat Jar,但运行的时候总是提示找不到主类,报错信息如下:

HappyBirthdayWisher\build\libs>java -jar HappyBirthdayWisher-1.0-SNAPSHOT.jar
Error: Could not find or load main class org.example.Main
Caused by: java.lang.ClassNotFoundException: org.example.Main

HappyBirthdayWisher\build\libs>java -cp HappyBirthdayWisher-1.0-SNAPSHOT.jar org.example.Main
Error: Could not find or load main class org.example.Main
Caused by: java.lang.ClassNotFoundException: org.example.Main

我特意检查了Jar包内部的文件结构,org.example.Main对应的Main.class文件确实存在于正确的包路径下。

我的Manifest文件内容如下:

Manifest-Version: 1.0
Main-Class: org.example.Main

真的搞不懂哪里出问题了,希望大家能帮我排查一下!


编辑补充:

  1. 我整理了Jar包的完整文件列表(内容较多)。
  2. 以下是我的原始Main类代码:
package org.example;

import io.github.cdimascio.dotenv.Dotenv;
import org.apache.poi.ss.usermodel.*;
import org.example.email.EmailSender;
import org.example.entity.Employee;
import org.example.mappings.TemplateMappings;
import org.example.thymeleaf.ThymeleafTemplateEngine;
import org.example.utils.AzureBlobUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.mail.MessagingException;
import java.io.*;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

    public static void main(String[] args) throws MessagingException {
        Dotenv dotenv = Dotenv.load();
        String employeeInfoFileName = "birthdayWisherFiles/Employee Sample Data.xlsx";
        String imageOrderFileName = "birthdayWisherFiles/logicFiles/birthday_image_order.txt";
        String emailSentLogFileName = "birthdayWisherFiles/logicFiles/email_sent_log.txt";
        String imageCounterFileName = "birthdayWisherFiles/logicFiles/image_counter.txt";
        String birthDateColumn = "Birth Date";
        String fullNameColumn = "Full Name";
        String emailColumn = "Email";
        // Azure Blob Storage SAS Token URL
        String azureBlobUrl = dotenv.get("AZURE_BLOB_URL");
        // Get today's month and day
        MonthDay todayMonthDay = MonthDay.now();
        Month currentMonth = todayMonthDay.getMonth();
        try {
            // Get the birthday havers of the day
            List<Employee> employees = getTodaysBirthdayHavers(azureBlobUrl,employeeInfoFileName, birthDateColumn, fullNameColumn, emailColumn, todayMonthDay);
            // Fetch and save image order if needed
            List<String> imageFileNames = getOrUpdateImageOrder(imageOrderFileName, azureBlobUrl, currentMonth);
            System.out.println("Employees with birthdays today: " + employees);
            if (employees.isEmpty()) {
                System.out.println("No birthdays today.");
                return;
            }
            if (imageFileNames.isEmpty()) {
                System.out.println("No images found in Azure Blob Storage.");
                return;
            }
            // Initialize Thymeleaf template engine
            TemplateEngine templateEngine = ThymeleafTemplateEngine.initializeTemplateEngine();
            // Load or initialize the image counter
            int[] imageCounter = loadImageCounter(azureBlobUrl,imageCounterFileName);

            // Save into the list to later log it to a file
            List<String> emailsSent = new ArrayList<>();
            // Send email to each employee
            for (Employee employee : employees) {
                // Get image for employee according to the current image order
                String selectedImage = getImageForEmail(imageFileNames, imageCounter);
                //increment the counter after getting the image
                incrementImageCounter(imageCounter,imageFileNames);
                String fileNameWithoutExtension = selectedImage.substring(selectedImage.lastIndexOf("/") + 1, selectedImage.lastIndexOf("."));
                String templateName = determineTemplate(fileNameWithoutExtension);
                // Create the Thymeleaf context and render the appropriate template
                assert azureBlobUrl != null;
                String selectedImageURl = AzureBlobUtils.getAzureBlobImageUrl(azureBlobUrl,selectedImage);
                Context context = ThymeleafTemplateEngine.createContext(selectedImageURl,employee.getFullName());
                String htmlContent = ThymeleafTemplateEngine.renderTemplate(templateEngine, templateName, context);

                String recipient = employee.getEmail();
                String subject = "Happy Birthday, " + employee.getFullName() + "!";

                // Send the email
                EmailSender.sendEmail(recipient, subject, htmlContent);

                // add to the list the emails with a timestamp
                saveEmailSentToList(employee.getFullName(),recipient,selectedImage, emailsSent);
            }
            // Append the list to file
            appendEmailSentListToFile(azureBlobUrl,emailSentLogFileName, emailsSent);
            // Save the updated image counter
            saveImageCounterToFile(azureBlobUrl,imageCounterFileName, imageCounter[0]);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //Excel stuffs
    private static List<Employee> getTodaysBirthdayHavers(String blobURL, String filePath, String birthDateColumn,
                                                          String fullNameColumn, String emailColumn, MonthDay todayMonthDay) throws IOException {
        try (InputStream inputStream = AzureBlobUtils.getFileInputStream(blobURL, filePath);
             Workbook workbook = WorkbookFactory.create(inputStream)) {

            Sheet sheet = workbook.getSheetAt(0); // Get the first sheet
            if (sheet == null) {
                System.out.println("No sheets found in the workbook.");
                return new ArrayList<>();
            }

            int birthDateColumnIndex = findColumnIndex(sheet, birthDateColumn);
            int fullNameColumnIndex = findColumnIndex(sheet, fullNameColumn);
            int emailColumnIndex = findColumnIndex(sheet, emailColumn);

            if (birthDateColumnIndex == -1 || fullNameColumnIndex == -1 || emailColumnIndex == -1) {
                System.out.println("One or more required columns not found.");
                return new ArrayList<>();
            }

            return getMatchingEmployees(sheet, birthDateColumnIndex, fullNameColumnIndex, emailColumnIndex, todayMonthDay);
        }
    }

    private static int findColumnIndex(Sheet sheet, String targetColumn) {
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            return -1;
        }

        for (Cell cell : headerRow) {
            if (cell.getCellType() == CellType.STRING && targetColumn.equals(cell.getStringCellValue())) {
                return cell.getColumnIndex();
            }
        }

        return -1;
    }

    private static List<Employee> getMatchingEmployees(Sheet sheet, int birthDateColumnIndex, int fullNameColumnIndex, int emailColumnIndex, MonthDay todayMonthDay) {
        List<Employee> employees = new ArrayList<>();

        for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
            Row row = sheet.getRow(rowIndex);
            if (row != null) {
                Cell birthDateCell = row.getCell(birthDateColumnIndex);
                Cell fullNameCell = row.getCell(fullNameColumnIndex);
                Cell emailCell = row.getCell(emailColumnIndex);

                if (birthDateCell != null && isDateCell(birthDateCell)) {
                    LocalDate birthDate = convertToLocalDate(birthDateCell.getDateCellValue());
                    MonthDay birthMonthDay = MonthDay.from(birthDate);

                    if (birthMonthDay.equals(todayMonthDay)) {
                        String fullName = fullNameCell != null ? fullNameCell.getStringCellValue() : "Unknown";
                        String email = emailCell != null ? emailCell.getStringCellValue() : "Unknown";
                        employees.add(new Employee(fullName, email, birthDate));
                    }
                }
            }
        }

        return employees;
    }

    private static boolean isDateCell(Cell cell) {
        return cell.getCellType() == CellType.NUMERIC && DateUtil.isCellDateFormatted(cell);
    }

    private static LocalDate convertToLocalDate(java.util.Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    private static List<String> getOrUpdateImageOrder(String imageOrderFileName,
                                                      String azureBlobUrl,
                                                      Month currentMonth) throws IOException {
        String fileContent = AzureBlobUtils.readTextFileFromBlob(azureBlobUrl, imageOrderFileName);
        List<String> fileNames;

        if (fileContent != null && !fileContent.isEmpty()) {
            // Split the string into lines
            List<String> lines = new ArrayList<>(List.of(fileContent.split("\\R"))); // "\\R" matches line breaks

            if (!lines.isEmpty() && Month.valueOf(lines.get(0).toUpperCase()).equals(currentMonth)) {
                fileNames = lines.subList(1, lines.size());
            } else {
                // 重新获取并生成图片顺序
                fileNames = AzureBlobUtils.listBlobFiles(azureBlobUrl, "birthdayImages/" + currentMonth.name().toLowerCase());
                Collections.shuffle(fileNames);
                // 写入文件
                StringBuilder sb = new StringBuilder();
                sb.append(currentMonth.name()).append("\n");
                for (String fileName : fileNames) {
                    sb.append(fileName).append("\n");
                }
                AzureBlobUtils.writeTextFileToBlob(azureBlobUrl, imageOrderFileName, sb.toString());
            }
        } else {
            // 文件为空或不存在,重新获取并生成图片顺序
            fileNames = AzureBlobUtils.listBlobFiles(azureBlobUrl, "birthdayImages/" + currentMonth.name().toLowerCase());
            Collections.shuffle(fileNames);
            // 写入文件
            StringBuilder sb = new StringBuilder();
            sb.append(currentMonth.name()).append("\n");
            for (String fileName : fileNames) {
                sb.append(fileName).append("\n");
            }
            AzureBlobUtils.writeTextFileToBlob(azureBlobUrl, imageOrderFileName, sb.toString());
        }
        return fileNames;
    }

    // 以下为未完整展示的方法占位(原代码截断)
    private static int[] loadImageCounter(String azureBlobUrl, String imageCounterFileName) throws IOException {
        // 业务逻辑实现
        return new int[]{0};
    }

    private static String getImageForEmail(List<String> imageFileNames, int[] imageCounter) {
        // 业务逻辑实现
        return imageFileNames.get(imageCounter[0] % imageFileNames.size());
    }

    private static void incrementImageCounter(int[] imageCounter, List<String> imageFileNames) {
        imageCounter[0] = (imageCounter[0] + 1) % imageFileNames.size();
    }

    private static String determineTemplate(String fileNameWithoutExtension) {
        // 业务逻辑实现
        return TemplateMappings.getTemplateName(fileNameWithoutExtension);
    }

    private static void saveEmailSentToList(String fullName, String recipient, String selectedImage, List<String> emailsSent) {
        // 业务逻辑实现
        emailsSent.add(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + " - " + fullName + " <" + recipient + "> - 使用图片:" + selectedImage);
    }

    private static void appendEmailSentListToFile(String azureBlobUrl, String emailSentLogFileName, List<String> emailsSent) throws IOException {
        // 业务逻辑实现
        StringBuilder sb = new StringBuilder();
        for (String entry : emailsSent) {
            sb.append(entry).append("\n");
        }
        AzureBlobUtils.appendTextToBlob(azureBlobUrl, emailSentLogFileName, sb.toString());
    }

    private static void saveImageCounterToFile(String azureBlobUrl, String imageCounterFileName, int counter) throws IOException {
        // 业务逻辑实现
        AzureBlobUtils.writeTextFileToBlob(azureBlobUrl, imageCounterFileName, String.valueOf(counter));
    }
}

备注:内容来源于stack exchange,提问作者Nguyễn Nam Vinh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 10:03:08