ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Java+MySQL图书馆信息管理系统:从环境配置到期末答辩完整指南

Java+MySQL图书馆信息管理系统:从环境配置到期末答辩完整指南 简介一份基于Java与MySQL的图书馆信息管理系统完整项目面向计算机专业学生适用于期末大作业、课程设计或本科毕业设计参考。项目包含前端Vue页面、后端Java服务、数据库SQL脚本以及配套说明文档代码注释详细清晰降低了初学者的理解门槛。资源包内共152个文件大小约11.79MB主要包括Java源码、Vue组件、JavaScript脚本、CSS样式表、SQL数据脚本和Markdown说明文件文件分类明确前后端与数据库结构一目了然便于按模块查阅与二次开发。系统实现了图书信息管理、借阅与归还流程、读者资料维护、图书检索等常用功能界面简洁美观操作逻辑顺畅经过完整调试后可直接部署使用。该项目由作者在课程作业中开发并获得高分目前已有153人在CSDN学习下载整体评价良好是完成期末大作业和毕业设计的实用参考资料。1. 图书馆信息管理系统期末大作业里最容易被低估的JavaMySQL项目期末周拿到这套题的人多半先搜个开源项目改改结果困在JDBC驱动版本、MySQL 8认证插件和Tomcat端口冲突里正经业务代码一行没写。图书馆信息管理系统作为Java和MySQL期末大作业核心是登录会话、图书/读者/借阅三类对象的增删改查以及借书还书时的事务边界——没有高并发、没有分布式但它恰好把JavaWeb最该考的语法、JDBC操作、SQL设计全串起来了。这个方向适合两类人一是想用一个完整案例把JavaWeb链路走通的初学者二是需要一份能过答辩、文档齐全的期末交付物。别指望它炫技它值钱的地方是结构完整、能跑通、能讲明白。2. 项目结构与技术选型先分清JSPServlet和Spring Boot的边界2.1 这套系统到底长什么样三个功能域与两条数据流我拿到这种标题的项目第一件事不是看代码是画功能边界。图书馆信息管理系统无论怎么改功能域都不会跑出三块读者端查书借书还书、管理员端图书管理、系统端的登录与权限控制。对应到数据流就是两条一条是读者发起借阅系统扣减库存并生成借阅记录另一条是管理员维护图书信息所有操作落MySQL。把这两个流画清楚后面所有表和代码都是顺着填坑。期末大作业的常见做法是用JSPServletJDBC不引Spring Boot。原因很实际多数学校JavaWeb课程教的就是Servlet和JSPSpring Boot在答辩时容易被追问“依赖原理”答不上来反而减分。但如果你是自学者Spring Boot能省掉大量web.xml配置用RestController暴露JSON接口前端用简单HTMLaxios就够。标题只说JAVA和MySQL没限定框架我建议按你课程进度选——课程教的是Servlet就写Servlet别用一个你没在课堂上讲过的框架冒险。2.2 环境清单与版本对应JDK、Tomcat、MySQL怎么配对环境配不齐是这类项目跑不起来的头号原因。我一般用这套组合JDK 8、Tomcat 8.5、MySQL 5.7或8.0、Eclipse或IDEA。JDK 8配Tomcat 8.5几乎不会有什么兼容问题Servlet 3.1规范对应Tomcat 8.5JavaEE项目粘贴进去直接部署。MySQL方面5.7和8.0都行但JDBC连接串不一样尤其是8.0必须带serverTimezone参数驱动类名也从com.mysql.jdbc.Driver变成了com.mysql.cj.jdbc.Driver。这一点在避坑章节我会展开说。如果你的机器还没装MySQL网上mysql安装配置教程非常多我提三个要点安装时选UTF-8字符集、端口保持默认3306、服务名记住别和旧版冲突。装好以后用命令行验证一下能进MySQL才继续下一步。JDK环境变量配置同样是个常见卡点配好后在命令行执行java -version确认输出1.8版本再开始写代码。2.3 建库建账号先给项目开一块独立数据库空间不要直接拿root账号连数据库更不要和别人的作业共用一个库。我建这类项目时固定先创建一个独立数据库和专用账号权限只给这一个库这样即使代码里写错SQL也不会影响机器上其他数据库。CREATE DATABASE IF NOT EXISTS library_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER lib_userlocalhost IDENTIFIED BY Lib2024; GRANT SELECT, INSERT, UPDATE, DELETE ON library_db.* TO lib_userlocalhost; FLUSH PRIVILEGES;utf8mb4和utf8的区别在于emoji和生僻字虽然期末项目用不到但答辩时说出这个细节是加分项。GRANT语句只授权了SELECT/INSERT/UPDATE/DELETE四种操作没给DROP和CREATE权限这会在建表阶段带来一点麻烦。实际做法是先用root建完表再回收权限重新授权或者直接给lib_user加上CREATE和DROP权限等项目收尾再收回来。命令行工具里SHOW DATABASES;能看到新库就说明环境这块已经通了。2.4 项目目录结构与JDBC连接池从哪里放Java文件、哪里放JSP完整的期末项目目录都是按Maven或WebContent组织的。如果是Maven工程结构固定为src/main/java放Servlet和工具类src/main/webapp放JSP、CSS、JS和WEB-INF/web.xml。如果是WebContent结构Java文件在src下JSP在WebContent下两个结构本质上一样。library-system/ ├── src/main/java/com/library/ │ ├── dao/ # 数据访问层全是JDBC操作 │ ├── model/ # 图书、读者、借阅记录的实体类 │ ├── servlet/ # 控制器接收HTTP请求并跳转 │ └── util/ # DBUtil数据库连接工具 ├── src/main/webapp/ │ ├── WEB-INF/web.xml │ ├── css/ js/ │ ├── login.jsp │ └── book_list.jsp └── src/main/resources/db.propertiesdb.properties放数据库连接配置这是整个项目最容易改错的地方。我把这里单独拧出来说因为很多同学直接把这个文件里的URL写错就报CommunicationsException。jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/library_db?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 jdbc.usernamelib_user jdbc.passwordLib2024 jdbc.maxPoolSize20 jdbc.initPoolSize5JDBC连接不建议每次都DriverManager.getConnection因为频繁创建连接非常慢。简单做法是写一个DBUtil类用静态代码块读取配置文件再用连接池管理。期末项目用DBCP或C3P0都行配置里maxPoolSize控制在20以内就够了不要抄生产环境的几百那会让Tomcat启动变慢。serverTimezoneAsia/Shanghai是MySQL 8的强制要求不写会直接报时区错误。3. 数据库设计与事务图书、读者、借阅三张表怎么撑起整套系统3.1 三张核心表的DDL字段类型、默认值与索引图书馆系统的数据模型谈不上复杂但期末答辩时老师最喜欢问的就是“为什么这样设计”。图书表、读者表、借阅表三张是必备的管理员表视需求决定要不要。图书表里book_id做主键stock字段记录当前可借数量total_stock记录总量这两个字段分开是有讲究的——还书时要恢复stock但total_stock保持历史总量不被动。读者表里status默认值为00表示正常1表示禁借这比删除读者更稳妥因为历史借阅记录不能因为读者被删就断了外键关联。CREATE TABLE book ( book_id INT AUTO_INCREMENT PRIMARY KEY, isbn VARCHAR(20) NOT NULL UNIQUE, title VARCHAR(100) NOT NULL, author VARCHAR(50) NOT NULL, category VARCHAR(30), publisher VARCHAR(60), publish_date DATE, stock INT NOT NULL DEFAULT 0, total_stock INT NOT NULL DEFAULT 0, INDEX idx_book_title (title), INDEX idx_book_category (category) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE reader ( reader_id INT AUTO_INCREMENT PRIMARY KEY, reader_no VARCHAR(20) NOT NULL UNIQUE, name VARCHAR(50) NOT NULL, phone VARCHAR(20), status TINYINT NOT NULL DEFAULT 0, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_reader_name (name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE borrow ( borrow_id INT AUTO_INCREMENT PRIMARY KEY, book_id INT NOT NULL, reader_id INT NOT NULL, borrow_date DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, due_date DATETIME NOT NULL, return_date DATETIME DEFAULT NULL, status TINYINT NOT NULL DEFAULT 0, CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES book(book_id), CONSTRAINT fk_borrow_reader FOREIGN KEY (reader_id) REFERENCES reader(reader_id), INDEX idx_borrow_status (status), INDEX idx_borrow_due (due_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;三张表的字段设计是答辩的重点。book表的isbn加了UNIQUE约束防止同一本书录入两次。borrow表用status表示借阅状态0表示借出未还1表示已归还2表示逾期未还——逾期状态通常是定时任务或还书时判断。外键在期末项目里必须加老师用Navicat看表关系图时外键连线能直接证明你理解了数据关联。有人会图省事用MyBatis-Plus根据实体类生成建表SQL但手写DDL在答辩时被问字段含义时能答得有条理建议你亲自写一遍这些建表语句。3.2 借书与还书事务为什么必须用Connection控制借书操作不是一条INSERT就完事。它要做两件事在borrow表插入借阅记录同时把book表的stock减1。这两件事必须放在同一个事务里否则会出现“记录插了但库存没减”或“库存减了却没记录”的脏数据。期末项目很多人忽略这一点直接用两个dao方法各执行各的答辩演示时连点两次借书库存就变成负数了。public void borrowBook(int bookId, int readerId) { Connection conn null; PreparedStatement psInsert null; PreparedStatement psUpdate null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); String sqlInsert INSERT INTO borrow(book_id, reader_id, due_date) VALUES(?, ?, DATE_ADD(NOW(), INTERVAL 30 DAY)); psInsert conn.prepareStatement(sqlInsert); psInsert.setInt(1, bookId); psInsert.setInt(2, readerId); psInsert.executeUpdate(); String sqlUpdate UPDATE book SET stock stock - 1 WHERE book_id ? AND stock 0; psUpdate conn.prepareStatement(sqlUpdate); psUpdate.setInt(1, bookId); int rows psUpdate.executeUpdate(); if (rows 0) { conn.rollback(); throw new RuntimeException(库存不足借阅失败); } conn.commit(); } catch (SQLException e) { try { if (conn ! null) conn.rollback(); } catch (SQLException ex) {} e.printStackTrace(); } finally { DBUtil.close(conn, psInsert, psUpdate); } }这段代码的要点全在setAutoCommit(false)和rollback()上。MySQL默认autocommit为1每条SQL都自动提交手动关闭后INSERT和UPDATE变成一个原子操作任何一个失败都能撤回。WHERE book_id ? AND stock 0这句是防止并发超借的关键——即使连续两个人同时借同一本书也只能有一个走通因为第二个的stock 0条件在行锁下不成立。这就是MySQL锁分类里InnoDB行锁的实际应用比单纯在Java代码里判断库存数量可靠得多。期末答辩时把这个逻辑讲清楚老师会认为你理解了并发下的数据一致性。3.3 还书与逾期罚款存储过程不是必须的还书操作跟借书对偶更新borrow表把return_date设为当前时间、status设为1再把book表stock加1。这里有个边界情况就是逾期。我的做法是还书时判断due_date和NOW()的大小如果还书时间大于应还时间就把borrow表里加一个overdue_days字段记录逾期天数罚款金额在Java代码计算而不是在SQL里算。常见做法是写一个MySQL存储过程处理整个还书流程但我不会这么干——期末作业写存储过程答辩时老师会抓住不放问存储过程和普通SQL的性能差异、调试手段反而容易翻车。MySQL存储过程更适合那种固定流程、多步操作、反复调用的场景但JavaServlet项目里事务控制已经在代码层做了存储过程的价值就没那么大。你要是在课程里学了存储过程想展示一下可以写一个简单的count_overdue()返回当前逾期记录数挂在管理员统计页面上不至于说不清楚。4. 登录、CRUD与分页从Servlet到JDBC的完整请求链4.1 登录会话与过滤器每个页面都要防未授权访问图书管理里登录模块是第一个要写的功能也是期末答辩进场必演示的功能。流程是JSP页面提交用户名密码到LoginServletServlet查管理员表验证通过就request.getSession().setAttribute(admin, adminUser)写入会话验证失败就重定向回登录页并带一个error参数。这类系统里密码存储建议用MD5加盐至少比明文强一个档次答辩时被问安全问题也能给出合理回复。但光登录成功还不够如果不拦截未登录访问别人直接输入book_list.jsp的地址就能绕过登录进入系统这道防线必须补上。Servlet 3.0以后支持注解方式配置过滤器不用动web.xml代码量也小。WebFilter(/*) public class AuthFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req (HttpServletRequest) request; HttpServletResponse resp (HttpServletResponse) response; String uri req.getRequestURI(); if (uri.endsWith(login.jsp) || uri.contains(LoginServlet) || uri.contains(/css/) || uri.contains(/js/)) { chain.doFilter(request, response); return; } Object admin req.getSession().getAttribute(admin); if (admin null) { resp.sendRedirect(req.getContextPath() /login.jsp); return; } chain.doFilter(request, response); } }过滤器的逻辑很简单静态资源和登录相关的路径放行其余路径全部检查Session里有没有admin对象。这个过滤器写在com.library.filter包里是典型的一劳永逸组件。注意WebFilter(/*)拦截的是所有请求所以放行条件必须把JSP、Servlet、静态资源分清楚否则会陷入页面无限重定向。用uri.contains()判断路径时要带上前缀比如/css/不然xxxcssss.jsp这种路径也会被误放行。4.2 图书增删改查PreparedStatement防注入与参数校验图书管理是管理员端的主界面包含列表展示、新增、修改、删除四个操作分别对应BookServlet里四个方法或用action参数区分。每一个操作都要走“接收参数 → 构建SQL → 执行 → 回显结果”这条线但新手最容易犯的错是在Servlet里拼接SQL字符串String title request.getParameter(title); String sql SELECT * FROM book WHERE title title ;这种做法在期末作业里能跑通但只要在搜索框输入 OR 11就会把整个图书表拉出来答辩演示时现场翻车非常难看。正确写法是用PreparedStatement占位符让JDBC驱动处理特殊字符。public ListBook searchBooks(String keyword) { String sql SELECT * FROM book WHERE title LIKE ? OR author LIKE ? ORDER BY book_id DESC; ListBook books new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, % keyword %); ps.setString(2, % keyword %); try (ResultSet rs ps.executeQuery()) { while (rs.next()) { Book book new Book(); book.setBookId(rs.getInt(book_id)); book.setTitle(rs.getString(title)); book.setAuthor(rs.getString(author)); books.add(book); } } } catch (SQLException e) { e.printStackTrace(); } return books; }PreparedStatement的setString会把单引号转义这是防SQL注入的最低门槛。搜索条件用LIKE ?配合%keyword%MySQL排序默认按主键升序这里用ORDER BY book_id DESC让新书显示在最前面很符合图书管理的展示习惯。还有一个容易忽略的点增删改操作执行完必须做重定向resp.sendRedirect(BookServlet?actionlist)如果用了forward转发用户按F5刷新页面会重复提交表单造成重复插入数据。4.3 分页查询与状态筛选LIMIT的offset该怎么算图书列表页数据一多不分页就会被老师指出页面性能问题。MySQL分页用LIMIT offset, size但很多人会猛地忘了offset从0开始第二页直接传pageNum * pageSize导致每页最后一两条数据被跳过去或重复显示。我一般用这个公式offset (currentPage - 1) * pageSize。public ListBook getBooksByPage(int currentPage, int pageSize) { int offset (currentPage - 1) * pageSize; String sql SELECT * FROM book ORDER BY book_id DESC LIMIT ?, ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setInt(1, offset); ps.setInt(2, pageSize); try (ResultSet rs ps.executeQuery()) { // 遍历结果集封装Book对象 } } catch (SQLException e) { e.printStackTrace(); } return books; } public int getTotalCount() { String sql SELECT COUNT(*) FROM book; // 返回记录总数用于计算总页数 }LIMIT后的两个参数分别是offset和rowsLIMIT 0, 10取第1到10条LIMIT 10, 10取第11到20条。前端页面用一个pageNav.jsp公共组件接收currentPage和totalPages渲染上一页/下一页按钮。totalPages通过(totalCount pageSize - 1) / pageSize计算这种写法比浮点数除法然后向上取整更稳不会出现10条记录、pageSize为3时算出的页数偏小的问题。如果每页想显示借阅次数最多的图书来丰富页面MySQL排序换成ORDER BY borrow_count DESC但需要在book表加一个冗余字段borrow_count每次借书成功时顺便把它加1比每次实时COUNT(*)关联查询快得多。5. 常见问题与避坑排查为什么在别人电脑能跑到你这就启动失败5.1 Tomcat启动即报ClassNotFoundException驱动JAR到底放哪个目录现象项目部署到Tomcat启动时立刻报ClassNotFoundException: com.mysql.cj.jdbc.Driver或com.mysql.jdbc.Driver但IDE里明明引用了mysql-connector-java包。原因驱动JAR的发布范围不对。在IDEA里如果把JAR加到Project Structure的Libraries里编译期能找到类但运行时Web应用是加载WEB-INF/lib下的JAR。scope为provided的依赖也不会被复制到lib目录。解决把JAR物理复制到src/main/webapp/WEB-INF/lib/下或者在Maven的pom.xml中确认scope不是provided。检查方法很简单展开部署目录看看WEB-INF/lib里有没有那个jar包没有就手工复制。顺带确认驱动类名和你MySQL版本匹配MySQL 5.7用com.mysql.jdbc.DriverMySQL 8.0用com.mysql.cj.jdbc.Driver写错一个字都不可能注册成功。5.2 Communications link failureMySQL 8的认证插件和时区两个坑叠加现象连接串写对了、用户密码也对但报Communications link failure后面跟一串Server connection failure或Public Key Retrieval is not allowed。原因MySQL 8.0默认用caching_sha2_password认证插件而一些老版本JDBC驱动只支持mysql_native_password另外连接串缺了serverTimezone参数也会在握手阶段失败。解决驱动换成8.0.x连接串路径补上useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8。如果已经在生产环境不好换驱动也可以执行ALTER USER lib_userlocalhost IDENTIFIED WITH mysql_native_password BY yourpass;把认证插件改回去。我一般两条路同时走驱动升级到位认证插件也改成native两边兼容最少折腾。allowPublicKeyRetrievaltrue这个参数在首次连接时也需要尤其当你用root账号通过TCP远程连MySQL时建议在连接串里一并加上。5.3 中文乱码三个层级的编码必须一致现象JSP页面显示“图书名称”变成“å¾ä¹¦ä¸»æ”或者写进数据库的汉字全部变成问号。原因三个层级的编码不一致——JSP文件本身的编码、服务器响应编码、数据库连接参数编码和表字段编码。最常见的是JSP文件用了GBK但连接串characterEncodingutf8再往utf8mb4表里写必然乱码。解决统一成UTF-8。JSP文件头写% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8%Servlet里request.setCharacterEncoding(UTF-8)必须在读取第一个参数之前调用放在doGet/doPost第一行MySQL连接串带characterEncodingutf8表的DEFAULT CHARSETutf8mb4。还需要在Tomcat的server.xml给Connector加URIEncodingUTF-8处理GET请求参数的中文乱码。这四个地方全对齐后再测试就不会出现玄学乱码了。5.4 端口被占用与虚拟机内存不足Tomcat起不来的两个隐性原因现象Tomcat启动时IDE控制台报Port 8080 required by Tomcat v8.5 Server at localhost is already in use或者启动一半就崩last line是OutOfMemoryError。原因8080被其他进程占了常见是之前调试时的残留进程也可能被一些开发工具占用。内存不足则是因为JSP编译和IDE同时吃内存默认的JVM堆不够。解决Windows命令行执行netstat -ano | findstr 8080查到占用进程的PID再用taskkill /PID pid /F结束它或换一个端口在server.xml里把Connector port8080改成8081然后所有访问URL同步改。内存问题在Catalina的setenv.sh或IDEA的VM options里设-Xms256m -Xmx512m期末项目这个量级足够了不要盲目调大因为物理内存不够时设大反而报错。改完端口启动成功后用浏览器访问http://localhost:8080/项目名验证能打开登录页就说明Web容器这层通了。5.5 连接未关闭导致连接池耗尽finally里忘了close会怎样现象系统用着用着突然变慢接着报Too many connections或Connection is not available, request timed out重启Tomcat又能用几分钟然后继续变慢。原因DBUtil.getConnection()每调用一次连接池就借出一个连接代码里ResultSet或PreparedStatement没有在finally块中关闭连接不会自动归还。DBCP连接池默认最大连接数20借出一个少一个泄漏到20个就彻底卡住。解决所有数据库操作都按“try-with-resources或finally关闭”的固定写法。我强烈建议用Java 7以后的try-with-resources它自动处理关闭逻辑少写很多重复代码。public ListBook listBooks() { String sql SELECT * FROM book ORDER BY book_id DESC; ListBook books new ArrayList(); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { // 封装Book对象写入books } } catch (SQLException e) { e.printStackTrace(); } return books; }try (Connection conn ...)会在try块结束自动调用closePreparedStatement和ResultSet同样被自动关闭。注意关闭顺序问题——Connection、Statement、ResultSet谁先关try-with-resources是按声明逆序关闭先关ResultSet再关Statement最后关Connection正好符合要求。手写finally时最容易踩的反而是反着关先关Connection导致后续关闭Statement抛异常被吞掉后很难排查。你可以在DBUtil里加一个计数器静态变量每次getConnection加一、每次close减一跑几个操作后打出数值验证是否有泄漏。6. 文档说明与答辩准备一份能加分的期末作业怎么收尾标题末尾写着“文档说明”这意味着交付物里除了能跑的代码还有配套文档。期末答辩老师看文档第一看格式是否完整第二看重点有没有讲透。我在交付这类项目时文档通常包含四件套需求说明、数据库设计说明、系统操作手册、核心代码讲解。数据库设计说明要放E-R图和三张表的字段说明表字段说明表里列出字段名、类型、是否为空、默认值、注释这比贴一段DDL直观得多老师扫一眼就知道你设计表的思路。答辩演示有一条技巧是我的血泪经验不要从登录页开始点先打开数据库客户端展示三张表和它们的关联关系再打开项目跑登录然后演示借书流程。这样做的目的是让老师一开始就看到“数据模型”这个设计核心而不是花三分钟看你输入账号密码。借书时故意把图书库存加到很大的书里连续借两本展示stock递减还书时演示逾期判断。功能演示完再翻到文档里的E-R图把外键关系和事务边界说一遍整个过程控制在十分钟内。验证做完以后有一件事容易忽略——把MySQL连接信息从代码里抽出去改用配置文件并在文档里说明db.properties是唯一需要按环境修改的文件。老师把项目拷回去自己跑的时候只需要改数据库密码就能运行不需要翻遍Servlet找JDBC连接串这个细节直接关系到最后印象分。还要确认Java文件里的注释是中文且覆盖关键方法不要让代码里残留一堆TODO和无注释的诡异逻辑。我每次带学生交付这套项目都会提醒一个收尾习惯把SQL建表脚本放在项目的sql/目录下文件名带上日期和版本比如20240610_library_schema.sql。这看起来多了一步但老师让你现场建库或者你自己换机器演示时一句source sql/20240610_library_schema.sql就能恢复整个环境不用手工一条条执行。希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表