一,项目背景
在线小说的由来可以追溯到互联网的普及和发展。随着互联网技术的不断进步,人们可以通过网络平台进行文字创作和阅读,这为在线小说的兴起提供了便利的条件。 最早的在线小说可以追溯到20世纪90年代末,当时一些文学爱好者开始在个人网站上创作小说,并通过网络进行发布。随着网络文学的发展,一些专门的文学网站和平台也相继出现,为作者和读者提供了更加便捷的交流和阅读方式。同时,一些作家也开始通过网络平台进行小说的连载和更新,吸引了大量的读者关注。 随着移动互联网的兴起,手机阅读成为了一种流行的阅读方式,许多在线小说也开始通过手机App进行发布和推广。一些知名的网络文学作家也因此获得了广泛的关注和认可,成为了文学界的新生力量。 总的来说,在线小说的由来是由互联网技术的发展和普及所推动的,它为文学创作和阅读提供了全新的可能性和机会,成为了当代文学的重要组成部分。
二,项目目标
建立一个服务端和客户端实现在线小说阅读,让它拥有登录和注册功能,登录后可以选择阅读小说,上传小说,下载小说三种基本功能.
三,系统功能实现
1,界面设计
客户端:
public class ClientTest {
static Socket socket=null;
Scanner sc =new Scanner(System.in);
static UserClientService userClientService;
public static void main(String[] args) throws IOException {
ClientTest clientTest = new ClientTest();
clientTest.clientInit();
//封装了接收数据和发送数据的api 功能
DataUtil dataUtil = new DataUtil(socket);
userClientService= new UserClientService(dataUtil,new ResultUtil(clientTest,dataUtil));
clientTest.welcome();
}
//初始化---连接服务器
public void clientInit() throws IOException {
//连接服务器
socket = new Socket();
socket.connect(new InetSocketAddress(8080));
}
//欢迎界面
public void welcome() throws IOException {
System.out.println("欢迎来到小说阅读系统");
System.out.println("1、登录系统");
System.out.println("2、注册用户");
System.out.println("3、退出系统");
System.out.println("输入序号进行操作");
String no = sc.nextLine();
if(no.equals("1")){
userClientService.login();
} else if (no.equals("2")) {//注册
userClientService.register();
}else {
System.exit(0);
}
}
//登录之后的二级菜单
public String menu(){
System.out.println("登录或者注册成功!!");
System.out.println("选择序号操作");
System.out.println("1、阅读小说");
System.out.println("2、上传小说");
System.out.println("3、下载小说");
System.out.println("4、退出");
String info = sc.nextLine();
return info;
}
}
服务端:
public static void main(String[] args) throws IOException, ClassNotFoundException, DocumentException {
new ServerApp().init();
}
public void init() throws IOException, ClassNotFoundException, DocumentException {
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(8080));
//监听
socket = serverSocket.accept();
postClientMessage();
//因为我服务器可能需要和客户端发送消息
//由于发送的不是对象 所以不需要对象流
}
public void postClientMessage() throws IOException, ClassNotFoundException, DocumentException {
//由于约定了发送的是messageEnttiy对象 所有通过对象流获取发送过来的对象
if (ois == null) {
os = socket.getOutputStream();
is = socket.getInputStream();
ois = new ObjectInputStream(is);
}
while (true) {
//发送一个对象
//获取输入流--->客户端可能给我发消息 读取客户端发送的消息
//接受客户端的数据
MessageEntity m = (MessageEntity) ois.readObject();
if (m.getOprator() == 1) {//登录
} else if (m.getOprator() == 3) {
//上传小说
} else if (m.getOprator() == 4) {//下载
} else if (m.getOprator() == 5) {//查询小说列表
} else if (m.getOprator() == 6) {
//阅读
}
}
}
}
}
2,接收登录
public void login() throws IOException {
System.out.println("请输入登录的用户名:");
String username = sc.nextLine();
System.out.println("请输入登录的密码:");
String password = sc.nextLine();
UserEntity userEntity = new UserEntity();
userEntity.setPassword(password);
userEntity.setUsername(username);
//chuangei fuwq
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(1);
messageEntity.setUserEntity(userEntity);
dataUtil.sendData(messageEntity);
//接受数据
String s = dataUtil.receiveData();
//根据服务器返回的结果取完成不同的处理
resultUtil.postUserResult(s);
}
3,判断登录
if (m.getOprator() == 1) {//登录
//客户端输入的用户名和密码
String result = userService.login(m.getUserEntity());
//把登录结果write给客户端
os.write(result.getBytes());
//为了服务器不停止---不断的阻塞读取客户端发送的消息
}
4.接收注册
public void register() throws IOException {
System.out.println("请输入注册的用户id:");
String userId = sc.nextLine();
System.out.println("请输入注册的用户账号:");
String username = sc.nextLine();
System.out.println("请输入注册的密码:");
String password = sc.nextLine();
UserEntity userEntity = new UserEntity();
userEntity.setUsername(username);
userEntity.setId(Integer.parseInt(userId));
userEntity.setPassword(password);
MessageEntity messageEntity= new MessageEntity();
messageEntity.setOprator(2);
messageEntity.setUserEntity(userEntity);
dataUtil.sendData(messageEntity);
String s = dataUtil.receiveData();
resultUtil.postUserResult(s);
}
5,判断注册
else if (m.getOprator() == 2) {
String register = userService.register(m.getUserEntity());
os.write(register.getBytes());
}
6,接收上传
else if(info.equals("2")){
System.out.println("请输入小说路径和名字:");
// d:\\music\\book\\天龙八部.txt
String bookPathName = sc.nextLine();
//为了获取文件的大小 ---百分比
File file = new File(bookPathName);
//整个文件的字节数
long length = file.length();
double l = (double) length;
System.out.println("文件长度="+length);
//上传----先读到内容---写出去网络
FileInputStream fis = new FileInputStream(file);
//服务器那边不知道你的文件名 ---告诉服务器文件名
String bookName =bookPathName.substring(bookPathName.lastIndexOf("\\\\"));
int total =0;
int k=1;
double temp=0.0;
while ((total=fis.read(bs))!=-1) {
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(3);
messageEntity.setBookName(bookName);
messageEntity.setContent(new String(bs,0,total));
dataUtil.sendData(messageEntity);
//如果接受成功 这一次读取的内容上传成功
String s = dataUtil.receiveData();
temp = (k*512/l)*100;
System.out.print(temp+"\r");
k++;
}
System.out.println(temp);
System.out.println("上传完成");
String r = ct.menu();
postBookResult(r);
}
7,判断上传
else if (m.getOprator() == 3) {
//上传小说
//当次上传小说的内容
String content = m.getContent();
if (content.equals("end")) {
//一部小说已经传完
uploadFile = null;
continue;
}
//这部分内容写到--对应的文件夹当中去---
//1、文件文件
if (uploadFile == null) {
uploadFile = new File(Contain.bookPath + "\\" + m.getBookName());
}
if (!uploadFile.exists()) {//如果文件不存在则创建
uploadFile.createNewFile();
} else {
if (!XMLUtil.isEmpty(m.getBookName())) {//服务器已经存在小说 重写上传
uploadFile.delete();//先删除
uploadFile.createNewFile();//重写创建
}
}
FileWriter fileWriter = new FileWriter(uploadFile, true);
fileWriter.write(content);
//这一次成功
os.write("success".getBytes());
fileWriter.close();
}
8,接收下载
else if (info.equals("3")) {
/**
// * 1、读取服务器上面所有的小说
// * 安装序列排好
// * 输入序号
// * 2--天龙八部 回车的时候 应该往服务器发送一条消息
// * 服务器接受到整个消息之后 应该 把对应的小说内容 先读取到内存---往网络上写
// *
// * 客户端服务器的内容 ---写道本地磁盘
// * 进行下载-----下载路径存到本地路径---D:\\book
// */
//下载之前先要做查询
List<String> list = bookClientService.queryPrintAllBook(dataUtil);
System.out.println("请输入下面显示的小说名字进行下载");
list.stream().forEach(s -> System.out.println(s));
String bookName="";
while (true){
bookName = sc.nextLine();
String finalBookName = bookName;
long count = list.stream().filter(s -> s.equals(finalBookName)).count();
if(count==0){//输入的小说名字不存在
System.out.println("请输入合理的小说名字");
}else {
break;
}
}
//收集到用户输入的小说名字
MessageEntity messageEntity = new MessageEntity();
messageEntity.setOprator(4);
messageEntity.setBookName(bookName);
dataUtil.sendData(messageEntity);
File file = new File(Contain.downloadPath + "\\" + bookName);
if (!file.exists()) {
file.createNewFile();
}else {
file.delete();
file.createNewFile();
}
while (true) {
String downLoadContent = dataUtil.receiveData();
//4
//String[] split = downLoadContent.split(Contain.FLAGSTR);
if (downLoadContent.endsWith("end")) {
System.out.println("下载完成!!!!!!!!!!!!!!!");
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(downLoadContent.replaceAll("end","").getBytes());
break;
}
// System.out.println("文件长度字节数="+split[2]+" "+"下载进度="+split[1]+"%"+" 下载的字节数="+split[3] );
FileOutputStream fos = new FileOutputStream(file, true);
fos.write(downLoadContent.getBytes());
}
String s = ct.menu();
postBookResult(s);
}
9,判断下载
else if (m.getOprator() == 4) {//下载
//获取现需要下载的小说的名字
String bookName = m.getBookName();
String downLoadPath = Contain.bookPath + "\\" + bookName;
File downLoadFile = new File(downLoadPath);
long length = downLoadFile.length();
FileInputStream fis = new FileInputStream(downLoadFile);
DecimalFormat df = new DecimalFormat("#.0");
int total = 0;
double percent = 0.0;
while ((total = fis.read(bs)) != -1) {
String message = new String(bs, 0, total);
//百分比
percent+= total;
String format = df.format((percent / length) * 100);
//xxxxj#1.2j#1234564
message+=Contain.FLAGSTR+format+Contain.FLAGSTR+length+Contain.FLAGSTR+percent;
System.out.println(message);
os.write(message.getBytes());
}
//读完了
os.write("end".getBytes());
四,遇到的困难
1,客户端与服务端连上后,执行登录操作时却断开了连接
原因:登录完成后没有下一步操作,没有给阻塞,使服务器直接结束运行
解决,在执行完登录后调用下一个方法,并添加判断阻塞
2,登录时出现如果第一次输入错误信息,即使第二次输入信息正确也无法登录
原因,把判断登录信息是否正确的一个集合设置为了全局变量
解决,直接去掉这个集合
五,收获
学习到了网络编程的实际运用,知道了IO流,多线程等知识的具体运用场景,加强了面向对象的思维,学到了如何用封装制作出一个个优美的方法,让界面看起来更加简洁.
总的来说,这次项目实践让我所学的知识进行了一个融会贯通,认识到了还有许多不足的地方,java语言博大精深,值得我们继续认真学习.