1.案例需求
完成在线小说阅读项目,主要分为以下几个任务:
任务1:创建客户端、服务器端,完成简单通信
任务2:完成登录、注册、退出、返回功能
任务3:完成小说查询列表的功能
任务4:完成在线阅读小说功能
任务5:完成下载小说功能
任务6:完成上传小说功能
2.编程思路
-
客户端的编程思路可以概括为以下几个关键步骤:
- 初始化资源:创建必要的资源,如Scanner用于输入,Socket用于网络通信,以及ObjectInputStream和ObjectOutputStream用于对象的序列化和反序列化。
- 主菜单展示:编写showFirstMenu方法,展示给用户的主菜单,包括登录、注册和退出选项。
- 注册功能实现:在register方法中,通过控制台接收用户输入的用户名和密码,创建User对象,并将其封装在Map中,通过Socket发送给服务器。
- 登录功能实现:在login方法中,接收用户输入的用户名和密码,与注册过程类似,创建User对象并发送至服务器,根据服务器响应判断登录是否成功。
- 网络通信方法:编写startNet方法来初始化网络连接和相关的输入输出流。编写closeNet方法来关闭网络连接和资源,确保在每个网络操作后都能正确关闭资源。
- 二级菜单展示:在showSecondMenu方法中,展示给已登录用户的二级菜单,包括小说列表、在线阅读、下载小说和上传小说功能。
- 小说列表展示:在showNovelList方法中,通过Socket向服务器请求小说列表,接收并展示小说信息。
- 在线阅读功能:在onlineRead方法中,允许用户选择小说并阅读。需要实现分页阅读,提供上一页和下一页的功能。
- 下载小说功能:在downLoad方法中,允许用户选择并下载小说,将服务器传来的小说文本写入本地文件。
- 上传小说功能:在upLoad方法中,允许用户上传本地小说文件到服务器,需要用户输入小说信息和选择本地文件。
- 错误处理和资源管理:在每个网络操作和文件操作后,使用try-catch-finally结构来处理可能发生的异常,并确保资源(如流和Socket连接)被正确关闭。
- 用户界面反馈:在每个关键操作后,给予用户明确的反馈信息,如登录成功、注册成功、下载完成等。
- 循环和条件判断:使用循环和条件判断来处理用户的输入,确保用户能够接收到正确的提示,并能够在操作失败时重新输入。
- 配置文件加载:使用Properties对象加载配置文件,获取服务器的端口号、文件保存路径等配置信息。
- 多线程考虑:如果客户端需要处理多个用户的并发操作,考虑使用多线程来实现。
初始化服务器:创建ServerSocket对象并监听特定端口,等待客户端的连接。
-
服务端的编程思路主要包括以下几个关键步骤:
- 接受客户端连接:在无限循环中调用serverSocket.accept()方法,接受客户端的连接请求,并为每个连接创建一个新的线程。
- 创建线程处理类:为每个客户端连接创建一个TxtServerThread线程对象,该对象将处理来自客户端的具体请求。
- 读取和解析用户数据:在TxtServerThread类中,通过ReadeXml方法读取和解析User.xml文件,将用户数据加载到内存中,以便进行登录验证。
- 网络通信初始化:在TxtServerThread的run方法中,调用startNet方法初始化网络通信,获取输入输出流以及对象输入输出流。
- 接收客户端请求:从客户端读取请求,通常是一个包含操作码和数据的Map对象。
- 根据操作码处理请求:根据客户端请求的操作码(如登录、注册、查询小说列表、在线阅读、下载、上传等),调用相应的处理方法。
- 处理登录和注册请求:在doLogin和doRegister方法中,根据用户请求进行用户验证或注册新用户,并返回相应的响应信息。
- 处理小说列表请求:在doShowNovelList方法中,解析Book.xml文件,并将小说列表发送给客户端。
- 处理在线阅读请求:在doOnlineRead方法中,根据客户端请求的页码和小说名,读取小说文本的指定部分并发送给客户端。
- 处理下载请求:在download方法中,根据客户端请求的小说名,读取服务器上的小说文件内容,并发送给客户端。
- 处理上传请求:在upload方法中,接收客户端上传的小说信息和文本内容,将信息写入Book.xml文件,并将文本内容保存到服务器。
- 错误处理和资源管理:在每个网络和文件操作后,使用try-catch-finally结构来处理可能发生的异常,并确保资源(如流和Socket连接)被正确关闭。
- 关闭网络连接:在closeNet方法中,关闭与客户端的网络连接和相关资源。
- 多线程管理:确保服务器能够同时处理来自多个客户端的请求,每个请求在独立的线程中处理。
- 配置文件加载:使用Properties对象加载配置文件,获取服务器的文件保存路径等配置信息。
- XML操作:使用dom4j库对XML文件进行读取、修改和写入操作。
3.案例源码
Client源码:
package novel2good;
import java.io.*;
import java.net.Socket;
import java.util.*;
/**
* @Version:1.0
* @Description: TODO(一句话描述该类的功能)
* @Date: 2024/7/15 15:49
* @Author: wjy
*/
public class Client {
Scanner input = new Scanner(System.in);
Socket socket = null;
InputStream is = null;
OutputStream os = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
List<Book> booksList = new ArrayList<>();
int page = 1;
Properties props = new Properties();
public static void main(String[] args) {
new Client().showFirstMenu();
}
//编写显示一级菜单
public void showFirstMenu() {
System.out.println("=======欢迎进入飞思小说网=======");
System.out.println("\n\n");
System.out.println("1.登录");
System.out.println("2.注册");
System.out.println("0.退出");
System.out.print("请选择:");
int choose = input.nextInt();
switch (choose) {
case 0:
System.out.println("感谢使用本软件");
System.exit(0);
break;
case 1:
login();
break;
case 2:
register();
break;
default:
System.out.println("输入有误,请重新输入!!!");
showFirstMenu();
break;
}
}
/**
* 注册操作
*/
private void register() {
//todo 注册待完成
System.out.print("请输入要注册用户名:");
String username = input.next();
System.out.print("请输入要注册的密码:");
String password = input.next();
/* System.out.print("请输入要注册的性别:");
String sex = input.next();*/
User user = new User(username, password);
Map<String, Object> map = new HashMap<>();
map.put("op", OpCanstant.OP_REGISTER);
map.put("data", user);
try {
//开启网络
startNet();
//发送数据
oos.writeObject(map);
oos.flush();//刷新,把缓冲区数据写出去
socket.shutdownOutput();
//接收服务器的信息
String reply = ois.readUTF();
System.out.println("【友情提示】:" + reply);
if ("注册成功,用户可以登录了".equals(reply)) {
//注册成功,开始登录
showFirstMenu();
} else {
//注册失败失败,回到一级菜单
showFirstMenu();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeNet();
}
}
/**
* 登录操作
*/
private void login() {
//输入用户密码
System.out.print("请输入用户名:");
String username = input.next();
System.out.print("请输入密码:");
String password = input.next();
User user = new User(username, password);
Map<String, Object> map = new HashMap<>();
//操作 1: 称为魔法数字, 可读性差, 在实际开发中,避免魔法数字
// 使用常量替换
map.put("op", OpCanstant.OP_LOGIN);
map.put("data", user);
try {
//开启网络
startNet();
//发送数据
oos.writeObject(map);
oos.flush();//刷新,把缓冲区数据写出去
socket.shutdownOutput();
//接收服务器的信息
String reply = ois.readUTF();
System.out.println("【友情提示】:" + reply);
if ("登录成功".equals(reply)) {
//登录成功,进入二级菜单
showSecondMenu();
} else {
//登录失败,回到一级菜单
showFirstMenu();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeNet();
}
}
/**
* 开启网络
*/
public void startNet() throws IOException {
//创建Socket对象
socket = new Socket("127.0.0.1", 9666);
//得到输入输出流
is = socket.getInputStream();
os = socket.getOutputStream();
//初始化对象流
oos = new ObjectOutputStream(os);
ois = new ObjectInputStream(is);
}
/**
* 关闭网络, 关闭资源
* ctrl + alt + t 包裹代码的快捷键
*/
public void closeNet() {
//倒序关 先开的后关
try {
if (oos != null) oos.close();
if (ois != null) ois.close();
if (socket != null) socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void showSecondMenu() {
//todo 二级菜单
System.out.println("===========二级菜单=============");
System.out.println("1.小说列表");
System.out.println("2.在线阅读");
System.out.println("3.下载小说");
System.out.println("4.上传小说");
System.out.println("0.返回上一级");
System.out.print("请选择:");
int choose = input.nextInt();
switch (choose) {
case 0:
showFirstMenu();
break;
case 1:
showNovelList();
break;
case 2:
onlineRead();
break;
case 3:
downLoad();
break;
case 4:
upLoad();
break;
default:
System.out.println("输入有误,请重新输入!!!");
showFirstMenu();
break;
}
}
private void downLoad() {
String bname=null;
if (booksList == null || booksList.isEmpty()) {
System.out.println("该小说列表中没有小说,请先获取小说列表");
showSecondMenu();
} else {
for (Book book : booksList) {
System.out.println(book.getBookId() + "." + book.getName());
}
}
System.out.println("请选择你要下载的小说:");
int i = input.nextInt();
if (i < 1 || i > booksList.size()) {
System.out.println("超出小说范围啦!");
System.out.println("========================");
showSecondMenu();
}else {
for (Book book : booksList) {
if (i==book.getBookId()){
bname=book.getName();
break;
}
}
}
Map<String, Object> map = new HashMap<>();
map.put("op", OpCanstant.OP_DOWNLOAD);
map.put("data", bname);
BufferedWriter bw=null;
try {
startNet();
oos.writeObject(map);
oos.flush();
map=(Map)ois.readObject();
String txt = map.get("data").toString();
props.load(new FileInputStream("src/novel.properties"));
bw=new BufferedWriter(new FileWriter(props.getProperty("ClientsavePath")+"/"+bname+".txt"));
StringBuffer stringBuffer = new StringBuffer();
char[] chars = txt.toCharArray();
for (int j = 0; j < chars.length; j++) {
stringBuffer.append(chars[j]);
if (j%100==0&&j!=0){
bw.write(stringBuffer.toString());
stringBuffer=stringBuffer.delete(0,101);
bw.newLine();
bw.flush();
}
}
if (bw!=null)bw.close();
System.out.println("下载完成");
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
closeNet();
showSecondMenu();
}
}
private void upLoad() {
System.out.println("==========上传小说=========");
System.out.print("请输入要上传的小说名:");
String bookname = input.next();
System.out.print("请输入要上传的小说作者:");
String author = input.next();
System.out.print("请输入要上传的小说描述:");
String desc = input.next();
System.out.println("请选择类型:1.武侠 2.言情 3.科幻 4.玄幻");
int typeId = input.nextInt();
String type = "";
switch (typeId) {
case 1:
type = "武侠";
break;
case 2:
type = "言情";
break;
case 3:
type = "科幻";
break;
case 4:
type = "玄幻";
break;
default:
System.out.println("选择的类型有误");
showSecondMenu();
}
Book book = new Book(bookname, author, desc, type);
Map<String, Object> map = new HashMap<>();
map.put("op", OpCanstant.OP_UPLOAD);
map.put("data", book);
BufferedReader br = null;
try {
startNet();
props.load(new FileInputStream("src/novel.properties"));
br = new BufferedReader(new FileReader(props.getProperty("ClientsavePath")+"/" + bookname + ".txt"));
StringBuffer stringBuffer = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
stringBuffer.append(line);
}
map.put("txt", stringBuffer.toString());
oos.writeObject(map);
oos.flush();
socket.shutdownOutput();
String reply = ois.readUTF();
System.out.println(reply);
socket.shutdownInput();
} catch (FileNotFoundException e) {
System.out.println("本地没有该小说文件" );
showSecondMenu();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (br!=null)br.close();
closeNet();
showSecondMenu();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void secondOnlineRead(String bookName) {
Map<String, Object> map = new HashMap<>();
map.put("op", OpCanstant.OP_READ);
map.put("data", bookName);
map.put("page", page);
try {
//开启网络
startNet();
//发送数据
oos.writeObject(map);
oos.flush();//刷新,把缓冲区数据写出去
socket.shutdownOutput();
//接收服务器的信息
String s = ois.readUTF();
System.out.println(s);
if (s.equals("这已经是最后一页了")) {
page--;
}
System.out.println("==================================");
socket.shutdownInput();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeNet();
showPage(bookName);
}
}
public void showPage(String bookName) {
System.out.println("1.上一页 2.下一页");
System.out.println("请选择(按除以上选项的任意数字键返回二级菜单:)");
switch (input.nextInt()) {
case 1:
upPage(bookName);
break;
case 2:
downPage(bookName);
break;
default:
page = 1;
showSecondMenu();
break;
}
}
private void downPage(String bookName) {
page++;
secondOnlineRead(bookName);
}
private void upPage(String bookName) {
if (page == 1) {
System.out.println("这已经是第一页了");
showSecondMenu();
}
page--;
secondOnlineRead(bookName);
}
public void onlineRead() {
if (booksList == null || booksList.isEmpty()) {
System.out.println("该小说列表中没有小说,请先获取小说列表");
showSecondMenu();
} else {
for (Book book : booksList) {
System.out.println(book.getBookId() + "." + book.getName());
}
}
System.out.println("请选择你要阅读的小说:");
int i = input.nextInt();
if (i < 1 || i > booksList.size()) {
System.out.println(i);
System.out.println("没有对应的小说,你输入的可能不在范围内。请重新输入");
onlineRead();
} else {
for (Book book : booksList) {
if (i == book.getBookId()) {
String bookName = book.getName();
secondOnlineRead(bookName);
break;
}
}
}
}
public void showNovelList() {
System.out.println("序号\t\t名称\t\t\t作者\t\t\t类型\t\t\t描述");
Map<String, Object> map = new HashMap<>();
map.put("op", OpCanstant.OP_LIST);
try {
//开启网络
startNet();
//发送数据
oos.writeObject(map);
oos.flush();//刷新,把缓冲区数据写出去
socket.shutdownOutput();
//接收服务器的信息
booksList = (List<Book>) ois.readObject();
if (booksList == null || booksList.isEmpty()) {
System.out.println("该小说列表中暂无小说数据");
System.out.println("===============================================================");
showSecondMenu();
} else {
for (Book book : booksList) {
System.out.println(book.getBookId() + "\t\t" + book.getName() + "\t\t" + book.getAuthor() + "\t\t" + book.getType() + "\t\t" + book.getDescription());
}
socket.shutdownInput();
System.out.println("===============================================================");
showSecondMenu();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
closeNet();
}
}
}
Serve源码
public class TxtNovelServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9666);
System.out.println("服务器启动");
while(true){
Socket socket = serverSocket.accept(); //阻塞的
System.out.println("有一个客户端连接了");
//创建线程对象
new TxtServerThread(socket).start();
}
}
}
ServerThread源码:
package novel2good;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 服务器的处理客户端请求的线程
*/
public class TxtServerThread extends Thread {
private Socket socket;
InputStream is = null;
OutputStream os = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
private static List<User> users = new ArrayList<>();
List<Book> books = new ArrayList<>();
//一旦这个线程类加载, 自动读取User.xml.并解析 保存User集合
public void ReadeXml() {
SAXReader saxReader = new SAXReader();
try {
//读取xml文件得到Document对象
Document document = saxReader.read("src/xml/User.xml");
//得到根元素
Element rootElement = document.getRootElement();
//获取user子元素
List<Element> userEles = rootElement.elements("user");
//遍历
for (Element userEle : userEles) {
//创建一个User对象
User user = new User();
//获取元素的属性
int userId = Integer.parseInt(userEle.attributeValue("userId"));
user.setUserId(userId);
//获取user的子元素
List<Element> childEles = userEle.elements();
for (Element childEle : childEles) {
if (childEle.getName().equalsIgnoreCase("username")) {
user.setUsername(childEle.getText());
}
if (childEle.getName().equalsIgnoreCase("password")) {
user.setPassword(childEle.getText());
}
}
//把User对象保存集合
users.add(user);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
public TxtServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//启动网络
startNet();
//接收客户端信息
Map<String, Object> map = (Map<String, Object>) ois.readObject();
socket.shutdownInput();
//获取操作符
int op = (Integer) map.get("op");
switch (op) {
case OpCanstant.OP_LOGIN:
doLogin(map);
break;
case OpCanstant.OP_REGISTER:
doRegister(map);
break;
case OpCanstant.OP_LIST:
doShowNovelList();
break;
case OpCanstant.OP_DOWNLOAD:
download(map);
break;
case OpCanstant.OP_UPLOAD:
upload(map);
break;
case OpCanstant.OP_READ:
doOnlineRead(map);
break;
default:
System.out.println("没有这个选项");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (DocumentException e) {
throw new RuntimeException(e);
} finally {
closeNet();
}
}
public void doOnlineRead(Map<String, Object> map) {
int page = (int) map.get("page");
String bookName = (String) map.get("data");
int skip = (page - 1) * SysCanstant.LIMIT;
FileReader fr = null;
try {
fr = new FileReader("D:/novelServe/" + bookName + ".txt");
fr.skip(skip);
StringBuffer stringBuffer = new StringBuffer("");
int ch = -1;
for (int i = 0; i < SysCanstant.LIMIT && (ch = fr.read()) != -1; i++) {
stringBuffer.append((char) ch);
}
if (stringBuffer.length() == 0) {
System.out.println("这已经是最后一页了");
}
oos.writeUTF(stringBuffer.toString());
oos.flush();
socket.shutdownOutput();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (fr!=null)fr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void WriteBookXml(Book book) throws DocumentException, IOException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/xml/Book.xml");
Element rootElement = document.getRootElement();
int maxId = rootElement.elements().size();
;
book.setBookId(maxId + 1);
//2,添加元素
Element newUserEle = rootElement.addElement("book");
//设置属性
newUserEle.addAttribute("bookId", String.valueOf(maxId + 1));
//添加子元素
newUserEle.addElement("name").setText(book.getName());
newUserEle.addElement("author").setText(book.getAuthor());
newUserEle.addElement("description").setText(book.getDescription());
newUserEle.addElement("type").setText(book.getType());
//上述步骤,都是保存在内存中
//把内存的数据写到xml
//输出格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");//默认UTF-8
FileWriter fw = new FileWriter("src/xml/Book.xml");
XMLWriter xmlWriter = new XMLWriter(fw, outputFormat);
//写入
xmlWriter.write(document);
//关闭资源
fw.close();
xmlWriter.close();
}
Properties props = new Properties();
public void upload(Map<String, Object> map) throws DocumentException, IOException {
Book book = (Book) map.get("data");
WriteBookXml(book);
books.add(book);
String txt = (String) map.get("txt");
BufferedWriter bw = null;
String reply = "";
props.load(new FileInputStream("src/novel.properties"));
bw = new BufferedWriter(new FileWriter(props.getProperty("ServesavePath")+"/" + book.getName() + ".txt"));
char[] chars = txt.toCharArray();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < chars.length; i++) {
stringBuffer.append(chars[i]);
if (i % 100 == 0 && i != 0) {
bw.write(stringBuffer.toString());
stringBuffer = stringBuffer.delete(0, 101);
bw.newLine();
bw.flush();
}
}
//发送
reply = "上传成功";
oos.writeUTF(reply);
oos.flush();
socket.shutdownOutput();
if (bw!=null)bw.close();
}
public void download(Map<String, Object> map) {
String bname = (String) map.get("data");
BufferedReader br=null;
try {
Properties props = new Properties();
props.load(new FileInputStream("src/novel.properties"));
br=new BufferedReader(new FileReader(props.getProperty("ServesavePath")+"/"+bname+".txt"));
StringBuffer stringBuffer = new StringBuffer();
String line=null;
while ((line=br.readLine())!=null){
stringBuffer.append(line);
}
map.put("data",stringBuffer);
oos.writeObject(map);
oos.flush();
socket.shutdownOutput();
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if (br!=null)br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public void doShowNovelList() throws DocumentException, IOException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/xml/Book.xml");
Element rootElement = document.getRootElement();
if (rootElement.elements().size() == 0) {
books = null;
} else {
for (Object element : rootElement.elements("book")) {
Element book = (Element) element;
int bookId = Integer.parseInt(book.attributeValue("bookId"));
Element bookName = book.element("name");
String bookNameText = bookName.getText();
Element bookAuthor = book.element("author");
String bookAuthorText = bookAuthor.getText();
Element bookDescription = book.element("description");
String bookDescriptionText = bookDescription.getText();
Element bookType = book.element("type");
String bookTypeText = bookType.getText();
Book book1 = new Book(bookId, bookNameText, bookAuthorText, bookDescriptionText, bookTypeText);
books.add(book1);
}
}
oos.writeObject(books);
oos.flush();
socket.shutdownOutput();
}
/**
* 处理客户端的登录请求
*/
private void doRegister(Map<String, Object> map) throws IOException, DocumentException {
User user = (User) map.get("data");
String reply = "注册失败,用户已注册,请直接登录";
if (!checkUser(user)) {
reply = "注册成功,用户可以登录了";
WriteXml(user);
}
oos.writeUTF(reply);
oos.flush();
socket.shutdownOutput();
}
public void WriteXml(User user) throws DocumentException, IOException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/xml/User.xml");
Element rootElement = document.getRootElement();
List elements = rootElement.elements();
int id = elements.size();
//2,添加元素
Element newUserEle = rootElement.addElement("user");
//设置属性
newUserEle.addAttribute("userId", String.valueOf(id + 1));
//添加子元素
newUserEle.addElement("username").setText(user.getUsername());
newUserEle.addElement("password").setText(user.getPassword());
//上述步骤,都是保存在内存中
//把内存的数据写到xml
//输出格式
OutputFormat outputFormat = OutputFormat.createPrettyPrint();
outputFormat.setEncoding("UTF-8");//默认UTF-8
FileWriter fw = new FileWriter("src/xml/User.xml");
XMLWriter xmlWriter = new XMLWriter(fw, outputFormat);
//写入
xmlWriter.write(document);
//关闭资源
fw.close();
xmlWriter.close();
}
/**
* 处理客户端的登录请求
*/
private void doLogin(Map<String, Object> map) throws IOException {
ReadeXml();
User user = (User) map.get("data");
String reply = "登录失败";
if (checkUser(user)) {
reply = "登录成功";
}
oos.writeUTF(reply);
oos.flush();
socket.shutdownOutput();
}
/**
* 判断用户是否存在
*
* @param user
* @return true: 存在 false: 不存在
*/
public boolean checkUser(User user) {
for (User user1 : users) {
if (user1.getUsername().equalsIgnoreCase(user.getUsername())
&& user1.getPassword().equals(user.getPassword())) {
return true;
}
}
return false;
}
/**
* 开启网络
*/
public void startNet() throws IOException {
//得到输入输出流
is = socket.getInputStream();
os = socket.getOutputStream();
//初始化对象流
oos = new ObjectOutputStream(os);
ois = new ObjectInputStream(is);
}
/**
* 关闭网络, 关闭资源
* ctrl + alt + t 包裹代码的快捷键
*/
public void closeNet() {
//倒序关 先开的后关
try {
if (oos != null) oos.close();
if (ois != null) ois.close();
if (socket != null) socket.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}
}
4.小结
在线小说阅读系统的代码实现涉及的关键知识点有
- 面向对象编程:类和对象的定义与使用。封装、继承和多态的应用。
- Socket 网络编程:服务器端使用 ServerSocket 监听端口并接受客户端连接。客户端使用 Socket 连接服务器。利用输入输出流进行数据的发送和接收。
- 多线程处理:服务器端为每个客户端连接创建新线程处理请求。
- 文件I/O操作:使用 FileReader、BufferedReader 等进行文件读取。使用 FileWriter、BufferedWriter 等进行文件写入。
- XML文件处理:使用dom4j库解析和生成XML文件。XML文件的读取、修改、创建和保存。
- 属性文件操作:使用 Properties 类加载和读取属性文件。
- 集合框架使用:List、Map 等集合的使用来存储和管理数据。
- 异常处理:使用 try-catch-finally 语句块处理异常和资源释放。
- 数据序列化与反序列化:使用 ObjectOutputStream 和 ObjectInputStream 进行对象的序列化和反序列化。
- 基本数据结构操作:使用 StringBuffer、ArrayList 等数据结构。
- 控制台输入输出:使用 Scanner 类进行控制台输入。
- 网络通信协议:定义通信协议,使用特定的操作码(如登录、注册等)。
- 用户认证:实现用户登录和注册的用户认证机制。
- 资源管理:合理管理网络资源和文件资源,确保及时关闭。
- 文本处理:字符串操作,如拼接、分割、查找等。
- 分页显示:在线阅读小说时,实现内容的分页显示。
- 文件路径处理:文件路径的构建和处理。
- 编码规范:遵循良好的编码规范,如驼峰命名法、代码注释等。
- 安全性考虑:考虑输入验证和异常安全,避免潜在的安全隐患。
- 用户界面反馈:为用户提供清晰的操作反馈信息。
这些知识点构成了在线小说阅读系统开发的基础,涵盖了从前端用户交互到后端数据处理的全过程。