我的 TicketDesk 系统
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:方法
方法将功能拆分为可重用的部分,并允许在不同类(TicketManager、Authentication、Main)之间引用代码。
示例 – 创建工单(对用户和管理员均可用)
// 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(以及User、Guest)继承自Person。
本项目中 OOP 的优势
- 灵活性: 添加新角色只需创建一个新的子类;无需重写已有逻辑。
- 可读性: 票务信息存放在专用的
Ticket类中,使代码直观易懂。 - 层次结构: 权限自然映射为继承关系(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 条工单”,管理员可以根据需要手动编辑该文件。
- 这避免了因缺失文件导致整个应用程序中断。
结束语
这些三个问题——分隔符处理、控制台溢出以及缺失文件保护——代表了我在构建工单系统时所面对的主要挑战。解决它们使代码:
- 更易读,便于其他开发者阅读。
- 更可靠,能够处理可能导致崩溃的边缘情况。
感谢阅读!