文章目录

  • 前言
  • 1. 小型图书管理系统框架思想
  • 2. 实现框架
    • 2.1 构建书架:存放书籍
    • 2.2 使用者的构建 - user
    • 2.3 主函数构建 - Main
    • 2.4 操作的构建 - operate
    • 2.5 对象与操作建立联系
  • 3. 细化各种操作内容
    • 3.1 增加图书:AddOperation
    • 3.2 借阅图书:BorrowOperation
    • 3.3 删除图书:DelOperation
    • 3.4 查找图书:FindOperation
    • 3.5 归还图书操作:ReturnOperation
    • 3.6 显示存在的图书:ShowOperation
    • 3.7 退出系统:ExitOperation
  • 4. 总体代码
  • 总结

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!

编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。


前言

本篇通过练习小型的图书管理系统,对java基础语法的进一步应用,提高对封装、继承、抽象、接口语法的熟练度。如有错误,请在评论区指正,让我们一起交流,共同进步!


本文开始

1. 小型图书管理系统框架思想

图书管理系统:顾名思义管理书的系统,他的功能有哪些?他的使用人群是哪些?
基本功能:
① 存储书的信息:
每本书book的基础信息:书名,价格,作者等
书架(存放各种书信息的地方):BookList,可以操作书的各种信息
② 面向的使用者:user
AdminUser:管理者(管理图书)对图书的增删改等信息的操作
NormalUser:正常使用者(借阅人)对图书查找,借阅等操作
③操作:对于使用者的各种操作,单独存放,使用接口调用操作对象
④主函数Main:让使用者根据User对象,做出具体什么操作

2. 实现框架

2.1 构建书架:存放书籍

定义一个包package: book =》关于书籍的操作
Book: 存放书的各种信息(一本) - 是一个类
BookList: 多本书,使用数组存储Book[ ]

Book 代码实现:
对于书的属性实现了封装:所以需要提供get,set方法,以便于操作书里面的属性

package book;public class Book {private String name;//书名private String author;private int price;private String  type;private boolean isBorrowed;//是否被借出//isBorrowed不需要初始化,开始的时候,书都是未被借出的默认赋值为false//当书真正被借出时,我们之间修改isBorrowed属性即可public Book(String name, String author, int price, String type) {this.name = name;this.author = author;this.price = price;this.type = type;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getType() {return type;}public void setType(String type) {this.type = type;}public boolean isBorrowed() {return isBorrowed;}public void setBorrowed(boolean borrowed) {isBorrowed = borrowed;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", type='" + type + '\'' +//", isBorrowed=" + isBorrowed +(isBorrowed ? "  已被借出 " : "  未被借出 ")+  //利用三木表达式判断是否借出'}';}
}

BookList 代码实现:
定义常量DEFAULT_SIZE 可以及时更改存放书的数量
书架里面封装了数组:Book[ ]可以存放多本书
usedSize: 记录书架上书的多少
【注】
这里也是封装了元素,但是出现的构造方法getBooks,setBooks不符合我们的期望,返回的是数组Book[ ], 这里只是构建框架,下面具体操作会详细说明情况!

package book;public class BookList {private static final int DEFAULT_SIZE = 5;private Book[] books = new Book[DEFAULT_SIZE];private int usedSize;//借书是一本本借,所以需要操作的一本书,而不是书的数组
//    public Book[] getBooks() {
//        return books;
//    }
//
//    public void setBooks(Book[] books) {
//        this.books = books;
//    }public int getUsedSize() {return usedSize;}public void setUsedSize(int usedSize) {this.usedSize = usedSize;}
}

2.2 使用者的构建 - user

这里我们提出两种使用者:管理者和正常使用者
我们通过思考代码实践,会发现他们会有共同的属性或方法,这时可以抽象出一个类User存放他们共有的元素;
而对应管理者和正常使用者,他们的基本操作大致是一样的,只有具体的操作略有不同;

