基于java的在线小说阅读系统

提示:

文章目录

前言

一、项目介绍

1.项目目的

2.任务需求

二、技术介绍

三、代码展示

1.文件格式

2. 封装类

3.客户端特有类

4.服务端特有类

任务一:客户端和服务器端通信连接

任务二:登录、注册、退出功能

任务三:小说查询列表功能

任务四:在线阅读小说功能

任务五:上传小说功能

任务六:下载小说功能

 5.错误提示

6.效果展示

总结


前言

        经过一段时间的Java知识学习,对这一段学习进行检验,因此做一个在线小说阅读系统项目,看自己的知识是否巩固。

        随着信息技术水平的空前提高,大众对于获取信息的方式有了越来越高的要求。作为一种新兴的阅读载体,电子书刊因其方便快捷的特性日益普及。图书馆作为搜集、整理图书文化资料的公共文化机构,势必要紧跟这一时代步伐以谋求进一步发展。传统的图书借阅方式虽重要且暂时不可替代,却无法完全满足读者的进一步需求。这时,将电子书纳入日常的借阅体系,为读者提供多样化的选择,不失为一个好的解决办法。

一、项目介绍

1.项目目的

        本系统的主要目标是设计并实现一个基于Java的在线阅读小说。项目需要实现关于服务端和客户端的连接,在此基础上,用户可以进行登录注册,并在登录注册后进行如阅读小说、下载小说、上传小说等功能。

2.任务需求

任务1:创建客户端、服务器端,完成简单通信

任务2:完成登录、注册、退出、返回功能

任务3:完成小说查询列表的功能

任务4:完成在线阅读小说功能

任务5:完成下载小说功能

任务6:完成上传小说功能

二、技术介绍

  • 应用面向对象的思想编写简单项目

  • 熟练操作Socket编程

  • 熟练操作文件I/O读写的操作

  • 了解配制文件的解析方式

  • 了解多线程的应用

  • 了解xml文件作为轻量级的存储,以及使用dom4j解析xml文件

三、代码展示

1.文件格式

我的整个项目分为两个部分——Client和Server

Client存放客户端方法

其中Contain方法和MessageEntity方法以及UserEntity方法是用来封装常量和变量的 ClientTest方法是客户端运行的代码

UserService方法用来判断登录与注册的成功与否

ResultUtil方法处理二级菜单

Server存放服务端方法 与Cilent方法的Contain方法和MessageEntity方法以及UserEntity方法作用一样

ServerApp方法是服务端运行的代码

UserService方法用来判断登录与注册的成功与否

XMLUtil方法用来处理xml的相关

2. 封装类

上面提到,项目中有很多共用的封装类,用来封装客户端和服务端都会用到的,或者代码需要经常用到的,就会单独封装

Contain类:用来存放经常使用的常量

//客户端的Contain
public class Contain {
   public static final String downloadPath="D:\\feisi_Java\\stream\\book";  //存放下载小说的路径
   public static final String bookPath  = "D:\\feisi_Java\\stream\\Server\\book"; //存放全部小说

    public static final String REGISTERSUCRESULT="100"; //注册成功
    public static final String REGISTERFAIRESULT="101"; //注册失败

    public static final String LOGINSUCRESULT="200";  //登录成功
    public static final String LOGINFAIRESULT="201";  //登录失败

    public static final String FLAGSTR = "j#";
}
//服务端的Contain
public class Contain {
    //服务器上存放小说的路径
    public static final String bookPath  = "D:\\feisi_Java\\stream\\Server\\book";
    public static final String FLAGSTR = "j#";
}

MessageEntity类:用来存放用户端和服务端都需要用到的交互信息

一定要实现Serializable接口

public class MessageEntity implements Serializable {
   
    private String bookName;
    private String content;
    private int page;

    public int getPage() { return page; }

    public void setPage(int page) { this.page = page; }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    private int oprator;
    private UserEntity userEntity;

    public int getOprator() {
        return oprator;
    }

    public void setOprator(int oprator) {
        this.oprator = oprator;
    }

    public UserEntity getUserEntity() {
        return userEntity;
    }

    public void setUserEntity(UserEntity userEntity) {
        this.userEntity = userEntity;
    }
}

UserEntity方法:用户的信息定义

一定要实现Serializable接口

public class UserEntity implements Serializable {
    private String username;
    private String password;
    private Integer id;


    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

3.客户端特有类

BookClientService类:用来查询服务器上的小说列表

public class BookClientService {
    public List<String> queryPrintAllBook(DataUtil dataUtil) throws IOException {
        List<String> list = new ArrayList<>();
        MessageEntity messageEntity =new MessageEntity();
        //只需要带一个操作
        messageEntity.setOprator(5);
        dataUtil.sendData(messageEntity);
        //阻塞
        String s = dataUtil.receiveData();
        String[] split = s.split("-");
        for (String s1 : split) {
            list.add(s1);
        }
        return list;
    }
}

DataUtil类:用来接收和发送服务端数据

public class DataUtil {
    static  byte[] bs  = new byte[512];
    Socket socket;
    ObjectOutputStream oos = null;
    public DataUtil(Socket socket){
        this.socket=socket;
    }

    public void sendData(MessageEntity messageEntity) throws IOException {
        OutputStream os = socket.getOutputStream();
        if(oos==null){
           oos= new ObjectOutputStream(os);
        }
        //写到服务器
        oos.writeObject(messageEntity);
    }

