!!!还有两个问题没有解决,但功能都能实现
实现图书馆功能,并有多线程功能,服务器客户端交互功能,存储数据文件功能。
实现代码后的整天架构思路如图:
即分为客户端和服务器,这里会发现一个暂时没有解决的问题就是客户端和服务器要共用同一个Book和User类,否则在以集合的数据形式交互时会无法识别对方传入的ArrayList,但仔细想想就会发现,服务器和客户端应该是两个不同的本地文件,怎么能隔空共享一个类数据呢?
犹豫单个传递String太过繁琐,所以暂时以不懂原理,但能实现功能的方式敷衍过去。毕竟String一个个传也能实现,就不在这上面浪费功夫了。原理只能之后再逐渐了解。
后续还有一个问题没有搞明白,但是有解决方法
就是我试图把添加图书功能中的三次交互信息的功能分拆到三个方法中,以便能够在其他的比如删除图书,修改图书中使用。
具体来讲就是把添加图书中要进行的(os.write(),oos.writeObject(),ois.readObject()拆到三个方法)三次交互分拆到三个方法中。
但是这样会报错,而且是没有任何问题的服务器端报错
Software caused connection abort: recv failed
原因是客户端发送信息后,服务器端接收出了问题,但是客户端不知道,只能继续傻傻的等待服务器回应,但实际上是因为客户端的代码写的有问题
我觉得可能导致的这个问题的原因是:客户端把os.write单独写在一个方法内后,方法结束调用就关闭了流,而服务器端的ObjectInputStream ois = new ObjectInputStream(is)在后续的ois.readObject就接受不到流了,那么服务端就会对ObjectInputStream ois = new ObjectInputStream(is)这个创建类的这一行代码报错。从而不执行oos.writeObject(),ois.readObject()直接结束掉这一次的线程,自然的客户端也得不到响应就只能一直等着了。所以如果能够把is,os的close分开两个方法,且能够关闭,应该也是可行的,但是不知道为什么我把所有close都删了还是后面有个地方会报错了,所以我就敷衍过去了
我的代码比较冗长,看起来比较难受,真正有用的就是客户端视窗界面,服务器main界面,客户端图书信息管理方法三个部分的代码,其他部分的功能实现都非常简单,可以参考别的博客已有的简便任务代码。
我把IO报错的的代码(add_fail这类后缀为_fail的代码是报错代码)和正确的代码都在后面展示了,希望有大佬能解答一下为什么。
客户端的视窗界面代码:
package DemoBook.Client;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;
public class ClientView {
ClientFuntionUser cfu = new ClientFuntionUser();
ClientFuntionBook cfb = new ClientFuntionBook();
public ClientView() throws IOException {
}
void operation() {
System.out.println("====欢迎使用图书管理系统====");
//设置身份验证是否通过的记录器
boolean x =false;
while (true) {
if (x) {
//身份验证通过,则循环执行图书信息编辑相关程序
while (true) {
operationBook();
//如果要设计推出登陆则在设置一个是否跳出循环且改变x为false的判断。该判断由一个方法返回
//原理和后面的id()类似
}
} else {
//如果身份验证不通过,则循环执行账号登陆或注册的程序
while (true) {
if (x == false) {
x = id();
} else {
break;
}
}
}
}
}
boolean id() {
try {
System.out.println("1-登陆系统,2-注册新账号");
Scanner input = new Scanner(System.in);
int identity = input.nextInt();
if (identity == 1) {
System.out.println("请输入登陆的账号");
String account = input.next();
System.out.println("请输入账号密码");
String password = input.next();
//开始登陆是否成功的判断
Boolean x = cfu.logon(account,password);
if (x){
//身份验证通过
return true;
}else{
System.out.println("输入的用户名或者密码不正确,请重新输入");
return false;
}
} else if (identity == 2) {
//开始注册功能
cfu.register();
}else {
System.out.println("你输入的数值不在可选项内,请重新输入:");
return false;
}
} catch (InputMismatchException identity) {
System.out.println("请按照提示,重新输入符合要求的信息");
return false;
}
return false;
}
void operationBook(){
try {
System.out.println("请选择操作:1-图书新增,2-图书修改,3-图书删除,4-查找图书,5-查看全部新增图书");
Scanner input = new Scanner(System.in);
int handle = input.nextInt();
switch (handle) {
case 1: {
cfb.add();
break;
}
case 2: {
cfb.change();
break;
}
case 3: {
cfb.delete();
break;
}
case 4: {
cfb.lookup();
break;
}
case 5: {
System.out.println("所有的新增图书信息如下:");
sort();
break;
}
default: {
System.out.println("你输入的数值不在可选项内,请重新输入:");
operationBook();
}
}
} catch (InputMismatchException handle) {
System.out.println("请按照提示重新输入信息");
operationBook();
}
}
void sort(){
Scanner input = new Scanner(System.in);
try {
System.out.println("请选择排序方法:1-价格从高到低排序,2-价格从低到高排序,3-新旧排序(出版日期排序)");
int handle = input.nextInt();
switch (handle){
case 1:{
cfb.priceHighSort();
break;
}
case 2:{
cfb.priceLowSort();
break;
}
case 3:{
cfb.publicDaySort();
break;
}default: {
System.out.println("你输入的数值不在可选项内,请重新输入:");
sort();
}
}
} catch (InputMismatchException identity) {
System.out.println("请按照提示重新输入信息");
sort();
}
}
}
客户端的用户登录方法和图书信息管理方法代码:
账号登录:
package DemoBook.Client;
import DemoBook.Data.User;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Scanner;
public class ClientFuntionUser {
Boolean logon(String account,String password){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//发送操作信号
os.write(12);
ArrayList<User> userArray = new ArrayList<>();
User user = new User();
user.setAccount(account);
user.setPassword(password);
userArray.add(user);
//发送存储数据的集合
oos.writeObject(userArray);
//等待接受回信
String text = (String)ois.readObject();
//关闭流
os.close();
is.close();
oos.close();
ois.close();
//进行后续判断
if (text.equals("账号密码正确")){
return true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return false;
}
void register(){
//判断注册人员是否有为工作人员
System.out.println("请输入图书馆工作人员授权码");
Scanner input = new Scanner(System.in);
//记录输入的授权码
int power = input.nextInt();
System.out.println("请输入登陆的账号");
String account = input.next();
System.out.println("请输入账号密码");
String password = input.next();
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//发送操作信号
os.write(11);
ArrayList<User> userArray = new ArrayList<>();
User user = new User();
user.setAccount(account);
user.setPassword(password);
user.setPower(power);
userArray.add(user);
//发送存储数据的集合
oos.writeObject(userArray);
//等待接受回信
String text = (String)ois.readObject();
//显示结果
System.out.println(text);
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 便于更改端口号
* @return
*/
int portNumber(){
return 7973;
}
}
图书信息管理
package DemoBook.Client;
import DemoBook.Data.Book;
import DemoBook.Server.ComparePrice;
import DemoBook.Server.ComparePubliceDay;
import java.io.*;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.*;
public class ClientFuntionBook {
/**
* 添加书籍
*/
void add(){
//接收输入书籍的名称
Scanner input = new Scanner(System.in);
System.out.println("请输入书籍名称");
//使用的是set集合,无法存储完全一样的书本,如果价格和出版日期不同,则同样存入一本新的同名但实际不同的书籍
String name = input.next();
//接收输入书籍的价格
int price = add_price();
//接收输入书籍的出版日期
long publicDay = add_PublicDay();
//建立新的数据存储类,并将本次添加的数据存入
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//发送操作信号
os.write(21);
//建立新的数据存储类,并将本次添加的数据存入
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setPublicDay(publicDay);
//将书籍类存入有序集合treeSet中去
ArrayList<Book> arrayList= new ArrayList<>();
arrayList.add(book);
//将集合发送给服务器
oos.writeObject(arrayList);
//接收返回结果
String text = (String)ois.readObject();
//显示结果
System.out.println(text);
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 输入出版日期
* @return
*/
long add_PublicDay() {
try {
Scanner input = new Scanner(System.in);
System.out.println("请输入书籍出版年份");
int year = input.nextInt();
System.out.println("请输入书籍出版月份");
int month = input.nextInt();
System.out.println("请输入书籍出版日期");
int day = input.nextInt();
if (year>0&&12>=month&&month>=1&&31>=day&&day>=1) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, month-1, day, 0, 0, 0);
Date date = calendar.getTime();
long publicDay = date.getTime();
System.out.println(date);
return publicDay;
}else{
System.out.println("输入的年月日不正确");
return add_PublicDay();
}
} catch (InputMismatchException year) {
System.out.println("请按照提示,重新输入符合要求的信息");
return add_PublicDay();
}
}
/**
* 输入书籍价格
* @return
*/
int add_price(){
Scanner input = new Scanner(System.in);
try {
System.out.println("请输入书籍价格");
int price = input.nextInt();
return price;
}catch (InputMismatchException nums) {
System.out.println("请按照提示,重新输入符合要求的信息");
return add_price();
}
}
/**
* 输入书名并删除输入书名的书籍
*/
void delete(){
Scanner input = new Scanner(System.in);
System.out.println("请输入要删除的书籍名称");
String name = input.next();
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
PrintStream ps = new PrintStream(os);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//发送操作信号
os.write(22);
//向服务器发送书名
ps.println(name);
//接收返回结果
String text = (String)ois.readObject();
//显示结果
System.out.println(text);
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 输入书名并修改输入书名的书籍
*/
void change() {
Scanner input = new Scanner(System.in);
System.out.println("请输入要修改的书籍名称");
String nameChange = input.next();
try {
Socket socket = new Socket("127.0.0.1", portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
PrintStream ps = new PrintStream(os);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//先判断图书是否存在
os.write(23);
//向服务器发送书名
ps.println(nameChange);
//接收返回结果
String text1 = (String)ois.readObject();
//显示结果
if (text1.equals("输入的书籍名称不存在。")) {
//如果书籍不存在,则显示结果
System.out.println(text1);
//如果是其他返回信息则证明图书存在,开始输入新书籍的操作
}else {
System.out.println("请输入新的信息");
System.out.println("书籍名称:");
String name = input.next();
//接收输入书籍的价格
int price = add_price();
//接收输入书籍的出版日期
long publicDay = add_PublicDay();
//建立新的数据存储类,并将本次添加的数据存入
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setPublicDay(publicDay);
//记录修改前的旧图书名称
book.setNameOld(nameChange);
//将书籍类存入有序集合arrayList中去
ArrayList<Book> arrayList = new ArrayList<>();
arrayList.add(book);
//将集合发送给服务器
oos.writeObject(arrayList);
//接收返回结果
String text2 = (String) ois.readObject();
//显示结果
System.out.println(text2);
}
os.close();
is.close();
oos.close();
ois.close();
ps.close();
br.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 查找图书
*/
void lookup(){
Scanner input = new Scanner(System.in);
System.out.println("请输入要查找的书籍名称");
String name = input.next();
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
PrintStream ps = new PrintStream(os);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
os.write(24);
//向服务器发送书名
ps.println(name);
//接收返回结果
String text = (String)ois.readObject();
//显示结果
System.out.println(text);
os.close();
is.close();
oos.close();
ois.close();
ps.close();
br.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 按照价从高到低排序并显示
*/
void priceHighSort(){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//向服务器发送获取图书数据的请求信号
os.write (25);
//接受从服务器端传入的ArrayList<Book>集合的流
ArrayList<Book> arrayList = (ArrayList<Book>)ois.readObject();
//将集合内的内容按照新的规则排序
TreeSet<Book> treeSet = resetPrice(arrayList);
//将集合的内容 倒序 的放进迭代器
Iterator it = treeSet.descendingIterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName()+"\t\t"+b.getPrice()+"\t\t"+publicDay);
}
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 按照价从低到高排序并显示
*/
void priceLowSort(){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//向服务器发送获取图书数据的请求信号
os.write (25);
//接受从服务器端传入的ArrayList<Book>集合的流
ArrayList<Book> arrayList = (ArrayList<Book>)ois.readObject();
//将集合内的内容按照新的规则排序
TreeSet<Book> treeSet = resetPrice(arrayList);
//将集合的内容 顺序 的放进迭代器
Iterator it = treeSet.iterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName()+"\t\t"+b.getPrice()+"\t\t"+publicDay);
}
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 按出版日期从新到旧排序并显示
*/
void publicDaySort(){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
//发送操作信号
//向服务器发送获取图书数据的请求信号
os.write (25);
//接受从服务器端传入的TreeSet<Book>集合的流
//接受从服务器端传入的ArrayList<Book>集合的流
ArrayList<Book> arrayList = (ArrayList<Book>)ois.readObject();
//将集合内的内容按照新的规则排序
TreeSet<Book> treeSet = resetPublice(arrayList);
//将集合的内容 倒序 的放进迭代器
Iterator it = resetPublice(arrayList).descendingIterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()) {
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book) it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName() + "\t\t" + b.getPrice() + "\t\t" + publicDay);
}
os.close();
is.close();
oos.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 排序出版日期
* @param arrayList
* @return
*/
TreeSet<Book> resetPublice(ArrayList<Book> arrayList){
ArrayList<Book> abg = arrayList;
TreeSet<Book> treeSet = new TreeSet<>(new ComparePubliceDay());
//使用迭代器取出ArrayList到临时对象中,在存入TreeSet中
Iterator it = abg.iterator();
while (it.hasNext()){
//将当前迭代器下标存储的ArrayList赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类存入treeSet集合
treeSet.add(b);
}
System.out.println("载入图书数据成功");
return treeSet;
}
/**
* 排序价格
* @param arrayList
* @return
*/
TreeSet<Book> resetPrice(ArrayList<Book> arrayList){
ArrayList<Book> abg = arrayList;
TreeSet<Book> treeSet = new TreeSet<>(new ComparePrice());
//使用迭代器取出ArrayList到临时对象中,在存入TreeSet中
Iterator it = abg.iterator();
while (it.hasNext()){
//将当前迭代器下标存储的ArrayList赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类存入treeSet集合
treeSet.add(b);
}
System.out.println("载入图书数据成功");
return treeSet;
}
/**
* 便于更改端口号
* @return
*/
int portNumber(){
return 7973;
}
//以下是,抽取传输数据为单独方法,然后报错的弃用代码
void add_fail(){
//发送操作信号
OutToServerBook(21);
//接收输入书籍的名称
Scanner input = new Scanner(System.in);
System.out.println("请输入书籍名称");
//使用的是set集合,无法存储完全一样的书本,如果价格和出版日期不同,则同样存入一本新的同名但实际不同的书籍
String name = input.next();
//接收输入书籍的价格
int price = add_price();
//接收输入书籍的出版日期
long publicDay = add_PublicDay();
//建立新的数据存储类,并将本次添加的数据存入
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setPublicDay(publicDay);
//将书籍类存入有序集合treeSet中去
ArrayList<Book> arrayList= new ArrayList<>();
arrayList.add(book);
//将集合发送给服务器
OutToServerBookArrayList(arrayList);
//接收返回结果
String text = inputToServerString();
//显示结果
System.out.println(text);
}
void delete_fail(){
//发送操作信号
OutToServerBook(22);
Scanner input = new Scanner(System.in);
System.out.println("请输入要删除的书籍名称");
String name = input.next();
//向服务器发送书名
OutToServerBookName(name);
//接收返回结果
String text = inputToServerString();
//显示结果
System.out.println(text);
}
void change_fail() {
//发送操作信号
OutToServerBook(23);
Scanner input = new Scanner(System.in);
System.out.println("请输入要修改的书籍名称");
String name = input.next();
//接收输入书籍的价格
int price = add_price();
//接收输入书籍的出版日期
long publicDay = add_PublicDay();
//建立新的数据存储类,并将本次添加的数据存入
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setPublicDay(publicDay);
//将书籍类存入有序集合treeSet中去
ArrayList<Book> arrayList= new ArrayList<>();
arrayList.add(book);
//将集合发送给服务器
OutToServerBookArrayList(arrayList);
//接收返回结果
String text = inputToServerString();
//显示结果
System.out.println(text);
}
void lookup_fail(){
//发送操作信号
OutToServerBook(24);
Scanner input = new Scanner(System.in);
System.out.println("请输入要查找的书籍名称");
String name = input.next();
//向服务器发送书名
OutToServerBookName(name);
//接收返回结果
String text = inputToServerString();
//显示结果
System.out.println(text);
}
void priceHighSort_fail(){
//向服务器发送获取图书数据的请求信号
OutToServerBook (25);
//接受从服务器端传入的TreeSet<Book>集合的流
TreeSet<Book> treeSet = inputToServer();
//将集合的内容 倒序 的放进迭代器
Iterator it = treeSet.descendingIterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName()+"\t\t"+b.getPrice()+"\t\t"+publicDay);
}
}
void priceLowSort_fail(){
//向服务器发送获取图书数据的请求信号
OutToServerBook (25);
//接受从服务器端传入的TreeSet<Book>集合的流
TreeSet<Book> treeSet = inputToServer();
//将集合的内容 顺序 的放进迭代器
Iterator it = treeSet.iterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName()+"\t\t"+b.getPrice()+"\t\t"+publicDay);
}
}
void publicDaySort_fail(){
//向服务器发送获取图书数据的请求信号
OutToServerBook (25);
//接受从服务器端传入的TreeSet<Book>集合的流
TreeSet<Book> treeSet = inputToServer();
//将集合内的内容按照新的规则排序
resetPublice_fail(treeSet);
//将集合的内容 倒序 的放进迭代器
Iterator it = treeSet.descendingIterator();
//使用迭代器一个一个的查过去
System.out.println("图书名称"+"\t\t"+"图书价格"+"\t\t"+"图书出版日期");
while (it.hasNext()) {
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book) it.next();
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(b.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
System.out.println(b.getName() + "\t\t" + b.getPrice() + "\t\t" + publicDay);
}
}
void resetPublice_fail(TreeSet<Book> treeSet){
//创建一个新的临时集合,并加载新的比较排序方法
TreeSet<Book> treeSetNew = new TreeSet<>(new ComparePubliceDay());
//将原来的集合元素转移到迭代器后再转移到新的集合中去
Iterator it = treeSet.descendingIterator();
//使用迭代器一个一个的查过去
while (it.hasNext()) {
//将当前迭代器下标存储的treeSet赋值给临时对象Book,然后添加到新的集合中去
Book b = (Book) it.next();
treeSetNew.add(b);
}
//将重新排序完成的集合赋值给原来的存储集合
treeSet = treeSetNew;
}
/**
* 接受服务器端传入的treeSet集合数据
* @return
*/
TreeSet<Book> inputToServer (){
try {
//接受服务器端数据
Socket socket = new Socket("127.0.0.1",portNumber());
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
TreeSet<Book> treeSet = (TreeSet<Book>)ois.readObject();
is.close();
ois.close();
return treeSet;
} catch (IOException e) {
System.out.println("IO异常");
} catch (ClassNotFoundException e) {
System.out.println("未能发现类的异常");
}
return new TreeSet<Book>();
}
/**
* 接受服务器端传入的String类结果
* @return
*/
String inputToServerString (){
try {
//接受服务器端数据
Socket socket = new Socket("127.0.0.1",portNumber());
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
String text = (String)ois.readObject();
is.close();
ois.close();
return text;
} catch (IOException e) {
System.out.println("IO异常");
} catch (ClassNotFoundException e) {
System.out.println("未能发现类的异常");
}
return "";
}
/**
* 向服务器发送集合数据
* @param arrayListBook
*/
void OutToServerBookArrayList (ArrayList<Book> arrayListBook){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(arrayListBook);
//向服务器发送获取图书数据的请求信号
os.close();
oos.close();
} catch (IOException e) {
System.out.println("array-IO异常");
}
}
/**
* 向服务器发送书本名称,即单个String
* @param name
*/
void OutToServerBookName (String name){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
PrintStream ps = new PrintStream(os);
ps.println(name);
//向服务器发送获取图书数据的请求信号
os.close();
ps.close();
} catch (IOException e) {
System.out.println("name-IO异常");
}
}
/**
* 向服务器发送指定的key信号
* @param key
*/
void OutToServerBook (int key){
try {
Socket socket = new Socket("127.0.0.1",portNumber());
OutputStream os = socket.getOutputStream();
os.write(key);
//向服务器发送获取图书数据的请求信号
os.close();
} catch (IOException e) {
System.out.println("key-IO异常");
e.printStackTrace();
}
}
}
服务器端代码
package DemoBook.Server;
import DemoBook.Data.Book;
import DemoBook.Data.User;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
public static void main(String[] args) throws IOException {
//创建线程池
ExecutorService threadPool = Executors.newCachedThreadPool();
//设置端口号
ServerSocket serverSocket = new ServerSocket(7973);
//服务器初始化完成
System.out.println("服务器初始化完成");
//载入数据
ServerFunctionUser sfu = new ServerFunctionUser();
ServerFunctionBook sfb = new ServerFunctionBook();
f:while (true) {
Socket socket = serverSocket.accept();
System.out.println("有一个客户端接入成功");
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
//初始化各个对象
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
ObjectInputStream ois = new ObjectInputStream(is);
PrintStream ps = new PrintStream(os);
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//初始化完成后,开始接收客户端信息
//读取操作类别,并转入相应操作中
int key = is.read();
k:switch (key){
//注册功能
case 11:{
//接收 客户端传入的用户名,密码,权限码,并检查权限码是否正确,以及要注册的用户名是否存在
ArrayList<User> arrayList = (ArrayList<User>)ois.readObject();
String account = arrayList.get(0).getAccount();
String password = arrayList.get(0).getPassword();
int power = arrayList.get(0).getPower();
if (sfu.powerTF(power)){
//权限码正确
//将收到的用户名送入检测,判断是否已存在
int i = sfu.checkAccount(account);
if (i == -1){
//该用户名不存在,可以开始注册
String text = sfu.register(account,password);
//返回结果给客户端
oos.writeObject(text);
}else {
//用户名不存在,返回信息给客户端
oos.writeObject("要注册的用户名已存在");
}
}
//权限码不正确,返回信息给客户端
oos.writeObject("权限码不正确");
break;
}
//登陆功能
case 12:{
//接收客户端传入的用户名,密码,以及要注册的用户名是否存在
ArrayList<User> arrayList = (ArrayList<User>)ois.readObject();
String account = arrayList.get(0).getAccount();
String password = arrayList.get(0).getPassword();
//将收到的用户名送入检测,判断是否已存在
int i = sfu.checkAccount(account);
if (i != -1){
//该用户名存在,可以开始登陆
boolean k = sfu.logon(account,password);
//返回结果给客户端
String text;
if (k){
text = "账号密码正确";
}else {
text = "账号密码不正确";
}
oos.writeObject(text);
}else {
//用户名不存在,返回信息给客户端
oos.writeObject("输入的用户名不存在");
}
break;
}
//新增图书
case 21:{
System.out.println("开始添加图书");
//接收客户端输入的图书信息
ArrayList<Book> array = (ArrayList<Book>)ois.readObject();
String name = array.get(0).getName();
int price = array.get(0).getPrice();
long publicDay = array.get(0).getPublicDay();
// 将数据传入处理方法中,并返回结果给客户端
sfb.add(name,price,publicDay);
//得到出版日期的String格式
String publicDayString = sfb.publicDaySize(publicDay);
String text = name+"\t\t"+price+"\t\t"+publicDayString;
//将返回结果传输给客户端
oos.writeObject(text);
break;
}
//删除图书
case 22:{
//检查书名是否存在,并返回客户端信息
String name = br.readLine();
//检索集合中是否存在这个书名,若存在返回这个name对应的Book类数据
Book book = sfb.checkName(name);
if (name.equals(book.getName())){
//检索到书名删除集合中的该数据
sfb.delete(book);
String text ="输入的书籍信息已删除成功";
oos.writeObject(text);
}else{
//如果返回的不是输入的书名(是一个空的book),则不执行程序,并反馈信息
String text = "输入的书籍名称不存在。";
oos.writeObject(text);
}
break;
}
//修改图书
case 23:{
//检查书名是否存在,并返回客户端信息
String name = br.readLine();
//检索到书名输出集合中的该数据
String text1 = sfb.lookup(name);
oos.writeObject(text1);
if (text1.equals("输入的书籍名称不存在。")) {
//书籍名称不存在则不执行结束这次线程
}else {
//其他信息则代表书籍存在,执行后续操作
//接收客户端输入的新的图书图书信息
ArrayList<Book> arrayList = (ArrayList<Book>)ois.readObject();
//把旧书名和新书籍数据传入方法中,并返回修改后的信息
String text2 =sfb.change(arrayList,name);
oos.writeObject(text2);
}
break;
}
//查找图书
case 24:{
//检查书名是否存在,并返回客户端信息
String name = br.readLine();
//检索到书名输出集合中的该数据
String text = sfb.lookup(name);
oos.writeObject(text);
break;
}
//查看所有图书
case 25:{
//返回存储集合交由本地排序
oos.writeObject(sfb.print());
break ;
}
default: {
break;
}
}
os.close();
is.close();
oos.close();
ois.close();
ps.close();
br.close();
System.out.println("一次线程任务结束");
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
});
}
}
}
服务器端的用户登录方法和图书信息管理方法代码:
用户登录:
package DemoBook.Server;
import DemoBook.Data.User;
import java.io.IOException;
import java.util.ArrayList;
public class ServerFunctionUser {
IO io = new IO();
ArrayList<User> userArray = io.userGet();
public ServerFunctionUser() throws IOException {
}
Boolean logon(String account,String password){
//检索userArray集合中是否有输入的用户名,如果有就返回它的下标,无则返回-1
int i = checkAccount(account);
if(i != -1){
//建立一个临时的存储userArray集合下标为i的对象
User user = userArray.get(i);
if (user.getPassword().equals(password)){
//如果密码正确,则可以进入系统开始操作
return true;
//如果密码不正确,则不操作,待方法尾部赋值为false
}//如果密码不正确,则不操作,待方法尾部赋值为false
}//如果i == -1,则用户名不存在,赋值同样为false
return false;
}
String register(String account,String password) throws IOException {
//把新注册的用户名和账号密码传入userArray集合中
//建立一个临时存放数据的User对象
User user = new User();
user.setAccount(account);
user.setPassword(password);
//把数据对象存入集合中
userArray.add(user);
io.userSet(userArray);
return "您的账号注册成功,注册的账号密码以存入服务器端系统文件";
}
int checkAccount(String account){
//创建一个临时存储数据的对象
User user = new User();
//如果集合长度为空,则没有任何一个账号,也就不存在用户名已经存在的情况,则不执行循环检索,直接输出-1
if (userArray.size() != 0) {
//检索集合
for (int i = 0; i < userArray.size(); i++) {
//给临时对象赋值
user = userArray.get(i);
if (user.getAccount().equals(account)) {
//判断用户名是否存在
return i;
}
}
}
return -1;
}
boolean powerTF(int passwordPower){
if( passwordPower == 123456 ){
//权限码正确
return true;
}else {
//权限码错误则
return false;
}
}
}
书籍信息管理
package DemoBook.Server;
import DemoBook.Data.Book;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
public class ServerFunctionBook {
IO io = new IO();
/**
* IO中创建的TreeSet默认加载comparePrice()来重写compare,实现Comparator接口
*/
TreeSet<Book> treeSet = io.bookGet();
public ServerFunctionBook() throws IOException {
}
/**
* 添加书籍
*/
void add(String name,int price,long publicDay){
//使用的是set集合,无法存储完全一样的书本,如果价格和出版日期不同,则同样存入一本新的同名但实际不同的书籍
//建立新的数据存储类,并将本次添加的数据存入
Book book = new Book();
book.setName(name);
book.setPrice(price);
book.setPublicDay(publicDay);
//将书籍类存入有序机会treeSet中去
treeSet.add(book);
setDate();
}
/**
* 检查输入名称对应的书籍是否已经存在,若存在返回这整个book类数据,以待处理
* @param name
* @return
*/
Book checkName(String name){
//将集合的内容放进迭代器
Iterator it = treeSet.iterator();
//使用迭代器一个一个的查过去
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
if(b.getName().equals(name)){
//如果找到同name的Book类,则返回这个Book
return b;
}
}
//如果没有找到则生成一个新的空Book
return new Book();
}
/**
* 输入书名并删除输入书名的书籍
*/
void delete(Book book){
treeSet.remove(book);
setDate();
}
/**
* 输入书名并修改输入书名的书籍
*/
String change(ArrayList<Book> arrayList,String nameOld) {
//读取传入的集合数据到新的book对象中
String nameNew = arrayList.get(0).getName();
int price = arrayList.get(0).getPrice();
long publicDay = arrayList.get(0).getPublicDay();
Book bookNew = new Book();
bookNew.setName(nameNew);
bookNew.setPrice(price);
bookNew.setPublicDay(publicDay);
//检索集合中是否存在这个书名,若存在返回这个name对应的Book类数据
Book book = checkName(nameOld);
//修改集合中的该数据,先删除旧的数据,在加入新的(直接调用图书新增的方法)
treeSet.remove(book);
treeSet.add(bookNew);
setDate();
String text = "输入的书籍信息已修改成功";
return text;
}
/**
* 查找图书
*/
String lookup(String name){
//检索集合中是否存在这个书名,若存在返回这个name对应的Book类数据
Book book = checkName(name);
if (name.equals(book.getName())){
//检索到书名输出集合中的该数据
//将数据存储类中的出版日期毫米值转换成固定格式的日期
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(book.getPublicDay());
String publicDay = format.format(date);
//显示查询图书的信息
String text = book.getName()+"\t\t"+book.getPrice()+"\t\t"+publicDay;
return text;
}else{
//如果返回的不是输入的书名(是一个空的book),则不执行程序,并反馈信息
String text = "输入的书籍名称不存在。";
return text;
}
}
/**
* 返回存储集合
* @return
*/
ArrayList<Book> print(){
//要将TreeSet装换为ArrayList,再序列化的传入文件中去
//使用迭代器取出TreeSet到临时对象中,在存入ArrayList中
Iterator it = treeSet.descendingIterator();
ArrayList<Book> alb = new ArrayList<>();
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类存入ArrayList集合
alb.add(b);
}
System.out.println("载入图书数据成功");
return alb;
}
/**
* 存储数据到文件中
*/
void setDate() {
IO io = new IO();
try {
io.bookSet(treeSet);
} catch (IOException e) {
System.out.println("发生异常");
}
}
/**
* 输出出版日期
* @param publicDay
* @return
*/
String publicDaySize(long publicDay){
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日");
Date date = new Date();
date.setTime(publicDay);
return format.format(date);
}
}
服务器端IO存储本地文件的功能
package DemoBook.Server;
import DemoBook.Data.Book;
import DemoBook.Data.User;
import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeSet;
public class IO {
//使用序列化和反序列化,Book和User类要实现接口,标记数据类使用了序列化和反序列化
void bookSet(TreeSet<Book> treeSet) throws IOException {
//由于使用了Comparator的重写方法类存treeSet而不是实现Comparable接口,没有在数据类中重写单值输入比较方法comparaTo,所以不能使用TreeSet来存取
//要将TreeSet装换为ArrayList,再序列化的传入文件中去
//使用迭代器取出TreeSet到临时对象中,在存入ArrayList中
Iterator it = treeSet.descendingIterator();
ArrayList<Book> abs = new ArrayList<>();
while (it.hasNext()){
//将当前迭代器下标存储的treeSet赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类存入ArrayList集合
abs.add(b);
}
FileOutputStream fileOut = new FileOutputStream("H://java/4-6/book.txt");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(abs);
objectOut.close();
fileOut.close();
}
/**
* 载入文件数据进入临时集合,返回值为TreeSet集合Book类
* @return
* @throws IOException
*/
TreeSet<Book> bookGet ()throws IOException{
//由于使用了Comparator的重写方法类存treeSet而不是实现Comparable接口,没有在数据类中重写单值输入比较方法comparaTo,所以不能使用TreeSet来存取
//要将序列化文件反序列化到ArrayList集合中去,然后再将ArrayList装换为TreeSet,在作为返回值返回出去
ArrayList<Book> abg = new ArrayList<>();
try {
FileInputStream fileIn = new FileInputStream("H://java/4-6/book.txt");
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
try (fileIn; objectIn) {
abg = (ArrayList<Book>)objectIn.readObject();
TreeSet<Book> treeSet = new TreeSet<>(new ComparePrice());
//使用迭代器取出ArrayList到临时对象中,在存入TreeSet中
Iterator it = abg.iterator();
while (it.hasNext()){
//将当前迭代器下标存储的ArrayList赋值给临时对象Book
Book b = (Book)it.next();
//将数据存储类存入treeSet集合
treeSet.add(b);
}
System.out.println("载入图书数据成功");
return treeSet;
} catch (IOException | ClassNotFoundException e) {
//可能载入的类不存在
e.printStackTrace();
System.out.println("载入图书数据失败");
//返回一个临时的空集合
return new TreeSet<>(new ComparePrice());
}
}catch (FileNotFoundException fileNotFoundException) {
System.out.println("未找到图书数据文件");
//返回一个临时的空集合
return new TreeSet<>(new ComparePrice());
} catch (IOException eofException) {
System.out.println("图书数据为空");
//返回一个临时的空集合
return new TreeSet<>(new ComparePrice());
}
}
void userSet(ArrayList<User> userArray) throws IOException {
FileOutputStream fileOut = new FileOutputStream("H://java/4-6/user.txt");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(userArray);
objectOut.close();
fileOut.close();
}
/**
* 载入文件数据进入临时集合,返回值为ArrayList集合User类
* @return
* @throws IOException
*/
ArrayList<User> userGet() throws IOException {
ArrayList<User> userArray = new ArrayList<>();
try {
FileInputStream fileIn = new FileInputStream("H://java/4-6/user.txt");
ObjectInputStream objectIn = new ObjectInputStream(fileIn);
try (fileIn; objectIn) {
userArray = (ArrayList<User>)objectIn.readObject();
System.out.println("载入登陆账号密码数据成功");
return userArray;
} catch (IOException | ClassNotFoundException e) {
//可能载入的类不存在
e.printStackTrace();
System.out.println("载入登陆账号密码数据失败");
return userArray;
}
}catch (FileNotFoundException fileNotFoundException) {
System.out.println("未找到登陆账号密码文件");
return userArray;
} catch (EOFException eofException) {
System.out.println("登陆账号密码数据为空");
return userArray;
}
}
}
两个数据存储类:
账号:
package DemoBook.Data;
import java.io.Serializable;
public class User implements Serializable {
private String account;
private String password;
private int power;
public User() {
}
public User(String account, String password) {
this.account = account;
this.password = password;
}
public int getPower() {
return power;
}
public void setPower(int power) {
this.power = power;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"account='" + account + '\'' +
", password='" + password + '\'' +
'}';
}
}
书籍的:
package DemoBook.Data;
import java.io.Serializable;
public class Book implements Serializable {
private String name;
private int price;
//通过日历类记录,然后转换成Date类,再变成long类型存储
private long publicDay;
/**
* 用于修改图书方法记录旧图书名称
*/
private String nameOld;
public Book() {
}
public Book(String name, int price, long publicDay, String nameOld) {
this.name = name;
this.price = price;
this.publicDay = publicDay;
this.nameOld = nameOld;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public long getPublicDay() {
return publicDay;
}
public void setPublicDay(long publicDay) {
this.publicDay = publicDay;
}
public String getNameOld() {
return nameOld;
}
public void setNameOld(String nameOld) {
this.nameOld = nameOld;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
", publicDay=" + publicDay +
'}';
}
}
treeSet排序方法类
按价格排序:
package DemoBook.Server;
import DemoBook.Data.Book;
import java.util.Comparator;
/**
* 价格降序,实现TreeSet的比较方法重写
*/
public class ComparePrice implements Comparator {
@Override
public int compare(Object o1, Object o2) {
//向集合中添加元素时,自动调用compare()
//根据返回值决定新元素插入位置
int x = 0;
Book b1 = (Book) o1;
Book b2 = (Book) o2;
if (b1.getPrice()<b2.getPrice()){
//负数,则是this小,最终输入排序为,小的在上面,如果
x = -1;
}else if (b1.getPrice()>b2.getPrice()){
//正数,则是this大
x = 1;
}else {
//不能存储数据一样大的数据,必须用其他元素继续比较,这里使用出版日期排序,同时要继续传递输入的Book数据
x = comparePublicDay(o1,o2,b1.getPublicDay(),b2.getPublicDay());
}
//返回x的值
return x ;
}
int comparePublicDay(Object o1, Object o2,long p1, long p2) {
int x = 0;
if (p1<p2){
//负数,则是this小,最终输入排序为,小的在上面,如果
x = -1;
}else if (p1>p2){
//正数,则是this大
x = 1;
}else {
//如果出版日期仍然一样,则比较名称的哈希值
Book b1 = (Book) o1;
Book b2 = (Book) o2;
x = compareName(b1.getName(),b2.getName());
}
//返回x的值
return x ;
}
int compareName(String n1,String n2) {
int x = 0;
if (n1.equals(n2)){
//如果名称也相同,则代表是同一本书,所以不存储。
x = 0;
}else{
//如果名称不相同,则默认返回1,即先输入的排在前面
x = 1;
}
//返回x的值
return x ;
}
}
按出版日期排序:
package DemoBook.Server;
import DemoBook.Data.Book;
import java.util.Comparator;
/**
* 出版日期由旧到新排序,实现TreeSet的重写
*/
public class ComparePubliceDay implements Comparator {
@Override
public int compare(Object o1, Object o2) {
//向集合中添加元素时,自动调用compare()
//根据返回值决定新元素插入位置
int x = 0;
Book b1 = (Book) o1;
Book b2 = (Book) o2;
if (b1.getPublicDay()<b2.getPublicDay()){
//负数,则是this小,最终输入排序为,小的在上面,如果
x = -1;
}else if (b1.getPublicDay()>b2.getPublicDay()){
//正数,则是this大
x = 1;
}else {
//不能存储数据一样大的数据,必须用其他元素继续比较,这里使用价格,同时要继续传递输入的Book数据
x = comparePublicDay(o1,o2,b1.getPrice(),b2.getPrice());
}
//返回x的值
return x ;
}
int comparePublicDay(Object o1, Object o2,long p1, long p2) {
int x = 0;
if (p1<p2){
//负数,则是this小,最终输入排序为,小的在上面,如果
x = -1;
}else if (p1>p2){
//正数,则是this大
x = 1;
}else {
//如果价格仍然一样,则比较名称的哈希值
Book b1 = (Book) o1;
Book b2 = (Book) o2;
x = compareName(b1.getName(),b2.getName());
}
//返回x的值
return x ;
}
int compareName(String n1,String n2) {
int x = 0;
if (n1.equals(n2)){
//如果名称也相同,则代表是同一本书,所以不存储。
x = 0;
}else{
//如果名称不相同,则默认返回1,即先输入的排在前面
x = 1;
}
//返回x的值
return x ;
}
}
客户端main界面
package DemoBook.Client;
import java.io.IOException;
public class Client {
public static void main(String[] args) {
try {
ClientView v = new ClientView();
while (true) {
v.operation();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}