User为什么是抽象类?
主函数首先需要调用login需要显示菜单,但是父类对象没有办法使用子类里面的方法,所以menu()写成抽象方法,进而User类改成抽象类;父类再调用时发生运行时绑定,会调用子类menu()方法

User代码的实现:

package user;import book.BookList;public abstract class User {public String name;public User(String name) {this.name = name;}//主函数调用login需要显示菜单,但是父类对象没有办法使用子类里面的方法,// 所以menu()写成抽象方法,进而User类改成抽象类// 父类再调用时发生运行时绑定,会调用子类menu()方法public abstract int menu();
}

管理者代码实现:
知道管理者姓名,就显示可操作的菜单,根据菜单进行具体的增删改等操作

package user;
import operate.*;
import java.util.Scanner;public class AdminUser extends User{//知道对象的时候,构造方法会初始化namepublic AdminUser(String name) {super(name);}@Overridepublic int menu() {System.out.println("=======================");System.out.println("hello  " + name + "  欢迎使用图书系统!");System.out.println("1.查找图书!");System.out.println("2.新增图书!");System.out.println("3.删除图书!");System.out.println("4.显示图书!");System.out.println("0.退出系统!");System.out.println("========================");System.out.println("请输入你的操作:");Scanner sc = new Scanner(System.in);int choice = sc.nextInt();return choice;}
}

正常使用者代码实现

import operate.*;
import java.util.Scanner;
public class NormalUser extends User{public NormalUser(String name) {super(name);}@Overridepublic int menu() {System.out.println("=======================");System.out.println("hello  " + name + "  欢迎使用图书系统!");System.out.println("1.查找图书!");System.out.println("2.借阅图书!");System.out.println("3.归还图书!");System.out.println("0.退出系统!");System.out.println("========================");System.out.println("请输入你的操作:");Scanner sc = new Scanner(System.in);int choice = sc.nextInt();return choice;}
}

2.3 主函数构建 - Main

主函数中,使用者首先需要见到登录页面,确定登录身份输入0 或 1 确定管理者还是正常使用者,再返回对应的对象菜单;

login(): 登录操作,调用login返回对象有两种结果,所以使用(返回值类)向上转型,通过父类可以介绍多种子类对象;

