任务描述
编写一个控制台程序,模拟公交查询系统。
本项目主要有4个功能:线路查询、站点查询、换乘查询和后台管理。
(1)线路查询:获得需要查询的公交的信息。
(2)站点查询:获得通过输入的经过该站点的指公交信息。
(3)换乘查询:判断公交直达或公交一次换乘,并获得所有换乘方法。
(4)后台管理:管理员登录,添加、删除、修改公交线路功能。
程序需要存储各公交线路站点信息,这里采用文件存储线路信息,形式如下:
1s%……站%……站%……站%6:00-18:00 票价1元 ABCD卡有效
1x%……站%……站%……站%6:00-18:00 票价1元 ABCD卡有效
……
其中1s为上行,1x为下行,站点信息之间使用“%”分割。
需求分析
公交查询系统需要对公交线路信息文件进行提取并存储,创建类busInformation,成员变量包括route、station、time、price、card和相应的get方法和set方法。由类busEnquirySystem实现用户端功能,成员方法包括main、transform、getBusInformation、exist、routeInquiry、stationInquiry、transferInquiry。由类backEndManagement实现后台端管理员功能,成员方法包括Main、exist、findLineNumber、addBusInformation、updateBusInformation、deleteBusInformation。
设计思路
公交查询系统首先将公交线路信息文件中的数据分割提取,然后使用ArrayList存储,用户端功能对ArrayList进行操作,而后台端管理员功能直接对文件进行操作。
对公交线路信息文件中的数据分割提取并使用ArrayList存储,创建类busInformation包含路线号、站点名、路线时间、路线票价、路线公交卡,存储于ArrayList中,其中站点名由AraayList存储。
用户端功能由类busEnquirySystem中的成员方法实现,包含用户端功能操作界面,各成员方法对公交线路信息的操作均为对ArrayList的操作,并且可以跳转到后台端管理员功能操作界面。包含成员方法如下:
(1)main创建ArrayList,使用while循环实现控制台程序,模拟用户端功能操作,分别调用方法transform、getBusInformation、exist、routeInquiry、stationInquiry、transferInquiry以及退出程序和输入错误的处理。
(2)transform创建输入流并提取文件的每一行,然后将busInformation对象存储于ArrayList中。
(3)getBusInformation将提取的文件的每一行进行分割,并将分割后的内容转换为字符串,然后将这些字符串存放在数组中,创建并存储于busInformation对象中。
(4)exist使用循环遍历判断公交线路信息是否存在,是否重复。
(5)routeInquiry线路查询。接收并判断公交线路号,循环遍历获得要查询的公交线路的信息。
(6)stationInquiry站点查询。接收并判断公交线路站点,循环遍历指定站点查询经过该站点的所有公交线路。
(7)transferInquiry换乘查询。接收并判断公交线路起点和终点,判断直达与公交一次换乘,并输出相应线路。
后台端管理员功能由类backEndManagement中的成员方法实现,包含管理员账号密码验证和后台端管理员功能操作界面,各成员方法对公交线路信息的操作均为对文件的操作。包含成员方法如下:
(1)Main使用while循环实现控制台程序,模拟后台端管理员功能操作,分别调用方法Main、exist、findLineNumber、addBusInformation、updateBusInformation、deleteBusInformation以及退出程序和输入错误的处理。
(2)exist使用循环遍历判断公交线路信息是否存在,是否重复。
(3)findLineNumber使用循环遍历判断公交线路信息的文件行号。
(4)addBusInformation添加公交线路。接收并判断公交线路号和公交线路信息,将输入内容写入文件。
(5)updateBusInformation修改公交线路。接收并判断公交线路号和公交线路信息,修改文件某一行,将文件信息按行拆分进行操作,然后将修改后的内容写回文件。
(6)deleteBusInformation删除公交线路。接收并判断公交线路号,将文件信息按行拆分进行操作,删除文件某一行,然后将修改后的内容写回文件。
实现过程
(1)对公交路线信息进行抽象建类
import java.util.ArrayList;
public class busInformation {
//线路
public String route;
//站点
public ArrayList<String> station;
//ArrayList类是一个可以动态修改的数组,没有固定大小的限制,继承了AbstractList并实现了List接口
//时间
public String time;
//价格
public String price;
//卡
public String card;
//get与set方法
public String getRoute() { return route; }
public void setRoute(String route) { this.route = route; }
public ArrayList<String> getStation() { return station; }
public void setStation(ArrayList<String> station) { this.station = station; }
public String getTime() { return time; }
public void setTime(String time) { this.time = time; }
public String getPrice() { return price; }
public void setPrice(String price) { this.price = price; }
public String getCard() { return card; }
public void setCard(String card) { this.card = card; }
}
(2)用户端功能
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.Scanner;
public class busEnquirySystem {
public static void main(String[] args) throws IOException {
//throws IOException是Java中的异常声明,表示该方法可能会抛出IOException异常
//当调用此方法时,如果发生I/O错误,程序将抛出该异常并终止执行
//初始化公交信息文件中的数据
//使用ArrayList存储公交信息
ArrayList<busInformation> arrayList = transform();
//使用while循环实现控制台程序,模拟用户端功能操作,调用功能方法
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("---------欢迎使用公交查询系统---------");
System.out.println("----------请选择您需要的操作----------");
System.out.println("-------------1.线路查询-------------");
System.out.println("-------------2.站点查询-------------");
System.out.println("-------------3.换乘查询-------------");
System.out.println("-------------4.后台管理-------------");
System.out.println("---------------5.退出--------------");
int choice = scanner.nextInt();
switch (choice) {
case 1 -> routeInquiry(arrayList);
case 2 -> stationInquiry(arrayList);
case 3 -> transferInquiry(arrayList);
case 4 -> {
backEndManagement.Main();
//当管理员对文件进行修改后重新始化公交信息文件中的数据
arrayList = transform();
}
case 5 -> {
System.out.println("感谢使用!");
System.exit(0);
//终止当前运行的Java虚拟机,参数0表示正常退出,非零值表示异常退出
}
default -> System.out.println("输入数据不符合要求,请重新输入!");
}
}
}
//将公交信息文件中的数据拆分分割转化为busInformation实例并存放在ArrayList数组中
public static ArrayList<busInformation> transform() throws IOException {
ArrayList<busInformation> arrayList = new ArrayList<>();
//创建输入流
String filePath = "src/bus/busInformation.txt";
//文件路径
FileInputStream fileInputStream = new FileInputStream(filePath);
//FileInputStream用于从文件系统中的某个文件中读取字节
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "GBK");
//InputStreamReader用于将字节数据转换为字符数据,可指定文件编码
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//BufferedReader是用于从字符输入流中读取文本
//提取文件每一行
String line;
while ((line = bufferedReader.readLine()) != null) {
//readLine用于从输入流中读取一行文本
arrayList.add(getBusInformation(line));
}
return arrayList;
}
public static busInformation getBusInformation(String line) {
busInformation busInformation = new busInformation();
//将每一行按照空格或“%”字符进行分割,并将分割后的内容转换为字符串,然后将这些字符串存放在数组中
String[] split = line.split("[ %]+");
busInformation.setRoute(split[0]);
ArrayList<String> setStation = new ArrayList<>(Arrays.asList(Arrays.copyOfRange(split, 1, split.length - 3)));
busInformation.setStation(setStation);
busInformation.setTime(split[split.length - 3]);
busInformation.setPrice(split[split.length - 2]);
busInformation.setCard(split[split.length - 1]);
return busInformation;
}
//判断存在
public static int exist(ArrayList<busInformation> array, String route) {
int exist = 0;
//此公交路线路不存在
//使用线路号进行判断
for (busInformation i :array) {
if (Objects.equals(i.getRoute(), route)) {
//Objects.equals()用于比较两个对象是否相等
exist = 1;
//此公交路线路存在
break;
}
//使用站点进行判断
for (String j : i.getStation()) {
if (Objects.equals(j, route)) {
exist = 1;
//此公交路线路存在
break;
}
}
}
return exist;
}
//线路查询:获得需要查询的公交的信息
public static void routeInquiry(ArrayList<busInformation> array) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入需要查询的公交路线号:");
String route = scanner.next();
if (exist(array, route) == 0) {
System.out.println("公交路线号不存在,请重新操作!");
} else {
for (busInformation i : array) {
if (Objects.equals(i.getRoute(), route)) {
System.out.println("站点:" + i.getStation());
System.out.println("时间:" + i.getTime());
System.out.println("票价:" + i.getPrice());
System.out.println("公交卡:" + i.getCard());
}
}
}
}
//站点查询:获得通过输入的经过该站点的指公交信息
public static void stationInquiry(ArrayList<busInformation> array) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入需要查询的公交站点名:");
String station = scanner.next();
if (exist(array, station) == 0) {
System.out.println("公交站点名不存在,请重新操作!");
} else {
for (busInformation i : array) {
for (String j : i.getStation()) {
if (Objects.equals(j, station)) {
System.out.println("路线号:" + i.getRoute());
System.out.println("站点:" + i.getStation());
System.out.println("时间:" + i.getTime());
System.out.println("票价:" + i.getPrice());
System.out.println("公交卡:" + i.getCard());
}
}
}
}
}
//换乘查询:判断公交直达或公交一次换乘,并获得所有换乘方法
public static void transferInquiry(ArrayList<busInformation> array) {
//起点
Scanner scanner1 = new Scanner(System.in);
//终点
Scanner scanner2 = new Scanner(System.in);
//存储同时存在起点与终点的线路,直达相关
ArrayList<String> route = new ArrayList<>();
//存储存在起点的线路的站点
ArrayList<busInformation> stations1 = new ArrayList<>();
//存储存在终点的线路的站点
ArrayList<busInformation> stations2 = new ArrayList<>();
//存储一次换乘的线路方法
ArrayList<String> stations = new ArrayList<>();
//标记区分直达和一次换乘
boolean transferInquiry = false;
//公交一次换乘
System.out.print("请输入起点的公交站点名:");
String station1 = scanner1.next();
if (exist(array, station1) == 0) {
System.out.println("公交路线号不存在,请重新操作!");
} else {
System.out.print("请输入终点的公交站点名:");
String station2 = scanner2.next();
if (exist(array, station2) == 0) {
System.out.println("公交路线号不存在,请重新操作!");
} else {
for (busInformation i : array) {
if (i.getStation().contains(station1) && i.getStation().contains(station2)) {
//contains用于检查一个字符串是否包含另一个字符串
transferInquiry = true;
//公交直达
route.add(i.getRoute());
break;
}
}
if (transferInquiry) {
System.out.println("直达线路:");
System.out.println(route);
}
if (! transferInquiry) {
for (busInformation i : array) {
for (String j : i.getStation()) {
if (Objects.equals(j, station1)) {
stations1.add(i);
}
}
}
for (busInformation i : array) {
for (String j : i.getStation()) {
if (Objects.equals(j, station2)) {
stations2.add(i);
}
}
}
for (busInformation i : stations1) {
for (String j : i.getStation()) {
for (busInformation k : stations2) {
for (String l : k.getStation()) {
if (Objects.equals(j, l)) {
String way = i.getRoute() + "转" + k.getRoute();
if (!stations.contains(way)) {
stations.add(way);
}
}
}
}
}
}
System.out.println("换乘线路:");
for (int i = 0; i < stations.size(); i++) {
System.out.println("方案" + (i + 1) + ":" + stations.get(i));
}
}
}
}
}
}
(3)后台端管理员功能
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import static bus.busEnquirySystem.transform;
public class backEndManagement {
public static void Main() throws IOException {
//管理员登录
Scanner scanner = new Scanner(System.in);
System.out.println("---------欢迎使用公交查询系统后台管理系统---------");
System.out.println("-----------------请进行登录-------------------");
System.out.print("请输入管理员账号:");
int id = scanner.nextInt();
if (id == 12345) {
System.out.print("请输入管理员密码:");
int password = scanner.nextInt();
if (password == 12345) {
System.out.println("登录成功,欢迎使用!");
} else {
System.out.println("输入密码错误,请重新操作!");
return;
}
} else {
System.out.println("输入账号错误,请重新操作!");
return;
}
while (true) {
System.out.println("---------欢迎使用公交查询系统后台管理系统---------");
System.out.println("--------------请选择您需要的操作---------------");
System.out.println("-----------------1.添加线路------------------");
System.out.println("-----------------2.修改线路------------------");
System.out.println("-----------------3.删除线路------------------");
System.out.println("-------------------4.退出-------------------");
int choice = scanner.nextInt();
switch (choice) {
case 1 -> addBusInformation();
case 2 -> updateBusInformation();
case 3 -> deleteBusInformation();
case 4 -> {
System.out.println("感谢使用!");
return;
}
default -> System.out.println("输入数据不符合要求,请重新输入!");
}
}
}
//判断存在
public static int exist(String route) throws IOException {
ArrayList<busInformation> array = transform();
int exist = 0;
//此公交路线不存在
for (busInformation i :array) {
if (Objects.equals(i.getRoute(), route)) {
exist = 1;
//此公交路线存在
break;
}
}
return exist;
}
//判断线路在文件的行号
public static int findLineNumber(List<String> line, String route) {
for (int i = 0; i < line.size(); i++) {
if (line.get(i).contains(route)) {
return i;
}
}
return -1;
//此公交路线不存在
}
//添加公交线路
private static void addBusInformation() throws IOException {
Scanner scanner = new Scanner(System.in);
Scanner stations = new Scanner(System.in);
String inputRoute;
while (true) {
System.out.print("请输入需要添加的公交路线号:");
inputRoute = scanner.next();
if (exist(inputRoute) == 1) {
System.out.println("公交路线号已存在,请重新操作!");
} else {
break;
}
}
System.out.print("请输入需要添加的公交路线站点(请使用空格分隔):");
String inputStation = stations.nextLine();
//使用split()方法将字符串按空格分隔成一个字符串数组
String[] split = inputStation.split(" ");
ArrayList<String> station = new ArrayList<>(Arrays.asList(split));
System.out.print("请输入需要添加的公交路线时间:");
String inputTime = scanner.next();
System.out.print("请输入需要添加的公交路线票价:");
String inputPrice = scanner.next();
System.out.print("请输入需要添加的公交路线卡:");
String inputCard = scanner.next();
//将输入内容写入文件,创建输出流
String filePath = "src/bus/busInformation.txt";
FileOutputStream fileOutputStream = new FileOutputStream(filePath, true);
//FileOutputStream用于将数据写入到文件中,通常与字节流一起使用
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "GBK");
//OutputStreamWriter是一个字符流,它可以将字符写入到字节输出流中
//它提供了一种方便的方式来将字符转换为字节,以便进行文件操作、网络通信等
//OutputStreamWriter的构造函数接受一个OutputStream对象作为参数,用于指定要写入的目标字节输出流
//它还可以接受一个字符集名称作为第二个参数,用于指定字符编码方式,如果不指定字符集名称,则使用默认的字符集
BufferedWriter writer = new BufferedWriter(outputStreamWriter);
//BufferedWriter是一个字符流,它可以将字符写入到字符输出流中
//它提供了缓冲区,可以提高写入性能
//BufferedWriter的构造函数接受一个Writer对象作为参数,用于指定要写入的目标字符输出流
//它还可以接受一个字符集名称作为第二个参数,用于指定字符编码方式,如果不指定字符集名称,则使用默认的字符集。
writer.write(inputRoute + "%" + String.join("%", station) + "%" + inputTime + " " + inputPrice + " " + inputCard);
//write方法用于向输出流写入数据
writer.newLine();
//插入一个换行符
writer.close();
//close()方法关闭写入器
System.out.println("添加成功!");
}
//修改公交线路
private static void updateBusInformation() throws IOException {
Scanner scanner = new Scanner(System.in);
Scanner stations = new Scanner(System.in);
System.out.print("请输入需要修改的公交路线号:");
String route = scanner.next();
//将字符串形式的文件路径转换为Path对象
String filePath = "src/bus/busInformation.txt";
Path path = Paths.get(filePath);
//类型安全:使用Path对象可以避免直接使用字符串,从而减少因类型错误导致的运行时异常
//平台无关性:Path对象可以在不同的操作系统上使用相同的代码进行处理,而不需要对每个操作系统进行特殊处理
//可读性:使用Path对象可以提高代码的可读性,因为它明确表示了路径的类型和结构
//方便操作:Path对象提供了许多方法来操作路径,例如获取父路径、获取文件名等,这些方法在直接使用字符串时可能不太方便
//所以,虽然可以直接使用字符串作为文件路径,但使用Path对象可以使代码更加健壮、易于维护和理解
List<String> line = Files.readAllLines(path, Charset.forName("GBK"));
//Files.readAllLines()用于从文件中读取所有行并将其作为字符串列表返回
int lineUpdate = findLineNumber(line, route);
//需要修改的行号
if (lineUpdate == -1) {
System.out.println("公交路线号不存在,请重新操作!");
} else {
Scanner scanner1 = new Scanner(System.in);
String inputRoute;
while (true) {
System.out.print("请输入新的公交路线号:");
inputRoute = scanner1.next();
if (exist(inputRoute) == 1) {
System.out.println("公交路线号已存在,请重新操作!");
} else {
break;
}
}
System.out.print("请输入新的公交路线站点(请使用空格分隔):");
String inputStation = stations.nextLine();
String[] split = inputStation.split(" ");
ArrayList<String> station = new ArrayList<>(Arrays.asList(split));
System.out.print("请输入新的公交路时间:");
String inputTime = scanner.next();
System.out.print("请输入新的公交路票价:");
String inputPrice = scanner.next();
System.out.print("请输入新的公交路卡:");
String inputCard = scanner.next();
//将修改后的内容写回文件
String newLine = inputRoute + "%" + String.join("%", station) + "%" + inputTime + " " + inputPrice + " " + inputCard;
line.set(lineUpdate, newLine);
Files.write(path, line, Charset.forName("GBK"));
//Files.write用于将字节序列写入文件
//它接受两个参数:一个是文件路径,一个是要写入的字节序列
//这个方法会覆盖文件中的现有内容
System.out.println("修改成功!");
}
}
//删除公交线路
private static void deleteBusInformation() throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入需要删除的公交路线号:");
String route = scanner.next();
String filePath = "src/bus/busInformation.txt";
Path path = Paths.get(filePath);
List<String> line = Files.readAllLines(path, Charset.forName("GBK"));
int lineDelete = findLineNumber(line, route);
//需要删除的行号
if (lineDelete == -1) {
System.out.println("公交路线号不存在,请重新操作!");
} else {
line.remove(lineDelete);
//remove(int index)从集合中删除指定索引处的元素
// 将修改后的内容写回文件
Files.write(path, line, Charset.forName("GBK"));
System.out.println("删除成功!");
}
}
}