    //接受数据
    public String receiveData() throws IOException {
        InputStream is = socket.getInputStream();
        int total = is.read(bs);
        //把服务器相应的消息 判断一下
        String result = new String(bs,0,total);
        return result;
    }
}

UserCilentSercive类:专门用来记录登录和注册的输入

public class UserClientService {
    DataUtil dataUtil;
    ResultUtil resultUtil;
    public UserClientService(DataUtil dataUtil,ResultUtil resultUtil){
        this.dataUtil =dataUtil;
        this.resultUtil = resultUtil;
    }
    Scanner sc =new Scanner(System.in);
    public void login() throws IOException, InterruptedException {

        System.out.println("请输入登录的用户名:");
        String username = sc.nextLine();
        System.out.println("请输入登录的密码:");
        String password = sc.nextLine();
        UserEntity userEntity = new UserEntity();
        userEntity.setPassword(password);
        userEntity.setUsername(username);

        MessageEntity messageEntity = new MessageEntity();
        messageEntity.setOprator(1);
        messageEntity.setUserEntity(userEntity);


        dataUtil.sendData(messageEntity);

        //接受数据
        String s = dataUtil.receiveData();
        //根据服务器返回的结果取完成不同的处理
        resultUtil.postUserResult(s);
    }

    public void register() throws IOException, InterruptedException {

        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);
    }
}

ResultUtil类:客户端的二级菜单代码

public class ResultUtil {
    ClientTest ct;
    DataUtil dataUtil;

    byte[] bs = new byte[512];

    BookClientService bookClientService = new BookClientService();

    Scanner sc = new Scanner(System.in);


    public ResultUtil(ClientTest ct, DataUtil dataUtil) {
        this.ct = ct;
        this.dataUtil = dataUtil;
    }

    public void postUserResult(String result) throws IOException, InterruptedException {
        if (result.equals(Contain.LOGINSUCRESULT)) {
            System.out.println("登录成功");
            String info = ct.menu();
            postBookResult(info);
        } else if (result.equals(Contain.LOGINFAIRESULT)) {
            System.out.println("登录失败--重写操作");
            ct.welcome();
        } else if (result.equals(Contain.REGISTERSUCRESULT)) {
            System.out.println("注册成功");
            String info = ct.menu();
            postBookResult(info);
        } else if (result.equals(Contain.REGISTERFAIRESULT)) {
            System.out.println("注册失败");
            ct.welcome();
        }
    }

    //统一处理二级菜单的 操作序号
    public void postBookResult(String info) throws IOException {
        if (info.equals("1")) {
            //查询小说列表
            //提示--输入小说名字进行阅读
            //把小说名字发送给服务器
            //服务器:通过IO流读取小说内容---字符流
            List<String> list = bookClientService.queryPrintAllBook(dataUtil);
            list.stream().forEach(s -> System.out.println(s));
            System.out.println("请选择你要阅读的小说:");
            //输入小说名
            String bookName = sc.nextLine();
            //用来记录有页数
            int page = 1;
            while (true) {
                //每一次都向服务器发送要执行的操作和书的页码,让服务器根据页码来读取相应的内容
                MessageEntity messageEntity = new MessageEntity();
                messageEntity.setBookName(bookName);
                messageEntity.setOprator(6);
                messageEntity.setPage(page);
                //向服务器发送书名,和阅读小说的操作
                dataUtil.sendData(messageEntity);
                //接受读取到的内容
                String content = dataUtil.receiveData();
                //打印到控制台
                System.out.println(content);
                System.out.println("第"+page+"页");
                System.out.println("1.上一页  2.下一页");
                System.out.println("其他数字退出");
                String choose = sc.nextLine();
                if (choose.equals("2")){//如果客户端选择下一页,就把页码数加一
                    page++;
                }else if(choose.equals("1")){//如果客户端要阅读上一页,就把页码数减一
                    //先要判断当前页数是不是第一页
                    if(page == 1){
                        System.out.println("当前已经为第一页");
                    }else{
                        page--;
                    }
                }else if (page!=1 &&page!=2){
                    break;
                }
                if(content.equals("end")){
                    break;
                }
            }
            String s = ct.menu();
            postBookResult(s);
        } else if (info.equals("2")) {
            System.out.println("请输入小说路径和名字");
            //D:\feisi_Java\stream\book\\天龙八部.txt
            String bookPathName = sc.nextLine();

            //为了获取文件的大小 ---百分比
            File file = new File(bookPathName);
            //整个文件的字节数
            long length = file.length();

            System.out.println("文件长度=" + length + "个字节");

            //上传----先读到内容---写出去网络
            FileInputStream fis = new FileInputStream(file);

            //服务器那边不知道你的文件名 ---告诉服务器文件名
            String bookName = bookPathName.substring(bookPathName.lastIndexOf("\\\\"));
            int total = 0;//每次读取的字节数---读到文件末尾-1
            double temp = 0.0;//累计读了多少
            boolean flag = true;
            while ((total = fis.read(bs)) != -1) {
                temp += total;
                try {
                    //为了效果----模拟网络延迟
                    //本机不存在网络延迟----没有效果
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                MessageEntity messageEntity = new MessageEntity();
                messageEntity.setOprator(3);
                if (flag) {
                    messageEntity.setBookName(bookName);
                    flag = false;
                }
                messageEntity.setContent(new String(bs, 0, total));
                dataUtil.sendData(messageEntity);
                //如果接受成功 这一次读取的内容上传成功
                String s = dataUtil.receiveData();
                System.out.print("已经完成:" + String.format("%.1f", (temp / length) * 100) + "%\r");
            }

            System.out.println("上传进度=100%");
            System.out.println("上传完成");
            MessageEntity messageEntity = new MessageEntity();
            messageEntity.setOprator(3);
            messageEntity.setContent("end");
            dataUtil.sendData(messageEntity);

            String r = ct.menu();
            postBookResult(r);

        } else if (info.equals("3")) {
            //下载之前先要做查询
            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;
                //遍历查找list中是否存在输入的书名
                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();
                if (downLoadContent.endsWith("end")) {
                    //在上一步的最后,小说末尾有end,表示这里为小说末尾
                    System.out.println("下载完成!!!!!!!!!!!!!!!");
                    FileOutputStream fos = new FileOutputStream(file, true);
                    //这里把所有的end替换成无内容,实际上是删除所有end
                    fos.write(downLoadContent.replaceAll("end", "").getBytes());
                    break;
                }
                //写出接收到的内容到小说文件中
                FileOutputStream fos = new FileOutputStream(file, true);
                fos.write(downLoadContent.getBytes());
            }
            //返回二级菜单
            String s = ct.menu();
            postBookResult(s);
        }
    }
}