import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {public static User login() {//发生向上转型:返回值System.out.println("请输入姓名:>");Scanner sc = new Scanner(System.in);String name = sc.nextLine();System.out.println("请输入你的身份:1:管理者,0:借阅者 ");int choice = sc.nextInt();if(choice == 1) {return new AdminUser(name);} else {return new NormalUser(name);}}public static void main(String[] args) {BookList bookList = new BookList();//调用login返回的对象不确定需要父类对象来接受User user = login();//通过登录确认使用对象//显示登录对象的菜单,从而进行操作while (true) {//利用循环进行多次操作user.menu();//根据对象调用菜单}}
}

2.4 操作的构建 - operate

对于各种操作,都有不同的操作,我们可以定义一个接口,让所有操作implements接口,这样连接这个接口的对象都可以被同一个接口调用;

接口代码实现

package operate;
import book.BookList;
public interface IOPeration {void work(BookList bookList);
}

使用者的各种操作连接这个接口即可;

管理者基本操作:
查找图书:FindOperation
增加图书:AddOperation
删除图书:DelOperation
显示图书:ShowOperation
退出系统:ExitOperation

正常使用者基本操作:
查找图书:FindOperation
借阅图书:BorrowOperation
归还图书:DelOperation
退出系统:ExitOperation

2.5 对象与操作建立联系

使用者与操作建立联系:IOPeration [ ]
刚才建立了接口,可以通过接口数组存放使用者的操作对象 IOPeraton[ ]
由于都需要操作,所以接口数组,也需要定义在User中;

主函数与操作建立联系:doWork()
主函数中login()会返回对象,再根据菜单menu()返回具体选择choice,把选择与书架对象以参数形式传给doWork();

doWork()具体工作: 根据操作数组找到对象,在操作具体的工作; this.ioPerations[choice].work(bookList);
this.ioPeration[choice] => 根据选择找到操作的对象;work(bookList) => 操作对象的具体工作

更新User代码:

package user;
import book.BookList;
import operate.IOPeration;
public abstract class User {public String name;public IOPeration[] ioPerations;//操作数组存储操作对象public User(String name) {this.name = name;}public abstract int menu();public void doWork(int choice, BookList bookList) {this.ioPerations[choice].work(bookList);//this.ioPeration[choice] => 根据选择找到操作的对象//work(bookList) => 操作对象的具体工作}
}

main代码更新:

 public static void main(String[] args) {BookList bookList = new BookList();User user = login();//通过登录确认使用对象//显示登录对象的菜单,从而进行操作while (true) {//利用循环进行多次操作int choice =  user.menu();//根据对象调用菜单,返回操作的选择user.doWork(choice,bookList);}}

3. 细化各种操作内容

3.1 增加图书:AddOperation

输入图书的各种信息,再通过new对象,把书的参数给book, 再通过引用把书存放到usedSize位置,最后记录书的数量+1;
【注】通过循环查询增加的图书是否存在, 这里我们认为一本书只能存一本

增加书的代码实现:

package operate;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class AddOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("新增图书! ");Scanner sc = new Scanner(System.in);System.out.println(" 输入书名: ");String name = sc.nextLine();System.out.println(" 输入作者:");String author = sc.nextLine();System.out.println(" 输入类型:");String type = sc.nextLine();System.out.println(" 输入价格:");int price = sc.nextInt();Book book = new Book(name,author,price,type);int currentSize = bookList.getUsedSize();//判断书架上是否有此书,有就不能存入了for (int i = 0; i < currentSize; i++) {Book t = bookList.getBook(i);if(t.getName().equals(name)) {System.out.println("此书已存在,不能再放入!");break;}}//直接在最后位置存书bookList.setBooks(book);bookList.setUsedSize(currentSize+1);System.out.println("存入成功!");}
}

3.2 借阅图书:BorrowOperation

通过循环遍历,查看书是否有,状态是否是未被借出的状态;
书是对象,需要引用来获得(bookList.getBook());
因为是引用对象,比较其中的内容需要使用equals()方法;
【注】书被借出去了,记得改变书的状态

借阅图书代码实现:

package operate;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class BorrowOperation implements IOPeration {@Overridepublic void work(BookList bookList) {System.out.println("借阅图书!");System.out.println("请输入要借阅的图书:");Scanner sc = new Scanner(System.in);String name = sc.nextLine();int currentSize = bookList.getUsedSize();for (int i = 0; i < currentSize; i++) {Book book = bookList.getBook(i);if(book.getName().equals(name) && !book.isBorrowed()) {book.setBorrowed(true);System.out.println("借阅成功!");}}}
}

3.3 删除图书:DelOperation

循环找到删除图书的下标,根据下标从后往前覆盖要删除的对象,使用getBook()获取删除下标的下一个位置,使用setBook()把书覆盖到前一个位置;因为是对象最后需要把最后一个位置置null;
【注】统计书架大小的需要-1;为了防止下标越界需要循环结束条件为当前书的数量-1;

删除书代码实现:

package operate;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class DelOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("删除图书!");System.out.println("请输入要删除图书的名字:");Scanner sc = new Scanner(System.in);String name = sc.nextLine();int currentSize = bookList.getUsedSize();int index = -1;//循环找到删除图书的下标位置for (int i = 0; i < currentSize; i++) {Book t = bookList.getBook(i);if(t.getName().equals(name)) {index = i;  //记录删除图书的位置break;}}//删除图书:都是封装的对象,需要引用变量for (int j = index; j < currentSize-1; j++) {Book book = bookList.getBook(j+1);//找到j+1下标的图书bookList.setBooks(j,book);//把书放到j下标位置}//修改usedSizebookList.setUsedSize(currentSize-1);//删除的是对象,最后一个位置需要置nullbookList.setBooks(currentSize-1,null);System.out.println("删除成功!");}
}

3.4 查找图书:FindOperation

