我的 TicketDesk 系统

发布: (2026年1月19日 GMT+8 19:36)
8 min read
原文: Dev.to

Source: Dev.to

介绍

在我的 Intro to Programming 课程中,我用 Java 制作了一个 TicketDesk 系统,它可以:

  • 跟踪工单
  • 跟踪登录信息
  • 提供基于角色的认证系统

本开发日志探讨了我所面对的主要功能和挑战,并提供了我认为值得一提的关键点的有用注释。

程序简要描述

TicketDesk 系统的主要目标是将用户划分到不同的角色中,每个角色在使用工单台时会获得不同的体验:

Role功能
Admin删除工单,管理账户
User创建和管理工单(不包括账户管理)
Guest仅读取工单,信息受限

下面我将解释该程序的三个关键特性。

功能 1:用户输入

程序依赖用户输入来在系统中进行导航。用户不断进行菜单选择并输入数据,以便记录工单。

  • 我主要使用 Scanner 类,因为它比 BufferedReader 更简单,后者需要处理受检的 IOException
  • Main 类中将 scanner 变量声明为 private,因为它仅在该类内部读取。
private static Scanner sc = new Scanner(System.in);
int choice = Integer.parseInt(sc.nextLine());

通过 Scanner 捕获的输入驱动了工单窗口的控制流程:

  • 整数 用于导航菜单。
  • 字符串 用于填充工单字段,如标题和描述。

参考资料:
Scanner is skipping nextLine after using next/nextFoo – Stack Overflow

Source:

功能 2:方法

方法将功能拆分为可重用的部分,并允许在不同类(TicketManagerAuthenticationMain)之间引用代码。

示例 – 创建工单(对用户和管理员均可用)

// method for creating tickets, for only users and admins
public void createTicket(Person loggedIn, Scanner sc) {
    loadTickets();
    if (loggedIn.isGuest()) { // if the user is a guest
        System.out.println("Unauthorised to create tickets. Returning to main menu...");
        return;
    }
    String title = getInput("Enter the ticket title (or 'CANCEL' to go back): ", sc);
    // ... additional logic ...
}
  • createTicket() 方法将工单创建逻辑集中起来,避免代码重复。
  • 权限检查在方法内部完成,菜单只需调用一次即可。

参考:
How to apply the Single Responsibility Principle in Java – TheServerSide

反思:
该方法目前同时处理加载工单和检查权限,这意味着它并未完全遵循单一职责原则。未来的工作中,我会将这些关注点分离,以使方法更加可重用。

Feature 3: 面向对象编程

OOP 被广泛使用,尤其是在认证方面。系统定义了三种用户角色——guest、user、admin——每个角色都有自己的菜单和可访问的功能。

类结构

public class Person {
    // private fields for better encapsulation (getters and setters used)
    private String username;
    private String password;
    private String role;

    public Person(String username, String password, String role) {
        this.username = username;
        this.password = password;
        this.role = role;
    }
    // getters / setters omitted for brevity
}
public class Admin extends Person {
    // constructor for admin class
    public Admin(String username, String password) {
        super(username, password, "admin");
    }
}
  • 封装: 字段是私有的;通过 getter/setter 提供访问。
  • 继承: Admin(以及 UserGuest)继承自 Person

本项目中 OOP 的优势

  1. 灵活性: 添加新角色只需创建一个新的子类;无需重写已有逻辑。
  2. 可读性: 票务信息存放在专用的 Ticket 类中,使代码直观易懂。
  3. 层次结构: 权限自然映射为继承关系(admin > user > guest),展示了封装和继承。

参考资料:

遇到的问题

问题 1 – 分隔符输入

当管理员或用户创建或修改工单时,在任何字段(例如标题)中输入逗号 (,) 会导致显示错误,因为程序把逗号当作数据分隔符。

解决方案 – 一个帮助方法,用于拒绝逗号和空输入:

// very useful helper method to stop users from typing commas in the fields,
// as well as empty inputs
private String getInput(String prompt, Scanner sc) {
    while (true) {
        System.out.println(prompt);
        String userInput = sc.nextLine();

        if (userInput.contains(",")) {
            System.out.println("Commas cannot be entered! Please try again.");
        } else if (userInput.trim().isEmpty()) {
            System.out.println("Input cannot be empty, try again.");
        } else {
            return userInput;
        }
    }
}
  • 在所有需要用户输入的地方调用该方法(例如编辑工单字段)。
  • 如果检测到逗号,循环会重新执行并再次提示。
  • 同时阻止空字符串,强制用户提供有效值。

通过在各处使用 getInput(),程序不再因意外的逗号而崩溃。

问题 2 – 控制台输出溢出

在显示大型列表(所有工单、所有账户等)时,控制台会立即返回菜单,导致信息在屏幕上滚动消失,用户来不及阅读。

解决方案 – 在用户按 ENTER 之前暂停输出:

System.out.println("\n========== Limited Ticket View ============");
for (int i = 0; i < ticketList.size(); i++) {
    Ticket t = ticketList.get(i);
    // formatted manually so it only displays these fields
    System.out.println("ID: " + t.getTicketId()
            + " | Title: " + t.getTitle()
            + " | Status: " + t.getStatus()
            + " | Tag: " + t.getTag());
}
System.out.println("==============================================");

System.out.println("\nTap ENTER to continue.."); // prevents immediate return to menu
sc.nextLine();
  • 该提示强制用户在菜单重新出现前确认已阅读输出。
  • 在列出待删除用户时同样有效,给管理员留出查找正确账户的时间。

在 GUI 中这通常会自动处理,但对于基于控制台的应用来说,这个暂停显著提升了在不同 IDE 中的可用性。

问题 3 – 未找到工单文件

如果工单存储文件 (ticketlist.txt) 缺失或放在错误目录,程序会因无法加载或保存工单而崩溃。

解决方案 – 当文件不存在时自动创建:

if (!myFile.exists()) {
    // You can also add your own files directly; they must be formatted
    // the same way as ticketlist.txt.
    System.out.println("There is currently no file to load tickets from... "
            + "A new file has been created called " + filename + " !");
    try {
        myFile.createNewFile();
        System.out.println("The file ticketlist.txt has now been created!");
        return;
    } catch (IOException e) { // need to handle this checked exception
        System.out.println("Error creating file, returning to main menu... "
                + e.getMessage());
        return;
    }
}
  • 当创建新文件后,系统会报告 “已加载 0 条工单”,管理员可以根据需要手动编辑该文件。
  • 这避免了因缺失文件导致整个应用程序中断。

结束语

这些三个问题——分隔符处理、控制台溢出以及缺失文件保护——代表了我在构建工单系统时所面对的主要挑战。解决它们使代码:

  • 更易读,便于其他开发者阅读。
  • 更可靠,能够处理可能导致崩溃的边缘情况。

感谢阅读!

Back to Blog

相关文章

阅读更多 »

Java 多线程/并发

什么是 Java 中的多线程?Java 中的多线程是一项功能,允许程序的两个或多个部分(称为 thread)并发执行,……