CilentTest类:客户端的运动代码

public class ClientTest {
    static Socket socket=null;
    Scanner sc =new Scanner(System.in);
    static UserClientService userClientService;

    public static void main(String[] args) throws IOException, InterruptedException {
        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, InterruptedException {
        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("1、阅读小说");
        System.out.println("2、上传小说");
        System.out.println("3、下载小说");
        System.out.println("4、退出");
        String info = sc.nextLine();
        return info;
    }
}

4.服务端特有类

UserService类:验证客户端输入的登录信息和注册信息

public class UserService {

    public String login(UserEntity entity) throws DocumentException {
        List<UserEntity> userEntities = XMLUtil.parseXml();
        //通过stream流来判断用户名和密码是否合格
        //解析xml得到的数据----2条
        //count=1 表示有一条数据
        //else 表示没有数据或者数据大于一条,登录失败
        long count = userEntities.stream()
                .filter(s -> s.getUsername().equals(entity.getUsername()))
                .filter(s -> s.getPassword().equals(entity.getPassword())).count();
        if (count == 1){
            //登录成功
            return ServerApp.LOGINSUCRESULT;
        }else {
            //登录失败
            return ServerApp.LOGINFAIRESULT;
        }
    }

    public String register(UserEntity userEntity) {
        try {
            XMLUtil.updateXml(userEntity);
            //注册成功
            return ServerApp.REGISTERSUCRESULT;
        } catch (Exception e) {
            e.printStackTrace();
            //注册失败
            return ServerApp.REGISTERFAiRESULT;
        }
    }
}

XMLUtil类:用来处理xml的相关(例如读取和修改xml文件)

public class XMLUtil {
    static List<UserEntity> list = new ArrayList<>();

    public static List<UserEntity> getList(){
        return list;
    }

    static String xmlFilePath = "D:\\feisi_Java\\stream\\Server\\src\\Users.xml";

    static Document document = null;
    /**
     * 获取所有的XML当中的元素
     */
    public static List<UserEntity> parseXml() throws DocumentException {
        Element rootElement = init();
        //遍历根节点下面所有的节点
        Iterator<Element> iterator = rootElement.elementIterator();
        while (iterator.hasNext()){
            //一个子元素---更元素下面的子元素
            Element element = iterator.next();
            //获取元素的属性
            Element username = element.element("username");
            String usernameValue = username.getStringValue();
            Element pwd = element.element("pwd");
            String pwdValue = pwd.getStringValue();

            UserEntity userEntity = new UserEntity();
            userEntity.setUsername(usernameValue);
            userEntity.setPassword(pwdValue);

            list.add(userEntity);
        }
        return list;
    }

    public static Element init() throws DocumentException {
        List<UserEntity> list = new ArrayList<>();
        File file = new File(xmlFilePath);
        //实例化SAXReader对象   读取xml
        SAXReader saxReader = new SAXReader();
        //整个xml的内容----Document
        document = saxReader.read(file);
        //根元素节点
        Element rootElement = document.getRootElement();
        return rootElement;
    }

    //更新
    public static void updateXml(UserEntity userEntity) throws DocumentException, IOException {
        Element rootElement = init();
        //往根元素下面添加一个属性 user
        Element element = rootElement.addElement("user");
        //给先添加的user元素添加一个属性 userId
        element.addAttribute("userId",userEntity.getId() + "");
        element.addElement("username").setText(userEntity.getUsername());
        element.addElement("pwd").setText(userEntity.getPassword());

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        FileWriter fw = new FileWriter(xmlFilePath);
        XMLWriter xw = new XMLWriter(fw,format);
        xw.write(document);
        xw.close();
        fw.close();
    }
    public static boolean isEmpty(String s){
        if (s==null){
            return true;
        }else if (s.equals("")){
            return true;
        }
        return false;
    }
}