根据输入的书名,与存在的书相比较,如果有相同的即输出这本书的信息;

package operate;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class FindOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("查找图书!");System.out.println("请输入书名:");Scanner sc = new Scanner(System.in);String name = sc.nextLine();int currentSize = bookList.getUsedSize();for (int i = 0; i < currentSize; i++) {Book book = bookList.getBook(i);if(book.getName().equals(name)) {System.out.println("存在这本书:");System.out.println(book);return;}}System.out.println("不存在这本书!");}
}

3.5 归还图书操作:ReturnOperation

输入归还图书的书名,比较书架上的书名与借的书名是否有相同的,并且书还是被借出去的(isBorrowed状态为ture)
【注】存在书名,归还后需要修改书的状态为false

归还书的代码操作实现:

package operate;
import book.Book;
import book.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("返回图书!");System.out.println("输入要归还图书的书名:");Scanner sc = new Scanner(System.in);String name = sc.nextLine();int currentSize = bookList.getUsedSize();//当前有多少图书for (int i = 0; i < currentSize; i++) {Book book = bookList.getBook(i);//比较书架上的书名与借的书名是否有相同的,并且书还是被借出去的(isBorrowed状态为ture)if(book.getName().equals(name) && book.isBorrowed()) {book.setBorrowed(false);System.out.println("归还成功");return;}}}
}

3.6 显示存在的图书:ShowOperation

通过循环输出显示结果,不能直接使用bookList[i]打印,这是引用对象,需要打印book对象,调用会调用重写的toString()方法,显示图书信息;

显示图书代码操作:

package operate;
import book.Book;
import book.BookList;
public class ShowOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("显示所有图书! ");int currentSize = bookList.getUsedSize();//封装的属性,只能通过对象的引用来调用for (int i = 0; i < currentSize; i++) {//System.out.println(bookList[i]);Book book = bookList.getBook(i);System.out.println(book);//通过调用重写的toString()显示书的内容}}
}

3.7 退出系统:ExitOperation

系统退出操作,输入0为一般退出操作

退出系统代码实现:

package operate;
import book.BookList;
public class ExitOperation implements IOPeration{@Overridepublic void work(BookList bookList) {System.out.println("退出系统!");//输入0即为退出系统,系统退出的操作System.exit(0);}
}

4. 总体代码

操作代码的详细内容为上述代码细化的内容;

//关于书信息的包下内容
package book;
public class Book {private String name;//书名private String author;private int price;private String  type;private boolean isBorrowed;//是否被借出//书的元素被封装:所以需要提供构造方法,以便于操作书里面的属性//isBorrowed不需要初始化,开始的时候,书都是未被借出的默认赋值为false//当书真正被借出时,我们之间修改isBorrowed属性即可public Book(String name, String author, int price, String type) {this.name = name;this.author = author;this.price = price;this.type = type;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getType() {return type;}public void setType(String type) {this.type = type;}public boolean isBorrowed() {return isBorrowed;}public void setBorrowed(boolean borrowed) {isBorrowed = borrowed;}@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", author='" + author + '\'' +", price=" + price +", type='" + type + '\'' +//", isBorrowed=" + isBorrowed +(isBorrowed ? "  已被借出 " : "  未被借出 ")+'}';}
}
//书架内容
package book;public class BookList {private static final int DEFAULT_SIZE = 5;private Book[] books = new Book[DEFAULT_SIZE];private int usedSize;public BookList() {books[0] = new Book("三国","罗贯中",43,"小说");books[1] = new Book("西游记","吴承恩",40,"小说");books[2] = new Book("红楼梦","罗贯中",45,"小说");this.usedSize = 3;}public Book getBook(int pos) {return this.books[pos];}//AddOperation操作时直接在useSize位置添加图书public void setBooks(Book book) {this.books[usedSize] = book;}//DelOperation操作时,设置pos位置的值public void setBooks(int pos,Book book) {this.books[pos] = book;}public int getUsedSize() {return usedSize;}public void setUsedSize(int usedSize) {this.usedSize = usedSize;}
}//使用者包下的代码:
package user;import book.BookList;
import operate.IOPeration;
public abstract class User {public String name;public IOPeration[] ioPerations;//操作数组存储操作对象public User(String name) {this.name = name;}//主函数调用login需要显示菜单,但是父类对象没有办法使用子类里面的方法,// 所以menu()写成抽象方法,进而User类改成抽象类// 父类再调用时发生运行时绑定,会调用子类menu()方法public abstract int menu();public void doWork(int choice, BookList bookList) {this.ioPerations[choice].work(bookList);//this.ioPeration[choice] => 根据选择找到操作的对象//work(bookList) => 操作对象的具体工作}
}//管理者
package user;
import operate.*;
import java.util.Scanner;
public class AdminUser extends User{//知道对象的时候,构造方法会初始化name,初始化接口数组(管理者5个对象,借阅者4个对象)public AdminUser(String name) {super(name);//引用变量赋值,需要动态赋值:需要new一下;根据数组的下标调用操作对象this.ioPerations = new IOPeration[] {new ExitOperation(),new FindOperation(),new AddOperation(),new DelOperation(),new ShowOperation()};}@Overridepublic int menu() {System.out.println("=======================");System.out.println("hello  " + name + "  欢迎使用图书系统!");System.out.println("1.查找图书!");System.out.println("2.新增图书!");System.out.println("3.删除图书!");System.out.println("4.显示图书!");System.out.println("0.退出系统!");System.out.println("========================");System.out.println("请输入你的操作:");Scanner sc = new Scanner(System.in);int choice = sc.nextInt();return choice;}
}
//普通使用者
package user;
import operate.*;
import java.util.Scanner;
public class NormalUser extends User{public NormalUser(String name) {super(name);this.ioPerations = new IOPeration[] {new ExitOperation(),new FindOperation(),new BorrowOperation(),new ReturnOperation()};}@Overridepublic int menu() {System.out.println("=======================");System.out.println("hello  " + name + "  欢迎使用图书系统!");System.out.println("1.查找图书!");System.out.println("2.借阅图书!");System.out.println("3.归还图书!");System.out.println("0.退出系统!");System.out.println("========================");System.out.println("请输入你的操作:");Scanner sc = new Scanner(System.in);int choice = sc.nextInt();return choice;}
}//主函数:
import book.BookList;
import user.AdminUser;
import user.NormalUser;
import user.User;
import java.util.Scanner;
public class Main {public static User login() {//发生向上转型:返回值System.out.println("请输入姓名:>");Scanner sc = new Scanner(System.in);String name = sc.nextLine();System.out.println("请输入你的身份:1:管理者,0:借阅者 ");int choice = sc.nextInt();if(choice == 1) {return new AdminUser(name);} else {return new NormalUser(name);}}public static void main(String[] args) {BookList bookList = new BookList();//调用login返回的对象不确定需要父类对象来接受User user = login();//通过登录确认使用对象//显示登录对象的菜单,从而进行操作while (true) {//利用循环进行多次操作int choice =  user.menu();//根据对象调用菜单,返回操作的选择user.doWork(choice,bookList);}}
}

总结

✨✨✨各位读友,本篇分享到内容如果对你有帮助给个

自制小型图书管理系统 - 简单版(锻炼java基础语法的使用)相关推荐

  1. python实现图书管理系统(简单版)

    简单实现图书管理系统 类和面向对象编程 """ 小钟图书管理系统 1. 查询 2. 增加 3. 借阅 4. 归还 5. 退出 """ cla ...

  2. 基于java SSM图书管理系统简单版设计和实现

    本项目演示链接地址 > 主要技术:后台采用技术: SSM框架(SpringMVC + Spring + Mybatis) 前台采用技术: div + css 功能比较简单.适合学习使用 主要功能 ...

  3. Java小项目--小型图书管理系统(含完整代码及工具)

    写在前面 对于一个java项目来说,我理解的整个流程是这样的: (1)进行需求分析 (2)设计数据库(重要) (3)编写java代码 注:数据库设计非常重要,特别是数据类型的定义,表与表之间的关系,如 ...

  4. 基于SpringBoot的社区小型图书管理系统的设计与实现

    作者主页:Designer 小郑 作者简介:Java全栈软件工程师一枚,来自浙江宁波,负责开发管理公司OA项目,专注软件前后端开发(Vue.SpringBoot和微信小程序).系统定制.远程技术指导. ...

  5. 【JavaEE】图书管理系统-简易版

    文章目录 book包 Book类 BookList类 operation包 AddOperation 类 BorrowOperation 类 DelOperation类 DisplayOperatio ...

  6. BUAA(2021春)小型图书管理系统

    BUAA数据结构第二次编程题--小型图书管理系统 看前须知 第二次上机题汇总 题目内容 问题描述 输入形式 输出形式 样例 样例说明 题解 易错点和难点 参考代码 补充测试的数据 推荐题单 看前须知 ...

  7. C语言——小型图书管理系统(课程设计)

    [文末获取资源] 该系统包括以下功能: 01.注册账号 02.登录账号 03.修改密码 04.录入功能 05.添加功能 06.删除功能 07.修改功能 08.浏览功能 09.查询密码 10.排序功能 ...

  8. BUAA_数据结构_2nd_小型图书管理系统

    BUAA_数据结构_2nd_小型图书管理系统 题目描述 小明同学特别喜欢买书看书.由于书较多,摆放杂乱,找起来非常麻烦.这学期小明同学上了数据结构与程序设计课后,决定改变这种状况:用C开发一个小型图书 ...

  9. BUAA小型图书管理系统

    [问题描述] 小明同学特别喜欢买书看书.由于书较多,摆放杂乱,找起来非常麻烦.这学期小明同学上了数据结构与程序设计课后,决定改变这种状况:用C开发一个小型图书管理系统.系统中包含的图书信息有:书名.作 ...

最新文章

  1. CM5.x配置spark错误解决
  2. 2015年最棒的10个 JavaScript 框架
  3. 集合的hashCode方法的最佳实现
  4. @AI大神们 前方31万巨额奖金,别走好吗跑起来!!!
  5. 设置计算机关机静音,Shortcuts 捷径控制 Windows 电脑:静音开关、音量调节、待机、关机...
  6. python socket 发送十六进制_python用socket怎么发送一段二进制数据
  7. 排序算法之——插入排序
  8. iOS - Swift NSData 数据
  9. Qt QtCreator 所有版本官方下载地址
  10. ie6 css padding,IE6padding的一个影响布局的问题在
  11. 项目是采用目前比较流行的 SpringBoot/SpringCloudAlibaba构建新零售微服务电商项目
  12. php正则表达式经典实例,php半小时精通正则表达式
  13. 计算机专业在沈阳有什么发展,985 计算机专业在全国 TOP10 在沈阳
  14. 图卷积网络GCN的简单理解
  15. python爬取教务系统_python 爬取 强智科技教务系统(湖南)
  16. 发布Oracle存储过程包c#代码生成工具(CodeRobot)
  17. 公安如何通过大数据破案?知识图谱实现公安情报分析(人工智能大数据公司)
  18. Maven 环境变量配置
  19. 如何给澳洲路局写信refound罚金,遇到交通罚款怎么办
  20. 【社招】 中/高级C++ Developer - 美国顶尖交易公司Akuna Capital–上海

热门文章

  1. linux下的nginx重启命令
  2. Android面试题数据结构篇
  3. 云原生爱好者周刊:利用 DNS 计算圆周率
  4. 高速系统设计自学笔记——信号完整性2
  5. fst 共享后缀_FST源代码解读2——FST的生成
  6. emplace_back
  7. 使用OwnCloud建立属于自己的私有的云存储网盘(百度网盘)
  8. Word文档标题自动编号问题(下级标题不跟随上级标题)
  9. 2018年腾讯游戏安全技术竞赛进阶版writeup
  10. 1575-我想满手鲜血(思路+LIS)