 Users.xml文件:存放用户的信息

任务一:客户端和服务器端通信连接

分析

  1. 创建服务器端线程类,并循环监听状态

  2. 创建客户端,请求服务器并发送消息

  3. 服务器端响应客户端

//服务端 
public void init() throws IOException, ClassNotFoundException, DocumentException {
        //监听是否有人来连接
        ServerSocket serverSocket = new ServerSocket();
        //绑定端口号
        serverSocket.bind(new InetSocketAddress(8080));
        System.out.println("服务器已启动,等待客户端连接...");
        //监听
        socket = serverSocket.accept();
        System.out.println("客户端已连接到服务器..."+socket.getInetAddress());
        postClientMessage();
}
//客户端 
public void clientInit() throws IOException {
        //连接服务器
        socket = new Socket();
        socket.connect(new InetSocketAddress(8080));
}

任务二:登录、注册、退出功能

分析

        1. 创建用于保存登录信息的文件

        2. 接收用户登录信息并查找登录信息文件,判断是否登录成功

        3. 接收用户注册信息并保存至登录信息文件

//服务端判定客户端输入内容
if (m.getOprator() == 1) { //登录
      //客户端输入的用户名,密码
      String result = userService.login(m.getUserEntity());
      //把登录结果write给客户端
      os.write(result.getBytes());
}else if (m.getOprator() == 2){
      //客户端输入的用户id,用户名,密码
      String register = userService.register(m.getUserEntity());
      //把注册结果write给客户端
      os.write(register.getBytes());
}

任务三:小说查询列表功能

else if (m.getOprator()==5){ //查询小说列表
            String bookList = "";
            File file = new File(Contain.bookPath);
            String[] list = file.list();
            for (String s : list) {
                bookList += s+"-";
            }
            os.write(bookList.getBytes());
        }

任务四:在线阅读小说功能

分析

  1. 添加用于存放各类小说文件地址的配制项

  2. 根据配制文件和小说列表xml文件将所有小说对象添加到List中

  3. 根据用户选择的小说名,从List中查找小说地址并显示内容

 

if (info.equals("1")) { //阅读小说
            List<String> list = bookClientService.queryPrintAllBook(dataUtil);
            list.stream().forEach(s -> System.out.println(s));
            System.out.println("请选择你要阅读的小说:");
            //输入小说名
            String bookName = sc.nextLine();
            //用来记录有页数
            int page = 1;
            while (true) {
                //每一次都向服务器发送要执行的操作和书的页码,让服务器根据页码来读取相应的内容
                MessageEntity messageEntity = new MessageEntity();
                messageEntity.setBookName(bookName);
                messageEntity.setOprator(6);
                messageEntity.setPage(page);
                //向服务器发送书名,和阅读小说的操作
                dataUtil.sendData(messageEntity);
                //接受读取到的内容
                String content = dataUtil.receiveData();
                //打印到控制台
                System.out.println(content);
                System.out.println("第"+page+"页");
                System.out.println("1.上一页  2.下一页");
                System.out.println("其他数字退出");
                String choose = sc.nextLine();
                if (choose.equals("2")){//如果客户端选择下一页,就把页码数加一
                    page++;
                }else if(choose.equals("1")){//如果客户端要阅读上一页,就把页码数减一
                    //先要判断当前页数是不是第一页
                    if(page == 1){
                        System.out.println("当前已经为第一页");
                    }else{
                        page--;
                    }
                }else if (page!=1 &&page!=2){
                    break;
                }
                if(content.equals("end")){
                    break;
                }
            }
            String s = ct.menu();
            postBookResult(s);
        }

任务五:上传小说功能

分析

  1. 根据用户输入的小说路径,读取源文件

  2. 根据配制文件的各类小说路径,将读取的源文件写入相应位置

  3. 根据用户输入的小说信息:小说名,保存至小说列表xml文件

 

else if (info.equals("2")) {
            System.out.println("请输入小说路径和名字");
            //D:\feisi_Java\stream\book\\天龙八部.txt
            String bookPathName = sc.nextLine();
            //为了获取文件的大小 ---百分比
            File file = new File(bookPathName);
            //整个文件的字节数
            long length = file.length();
            System.out.println("文件长度=" + length + "个字节");
            //上传----先读到内容---写出去网络
            FileInputStream fis = new FileInputStream(file);
            //服务器那边不知道你的文件名 ---告诉服务器文件名
            String bookName = bookPathName.substring(bookPathName.lastIndexOf("\\\\"));
            int total = 0;//每次读取的字节数---读到文件末尾-1
            double temp = 0.0;//累计读了多少
            boolean flag = true;
            while ((total = fis.read(bs)) != -1) {
                temp += total;
                try {
                    //为了效果----模拟网络延迟
                    //本机不存在网络延迟----没有效果
                    TimeUnit.MILLISECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                MessageEntity messageEntity = new MessageEntity();
                messageEntity.setOprator(3);
                if (flag) {
                    messageEntity.setBookName(bookName);
                    flag = false;
                }
                messageEntity.setContent(new String(bs, 0, total));
                dataUtil.sendData(messageEntity);
                //如果接受成功 这一次读取的内容上传成功
                String s = dataUtil.receiveData();
                System.out.print("已经完成:" + String.format("%.1f", (temp / length) * 100) + "%\r");
            }

            System.out.println("上传进度=100%");
            System.out.println("上传完成");
            MessageEntity messageEntity = new MessageEntity();
            messageEntity.setOprator(3);
            messageEntity.setContent("end");
            dataUtil.sendData(messageEntity);

            String r = ct.menu();
            postBookResult(r);

        } 

任务六:下载小说功能

分析

  1. 在配制文件添加下载路径的配制项

  2. 根据用户选择的小说读取小说源文件

  3. 把读取的文件写到对应下载路径中

else if (info.equals("3")) {
            //下载之前先要做查询
            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;
                //遍历查找list中是否存在输入的书名
                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();
                if (downLoadContent.endsWith("end")) {
                    //在上一步的最后,小说末尾有end,表示这里为小说末尾
                    System.out.println("下载完成!!!!!!!!!!!!!!!");
                    FileOutputStream fos = new FileOutputStream(file, true);
                    //这里把所有的end替换成无内容,实际上是删除所有end
                    fos.write(downLoadContent.replaceAll("end", "").getBytes());
                    break;
                }
                //写出接收到的内容到小说文件中
                FileOutputStream fos = new FileOutputStream(file, true);
                fos.write(downLoadContent.getBytes());
            }
            //返回二级菜单
            String s = ct.menu();
            postBookResult(s);
        }

 5.错误提示

提示:所有的功能中,向服务端传送的数据的oprator数字,必须和对应功能一样,否则可能会出现Exception in thread “main” java.net.SocketException: Connection reset(线程“main”java.net.SocketException异常:连接重置)的错误。一般出现这个错误说明你客户端或者服务端有一端的读写出错了,或者有一端连接断开,可以使用debug一步步查看。

6.效果展示


总结

        经过这一次的在线小说阅读系统,我对很多知识有了更全面的了解,不再只停留在之前固定的几种方式中。例如I/O流,在项目之前,做的最复杂的也就是文件的复制,而且有具体的模版,所以我对I/O流没有很熟悉,但是这次项目,结合Socket编程一起,不再只是简单的拿名字或者复制,而是实现了客户端和服务端内容的交互,服务端的内容可以写出到客户端中,客户端的内容也可以写入到服务端中进行判断。

        对于Socket编程,更加体验到了它的难点,尤其是关于客户端和服务端两边的信息交互,它们之间是如何输入输出的,又用什么连接起来,这也是我需要继续去努力学习的地方,在编程中遇到的错误也大部分出自于有关Socket的地方,都努力去解决了。

        总的来说,这个项目让我对这一阶段的知识有了更全面、深刻的认识,更加意识到自己在哪些方面有不足,需要继续努力的。

Java项目开发全程实录》这一本书从开发背景、需求分析、系统功能分析、数据库分析、数据库建模、网站开发和网站发布或者程序打包与运行,每一过程都进行了详细的介绍。 目 录 第1章 进销存管理系统(Swing+SQL Server 2000实现) 1 教学视频:1小时42分 1.1 开发背景 2 1.2 系统分析 2 1.2.1 需求分析 2 1.2.2 可行性分析 2 1.2.3 编写项目计划书 4 1.3 系统设计 6 1.3.1 系统目标 6 1.3.2 系统功能结构 6 1.3.3 业务逻辑编码规则 7 1.3.4 系统流程图 8 1.3.5 构建开发环境 8 1.3.6 系统预览 9 1.3.7 文件夹组织结构 10 1.4 数据库设计 10 1.4.1 数据库分析 10 1.4.2 进销存管理系统的E-R图 11 1.4.3 使用PowerDesigner建模 12 1.4.4 创建数据库 15 1.5 主窗体设计 16 1.5.1 创建主窗体 17 1.5.2 创建导航面板 18 1.6 公共模块设计 21 1.6.1 编写Dao公共类 22 1.6.2 编写Item类 25 1.7 基础信息模块设计 26 1.7.1 基础信息模块概述 26 1.7.2 基础信息模块技术分析 27 1.7.3 供应商添加实现过程 27 1.7.4 供应商修改与删除实现过程 30 1.7.5 单元测试 32 1.8 进货管理模块设计 36 1.8.1 进货管理模块概述 36 1.8.2 进货管理模块技术分析 38 1.8.3 进货单实现过程 38 1.9 查询统计模块设计 42 1.9.1 查询统计模块概述 42 1.9.2 查询统计模块技术分析 43 1.9.3 销售查询实现过程 43 1.10 库存管理模块设计 45 1.10.1 库存管理模块概述 45 1.10.2 库存管理模块技术分析 46 1.10.3 价格调整实现过程 46 1.10.4 单元测试 48 1.11 系统打包发布 49 1.12 开发技巧与难点分析 51 1.13 使用PowerDesigner逆向生成数据库 E-R图 52 1.14 本章总结 54 第2章 企业内部通信系统(Swing+JavaDB 实现) 55 教学视频:1小时40分 2.1 开发背景 56 2.2 系统分析 56 2.2.1 需求分析 56 2.2.2 可行性分析 56 2.2.3 编写项目计划书 58 2.3 系统设计 60 2.3.1 系统目标 60 2.3.2 系统功能结构 60 2.3.3 数据库设计 60 2.3.4 系统预览 62 2.3.5 文件夹组织结构 63 2.4 主窗体设计 64 2.4.1 创建主窗体 64 2.4.2 记录窗体位置 68 2.5 公共模块设计 69 2.5.1 数据库操作类 69 2.5.2 系统工具类 74 2.6 系统托盘模块设计 79 2.6.1 系统托盘模块概述 79 2.6.2 系统托盘模块技术分析 79 2.6.3 系统托盘模块实现过程 80 2.7 系统工具模块设计 82 2.7.1 系统工具模块概述 82 2.7.2 系统工具模块技术分析 82 2.7.3 系统工具模块实现过程 83 2.8 用户管理模块设计 87 2.8.1 用户管理模块概述 87 2.8.2 用户管理模块技术分析 87 2.8.3 用户管理模块实现过程 88 2.8.4 单元测试 93 2.9 通信模块设计 94 2.9.1 通信模块概述 94 2.9.2 通信模块技术分析 95 2.9.3 通信模块实现过程 95 2.10 开发技巧与难点分析 99 2.11 使用JDK 6新增的系统托盘 99 2.12 本章总结 100 第3章 企业人事管理系统 (Swing+Hibernate+Oracle实现) 101 教学视频:2小时53分 3.1 开发背景 102 3.2 系统分析 102 3.3 系统设计 102 3.3.1 系统目标 102 3.3.2 系统功能结构 102 3.3.3 系统预览 104 3.3.4 业务流程图 105 3.3.5 文件夹结构设计 106 3.4 数据库设计 107 3.4.1 数据库分析 107 3.4.2 数据库概念设计 107 3.4.3 数据库逻辑结构设计 109 3.5 主窗体设计 110 3.5.1 导航栏的设计 110 3.5.2 工具栏的设计 112 3.6 公共模块设计 114 3.6.1 编写Hibernate配置文件 114 3.6.2 编写Hibernate持久化类和映射文件 115 3.6.3 编写通过Hibernate操作持久化对象的 常用方法 116 3.6.4 创建用于特殊效果的部门树对话框 117 3.6.5 创建通过部门树选取员工的面板和 对话框 119 3.7 人事管理模块设计 120 3.7.1 人事管理模块功能概述 120 3.7.2 人事管理模块技术分析 122 3.7.3 人事管理模块实现过程 122 3.7.4 单元测试 127 3.8 待遇管理模块设计 128 3.8.1 待遇管理模块功能概述 128 3.8.2 待遇管理模块技术分析 129 3.8.3 待遇管理模块实现过程 129 3.9 系统维护模块设计 133 3.9.1 系统维护模块功能概述 134 3.9.2 系统维护模块技术分析 136 3.9.3 系统维护模块实现过程 136 3.9.4 单元测试 140 3.10 开发技巧与难点分析 140 3.11 Hibernate关联关系的建立方法 141 3.11.1 建立一对一关联 141 3.11.2 建立一对多关联 142 3.12 本章总结 144 第4章 酒店管理系统(Swing+SQL Server 2005实现) 145 教学视频:2小时39分 4.1 概述 146 4.2 系统分析 146 4.3 系统设计 146 4.3.1 系统目标 146 4.3.2 系统功能结构 147 4.3.3 系统预览 147 4.3.4 业务流程图 149 4.3.5 文件夹结构设计 149 4.4 数据库设计 150 4.4.1 数据库分析 150 4.4.2 数据库概念设计 150 4.4.3 数据库逻辑结构设计 151 4.4.4 视图设计 151 4.5 公共模块设计 152 4.5.1 编写数据库连接类 152 4.5.2 封装常用的操作数据库的方法 153 4.5.3 自定义表格组件 154 4.5.4 编写利用正则表达式验证数据 合法性的方法 156 4.6 主窗体设计 156 4.7 用户登录窗口设计 158 4.8 开台签单工作区设计 164 4.8.1 开台签单工作区功能概述 164 4.8.2 开台签单工作区技术分析 165 4.8.3 开台签单工作区实现过程 165 4.8.4 单元测试 170 4.9 自动结账工作区设计 171 4.9.1 自动结账工作区功能概述 171 4.9.2 自动结账工作区技术分析 172 4.9.3 自动结账工作区实现过程 172 4.10 结账报表工作区设计 173 4.10.1 结账报表工作区功能概述 173 4.10.2 结账报表工作区技术分析 175 4.10.3 结账报表工作区实现过程 175 4.10.4 单元测试 179 4.11 后台管理工作区设计 180 4.11.1 后台管理工作区功能概述 180 4.11.2 后台管理工作区技术分析 181 4.11.3 后台管理工作区实现过程 181 4.11.4 单元测试 188 4.12 开发技巧与难点分析 188 4.13 使用Visio逆向生成数据库E-R图 190 4.14 本章总结 192 第5章 图书馆管理系统(Swing+SQL Server 2000实现) 193 教学视频:2小时14分 5.1 开发背景 194 5.2 需求分析 194 5.3 系统设计 194 5.3.1 系统目标 194 5.3.2 系统功能结构 194 5.3.3 系统流程图 195 5.3.4 系统预览 196 5.3.5 构建开发环境 196 5.3.6 文件夹组织结构 197 5.4 数据库设计 197 5.4.1 数据库分析 197 5.4.2 数据库概念设计 197 5.4.3 使用PowerDesigner建模 200 5.5 公共模块设计 201 5.5.1 数据库连接及操作类的编写 201 5.5.2 MenuActions类的编写 203 5.5.3 限制文本框长度类的编写 205 5.5.4 描述组合框索引与内容类的编写 206 5.5.5 在JLable上添加图片类的编写 208 5.6 主窗体设计 208 5.6.1 主窗体概述 208 5.6.2 主窗体技术分析 209 5.6.3 主窗体的实现过程 211 5.7 登录模块设计 214 5.7.1 登录模块概述 214 5.7.2 登录模块技术分析 215 5.7.3 登录模块实现过程 216 5.8 图书信息管理模块设计 219 5.8.1 图书信息管理模块概述 219 5.8.2 图书信息管理模块技术分析 221 5.8.3 图书信息管理模块实现过程 221 5.8.4 单元测试 229 5.9 图书借阅、归还模块设计 230 5.9.1 图书借阅、归还模块概述 230 5.9.2 图书借阅、归还模块技术分析 231 5.9.3 图书借阅、归还模块实现过程 232 5.9.4 单元测试 238 5.10 图书查询模块设计 239 5.10.1 图书查询模块概述 239 5.10.2 图书查询模块技术分析 239 5.10.3 图书查询模块实现过程 240 5.11 开发技巧与难点分析 242 5.11.1 级联删除 242 5.11.2 窗体中单选按钮即时显示 243 5.12 格式化的文本框 243 5.12.1 使用JFormattedTextField限制整型 数字输入 244 5.12.2 使用JFormattedTextField限制日期 输入 244 5.13 本章总结 245 第6章 企业快信(Swing+JavaDB实现) 246 教学视频:1小时35分 6.1 企业快信概述 247 6.2 系统分析 247 6.2.1 需求分析 247 6.2.2 可行性研究 247 6.3 系统设计 248 6.3.1 系统目标 248 6.3.2 系统功能结构 248 6.3.3 业务流程图 248 6.3.4 系统预览 249 6.3.5 构建开发环境 251 6.3.6 文件夹组织结构 252 6.4 数据库设计 253 6.4.1 数据库分析 253 6.4.2 数据库概念设计 253 6.4.3 数据库逻辑结构设计 254 6.4.4 视图设计 255 6.5 主窗体设计 255 6.6 公共模块设计 258 6.6.1 编写数据库连接类 258 6.6.2 封装常用的操作数据库的方法 260 6.7 资源管理模块设计 261 6.7.1 名片夹管理功能概述 261 6.7.2 名片夹管理功能技术分析 262 6.7.3 名片夹管理功能实现过程 262 6.8 发送短信模块设计 270 6.8.1 发送短信模块功能概述 270 6.8.2 发送短信模块技术分析 271 6.8.3 发送短信模块实现过程 272 6.9 发送邮件模块设计 276 6.9.1 发送邮件模块功能概述 276 6.9.2 发送邮件模块技术分析 277 6.9.3 发送邮件模块实现过程 277 6.10 系统设置模块设计 282 6.10.1 系统设置模块功能概述 282 6.10.2 系统设置模块技术分析 283 6.10.3 短信设置实现过程 283 6.10.4 邮箱设置实现过程 285 6.11 开发技巧与难点分析 287 6.12 使用短信猫和Java Mail组件 288 6.12.1 使用短信猫 288 6.12.2 使用Java Mail组件 290 6.13 本章总结 295 第7章 欣想电子商城(Spring+Hibernate +SQL Server实现) 296 教学视频:1小时53分 7.1 开发背景 297 7.2 系统分析 297 7.2.1 需求分析 297 7.2.2 可行性分析 297 7.3 系统设计 298 7.3.1 系统目标 298 7.3.2 系统功能结构 298 7.3.3 购物流程图 299 7.3.4 系统预览 300 7.3.5 构建开发环境 301 7.3.6 文件夹组织结构 304 7.4 数据库设计 304 7.4.1 数据库分析 305 7.4.2 数据库概念设计 305 7.4.3 PowerDesigner数据库建模 306 7.4.4 数据库创建 307 7.5 网站首页设计 308 7.5.1 首页布局 308 7.5.2 创建首页控制器 311 7.5.3 配置控制器 312 7.6 公共模块设计 314 7.6.1 编写Dao公共类 314 7.6.2 配置数据库连接和事务管理器 316 7.6.3 配置Spring控制器的请求映射 317 7.7 会员管理模块设计 319 7.7.1 会员管理模块概述 319 7.7.2 会员管理模块技术分析 320 7.7.3 会员注册的实现过程 321 7.7.4 会员登录的实现过程 324 7.8 购物模块设计 327 7.8.1 购物模块概述 327 7.8.2 购物模块技术分析 328 7.8.3 购物车的实现过程 328 7.8.4 收银台的实现过程 332 7.8.5 单元测试 335 7.9 商品管理模块设计 336 7.9.1 商品管理模块概述 336 7.9.2 商品管理模块技术分析 337 7.9.3 商品列表的实现过程 338 7.9.4 商品添加的实现过程 340 7.9.5 单元测试 343 7.10 发布与运行 344 7.11 开发技巧与难点分析 346 7.11.1 为Spring的数据源配置正确的URL 346 7.11.2 为Tiles指定错误页面 347 7.12 使用MyEclipse生成Hibernate 实体类和映射文件 347 7.13 本章总结 351 第8章 企业门户网站(JSP+JavaBean +SQL Server 2000实现) 352 教学视频:1小时9分 8.1 开发背景 353 8.2 需求分析 353 8.3 系统设计 353 8.3.1 系统目标 353 8.3.2 系统功能结构 354 8.3.3 业务流程图 355 8.3.4 系统预览 355 8.3.5 构建开发环境 356 8.3.6 文件夹组织结构 358 8.4 数据库设计 359 8.4.1 数据库需求分析 359 8.4.2 数据库概念设计 359 8.4.3 数据库逻辑结构设计 360 8.5 公共模块设计 361 8.5.1 定义connsqlserver类 361 8.5.2 创建Web应用过滤器 363 8.5.3 构建转码类 365 8.6 网站首页设计 365 8.6.1 首页概述 365 8.6.2 首页技术分析 365 8.6.3 首页的实现过程 367 8.7 商品介绍模块设计 369 8.7.1 商品介绍模块概述 369 8.7.2 商品介绍模块技术分析 369 8.7.3 商品介绍模块实现过程 370 8.8 后台登录模块设计 371 8.8.1 后台登录模块概述 371 8.8.2 后台登录模块技术分析 372 8.8.3 后台登录模块实现过程 373 8.8.4 单元测试 375 8.9 商品管理模块设计 376 8.9.1 商品管理模块概述 376 8.9.2 商品管理模块技术分析 377 8.9.3 商品管理模块实现过程 378 8.9.4 单元测试 388 8.10 新闻管理模块设计 389 8.10.1 新闻管理模块概述 389 8.10.2 新闻管理模块技术分析 389 8.10.3 新闻管理模块实现过程 391 8.11 开发技巧与难点分析 397 8.11.1 页面弹出窗口控制 397 8.11.2 FileUpload组件获取表单中的值 399 8.11.3 配置全局Tomcat连接池 399 8.12 Proxool连接池 400 8.12.1 Proxool安装 400 8.12.2 Proxool使用 400 8.13 本章总结 402 第9章 BBS系统(Struts+MySQL实现) 403 教学视频:1小时46分 9.1 开发背景 404 9.2 需求分析 404 9.3 系统设计 404 9.3.1 系统目标 404 9.3.2 系统功能结构 405 9.3.3 业务流程图 405 9.3.4 系统预览 406 9.3.5 构建开发环境 407 9.3.6 文件夹组织结构 408 9.4 数据库设计 409 9.4.1 数据库分析 409 9.4.2 数据库概念设计 409 9.4.3 PowerDesigner数据库建模 410 9.4.4 创建数据库 411 9.5 论坛首页设计 412 9.5.1 创建首页视图组件 412 9.5.2 创建首页配置文件 416 9.5.3 创建首页控制器 416 9.5.4 创建首页业务逻辑类 417 9.6 公共模块设计 419 9.6.1 数据库连接 419 9.6.2 配置消息资源文件 422 9.6.3 创建转码类 423 9.7 用户登录模块设计 424 9.7.1 用户登录概述 424 9.7.2 用户登录技术分析 424 9.7.3 用户登录实现过程 425 9.7.4 单元测试 429 9.8 用户注册模块设计 430 9.8.1 用户注册概述 430 9.8.2 用户注册技术分析 430 9.8.3 用户注册实现过程 430 9.9 用户发布主题模块设计 436 9.9.1 发布主题概述 436 9.9.2 发布主题技术分析 437 9.9.3 发布主题实现过程 437 9.9.4 单元测试 443 9.10 后台栏目管理模块设计 445 9.10.1 栏目管理概述 445 9.10.2 栏目管理技术分析 446 9.10.3 栏目管理实现过程 446 9.11 开发技巧与难点分析 449 9.12 Struts框架与日志 450 9.13 本章总结 452 第10章 手机网络游戏(J2ME+Servlet 实现) 453 教学视频:1小时15分 10.1 开发背景 454 10.2 系统分析 454 10.2.1 需求分析 454 10.2.2 可行性分析 454 10.3 系统设计 454 10.3.1 系统目标 454 10.3.2 系统功能结构 455 10.3.3 构建开发环境(根据语言的实际 情况写) 455 10.3.4 系统预览 456 10.3.5 文件夹组织结构 457 10.4 主程序设计 458 10.5 公共模块设计 462 10.5.1 创建Player公共类 462 10.5.2 创建Queue公共类 463 10.5.3 创建Umpire公共类 465 10.5.4 创建Desk公共类 466 10.6 游戏模块设计 469 10.6.1 游戏模块概述 469 10.6.2 游戏模块技术分析 470 10.6.3 棋盘绘制模块实现过程 470 10.6.4 按键处理模块实现过程 478 10.6.5 游戏信息处理模块实现过程 481 10.6.6 客户端信息处理模块概述 483 10.7 服务器模块设计 484 10.7.1 服务器模块概述 484 10.7.2 服务器模块技术分析 485 10.7.3 服务器模块实现过程 485 10.7.4 单元测试 490 10.8 发布与运行 491 10.8.1 服务器端的发布与运行 491 10.8.2 客户端的运行 493 10.9 开发技巧与难点分析 493 10.10 使用EclipseMe工具编写 手机程序 494 10.10.1 EclipseMe的安装 494 10.10.2 配置EclipseMe插件 495 10.10.3 创建J2ME项目 496 10.11 本章总结 497
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值