ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

JSP+Servlet+JavaBean超市进销存系统:从原理到部署实战

JSP+Servlet+JavaBean超市进销存系统:从原理到部署实战 简介这是一份基于 JSP Servlet JavaBean 的超市进销存管理系统源码包面向 Java Web 初学者、课程设计及毕业设计人群。项目围绕商品信息、用户信息、分类管理、进货/出货/库存导出等模块展开通过 MVC 分层实现浏览器端与数据库的交互适合用来练习 Servlet 控制器编写、JSP 页面渲染、JavaBean 数据封装及 MySQL 增删改查等核心技能。资源共 134 个文件压缩包约 6.94 MB主要包含 14 个 Java 源文件、9 个 JSP 页面、14 个编译后的 class 文件以及配套的 CSS、JS、图片和字体资源Java 与 JSP 负责业务逻辑和页面展示静态资源用于完善前端界面配置类文件帮助快速导入 Eclipse 或 IDEA 运行。目前已有 67 人学习下载。源码均经本地编译验证下载后按文档配置环境即可运行注释与结构清晰可参考完整项目分层并直接借壳改造适合作为课设作业或进销存系统的开发蓝本。1. 基于JSPServletJavaBean的超市进销存管理系统先拆清楚再动手跑这套基于 JSPServletJavaBean 的超市进销存管理系统是很多学校里课程设计和毕业设计的高频选题。如果你正在找 jsp servlet mysql 方向的参考源码它几乎把超市业务里最常考的点都覆盖了管理员登录、用户管理、商品分类、商品管理、进货单、销售单、库存变更以及 Excel 导入导出。资源里自带编译好的 class 和源码下载后按文档配置环境就能跑。适合两类人一是想快速交一份合格课设的在校生二是想把老 JavaWeb 项目改造成 MVC 分层结构的初学者。我拆完后的第一感受是它没有用高大上的框架反而更容易看懂 Servlet 生命周期和 JavaBean 的用法。2. 技术栈与工程结构JSPServletJavaBean 这一套为什么还要学2.1 浏览器、Servlet、JavaBean、数据库四层到底怎么分工这个项目不是 Spring Boot也不是微服务而是最经典的 JavaWeb 三层协作浏览器发请求Servlet 接收请求并调度业务JavaBean 负责封装数据JSP 负责渲染页面数据库操作全部收拢在 DBOper 类里。这套分工其实就是 MVC 的早期落地形态JSP 对应 ViewServlet 对应 ControllerJavaBean 对应 Model。我第一次看这个项目的类列表时就注意到 HomeController 和 AdminController 两个类。它们就是 Controller 层的入口分别处理前台和后台的请求转发。比如访问首页时HomeController 会根据 Session 里有没有登录标记决定是放行到商品列表页还是强制跳回登录页。这一层做的是“调度”而不是“业务”业务逻辑要么写在了 Servlet 里要么下沉到 DBOper 里。下面这个片段模拟了 HomeController 的 doGet 动作// HomeController.java 片段 - 仅展示转发逻辑 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 取出当前登录用户决定跳转到首页还是登录页 HttpSession session request.getSession(false); if (session ! null session.getAttribute(adminId) ! null) { ListGoodsInfo goodsList new DBOper().queryGoodsList(); request.setAttribute(goodsList, goodsList); request.getRequestDispatcher(/index.jsp).forward(request, response); } else { response.sendRedirect(request.getContextPath() /login.jsp); } }这段代码里的 request.getSession(false) 是最容易被新手看漏的参数false 表示“如果当前没有 Session 就直接返回 null”而不是创建一个新的。很多课程设计里登录失效就是因为全站都在用 getSession(true) 乱建 Session最后内存里塞满了无用的会话。参数 false 的意义就是强制要求调用方处理“未登录”的情况这样的代码放到真实业务里也站得住脚。接着看 request.setAttribute 和 forward 的组合。setAttribute 是给 JSP 页面传一个名为 goodsList 的变量forward 则是把这次请求原封不动地转交给 /index.jsp。整个过程中 URL 不会变Session 也不会丢。这样做的价值在于 JSP 只负责从 request 里拿数据并渲染不直接拼 SQL职责清楚了很多。2.2 从类名反推系统边界这几个 JavaBean 各管哪块数据拿到压缩包后我习惯先把 class 文件的名字过一遍因为类名就是一张缩略版的设计图。这个包里值得看的类大致可以分成四组类名职责推断HomeController / AdminController前台首页与后台管理的控制层入口AdminInfo / UserInfo管理员与普通用户的信息封装GoodsInfo / CategoryInfo商品和商品分类的数据模型ImportInfo / ExportInfo进货记录与销售出库记录DBOper统一封装 JDBC 的增删改查ExcelUtil读写 Excel 的工具类以 GoodsInfo 为例它就是一个标准的 JavaBean字段基本对应商品表里的列商品编号、名称、分类、进价、售价、库存量、供应商等。下面的代码片段展示了这种 JavaBean 的常规写法// GoodsInfo.java 片段 - 商品的 JavaBean public class GoodsInfo { private Integer id; // 商品主键 private String goodsName; // 商品名称 private Integer categoryId; // 所属分类编号 private Double priceIn; // 进货价 private Double priceOut; // 售价 private Integer stock; // 当前库存 public Integer getId() { return id; } public void setId(Integer id) { this.id id; } // 其余字段的 getter / setter 同理这里省略 }你可能觉得这种满屏 getter/setter 的类很啰嗦但它恰恰是 JavaWeb 课程设计最稳的姿态。因为 JSP 的 EL 表达式比如 ${goods.goodsName}不认字段只认 getter 方法。如果把字段写成了 public 或者用了 Lombok反而可能因为依赖缺失导致页面取不到值。我建议保留最朴素的 JavaBean 写法别在课设里强行上 Lombok否则老师换一台机器运行很可能因为缺少插件直接翻车。CategoryInfo 和 UserInfo 的字段设计也遵循同一套路CategoryInfo 至少包含分类编号和分类名UserInfo 至少包含用户编号、用户名、密码和联系方式。这些字段不是拍脑袋来的而是和后面的表结构一一对应。看懂了这些 JavaBean就能反推出数据库里大概有哪些表。2.3 工具类 DBOper 与 ExcelUtil为什么把公共逻辑单独抽出这个项目最有价值的设计是把所有 JDBC 操作收拢进 DBOper。很多课设会把连接数据库的代码写得到处都是每一个 Servlet 都自己写一遍 Class.forName 和 DriverManager.getConnection。结果就是改一次数据库密码要全局搜索替换非常痛苦。DBOper 存在的意义就是让业务代码不直接碰 Connection 和 PreparedStatement只关心“查列表”和“改库存”这种业务动作。// DBOper.java 片段 - 获取连接与查询商品列表的示范 public class DBOper { private static final String URL jdbc:mysql://localhost:3306/supermarket ?useUnicodetruecharacterEncodingutf8; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); } } public ListGoodsInfo queryGoodsList() { ListGoodsInfo list new ArrayListGoodsInfo(); String sql SELECT id, goods_name, category_id, price_in, price_out, stock FROM goods; try (Connection conn DriverManager.getConnection(URL, USER, PASSWORD); PreparedStatement ps conn.prepareStatement(sql); ResultSet rs ps.executeQuery()) { while (rs.next()) { GoodsInfo goods new GoodsInfo(); goods.setId(rs.getInt(id)); goods.setGoodsName(rs.getString(goods_name)); goods.setCategoryId(rs.getInt(category_id)); goods.setPriceIn(rs.getDouble(price_in)); goods.setPriceOut(rs.getDouble(price_out)); goods.setStock(rs.getInt(stock)); list.add(goods); } } catch (SQLException e) { e.printStackTrace(); } return list; } }这段代码里最值得说明的是 try-with-resources 写法也就是把 Connection、PreparedStatement、ResultSet 放在 try 后的括号里。这样不管查询成功还是抛异常资源都会自动关闭不会出现连接泄漏。URL 上的 useUnicodetrue 和 characterEncodingutf8 这两个参数几乎是我跑 JavaWeb 课设必查的两项少一个就可能出现中文乱码。ExcelUtil 则是另一个“工具类思维”的代表。它封装了对 Excel 的读写让 ImportInfo 和 ExportInfo 能复用它。常见做法是用 Apache POI 操作 HSSFWorkbook导出商品列表或进货单时直接生成 .xls 文件导入时则逐行读取并转成集合。把这些逻辑放在一个工具类里Inport 和 Export 页面调起来就很干净也不会在 Servlet 里看到大段的 POI 样板代码。3. 核心功能拆解登录权限、进销存和 Excel 导入导出的实现逻辑3.1 登录与权限控制HomeController / AdminController 的职责边界登录功能是所有进销存系统都绕不开的入口。这个项目的登录逻辑通常放在 AdminController 里接收 login.jsp 提交的用户名和密码然后通过 AdminInfo 和 DBOper 去数据库校验。校验成功就写入 Session失败就重新跳回登录页并附带错误提示。// AdminController.java 片段 - 管理员登录校验 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding(utf-8); String username request.getParameter(username); String password request.getParameter(password); AdminInfo admin new DBOper().queryAdminByUsername(username); if (admin ! null admin.getPassword().equals(password)) { HttpSession session request.getSession(); session.setAttribute(adminId, admin.getId()); session.setAttribute(adminName, admin.getAdminName()); response.sendRedirect(request.getContextPath() /admin/index.jsp); } else { request.setAttribute(errorMsg, 用户名或密码错误); request.getRequestDispatcher(/login.jsp).forward(request, response); } }注意这里有一个容易被忽略的分工HomeController 管前台普通用户入口AdminController 管后台管理员入口两者通过 Session 里不同的 attribute 区分。上面代码中成功登录写入的是 adminId而查询商品列表时读取的也是 adminId。如果前后台混用了 attribute 名字比如前台写入 userId 后台却读 adminId就会出现“明明登录了但页面一直跳回登录页”的玄学问题。关于密码的校验方式这个项目里是直接比较明文。你如果拿去交课设我建议至少改成 MD5 或加盐哈希再做比较因为直接用 equals 比较明文密码评审老师只要打开数据库就能看到所有人的密码这样的安全边界在答辩时会被问得很难受。可以保留原逻辑运行但要在文档里说明改进方向。3.2 进货与销售事务保证库存和流水表不打架商品入库不是只往进货表里插一条记录那么简单还涉及两个关键改动一是写入进货记录 ImportInfo二是更新 goods 表的库存字段。如果这两步中间出现异常就会造成“流水表有新单据库存却原封不动”的数据不一致。解决这个问题的标准方案是 JDBC 事务。// 进货处理逻辑 - 核心事务示范 public boolean importGoods(int goodsId, int quantity, double price) { String insertImport INSERT INTO import_info(goods_id, quantity, price, import_time) VALUES(?,?,?,NOW()); String updateStock UPDATE goods SET stock stock ? WHERE id ?; Connection conn null; try { conn DriverManager.getConnection(url, user, password); conn.setAutoCommit(false); // 关闭自动提交 PreparedStatement ps1 conn.prepareStatement(insertImport); ps1.setInt(1, goodsId); ps1.setInt(2, quantity); ps1.setDouble(3, price); ps1.executeUpdate(); PreparedStatement ps2 conn.prepareStatement(updateStock); ps2.setInt(1, quantity); ps2.setInt(2, goodsId); ps2.executeUpdate(); conn.commit(); // 两条都成功才提交 } catch (Exception e) { if (conn ! null) { try { conn.rollback(); // 任何一条失败都回滚 } catch (SQLException ex) { ex.printStackTrace(); } } e.printStackTrace(); return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } return true; }这段代码里 setAutoCommit(false) 是整个事务的“总开关”。从那以后每次插入或更新都要手动 commit 才会真正落盘。参数 quantity 必须同等地用于 INSERT 和 UPDATE如果两处一个写了入库数量一个写了当前库存逻辑就会错乱。我见过把 updateStock 写成 stock stock - ? 的跟需求正好相反导致进货反而减少了库存。另外要记得 finally 里把 autoCommit 恢复为 true 再关连接。这不是形式主义因为连接池复用时如果连接还带着 false 状态下一个人拿到这条连接就会出现“改了数据但提交不了”的怪毛病排错时非常耗时间。3.3 Excel 导入导出ImportInfo/ExportInfo 怎么配合 ExcelUtil这个系统的另一个亮点是 Excel 导入导出。ExportInfo 负责把销售或库存数据整理成适合导出的 JavaBean 集合ExcelUtil 负责真正生成文件。导入则是反向过程从 Excel 文件读行塞进 ImportInfo再写数据库。// ExcelUtil.java 关键方法 - 将商品列表导出到 xls public static void exportGoods(ListGoodsInfo list, OutputStream out) throws IOException { HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(商品); String[] headers {商品编号, 名称, 分类, 进价, 售价, 库存}; HSSFRow headerRow sheet.createRow(0); for (int i 0; i headers.length; i) { headerRow.createCell(i).setCellValue(headers[i]); } for (int i 0; i list.size(); i) { GoodsInfo g list.get(i); HSSFRow row sheet.createRow(i 1); row.createCell(0).setCellValue(g.getId()); row.createCell(1).setCellValue(g.getGoodsName()); row.createCell(2).setCellValue(g.getCategoryId()); row.createCell(3).setCellValue(g.getPriceIn()); row.createCell(4).setCellValue(g.getPriceOut()); row.createCell(5).setCellValue(g.getStock()); } workbook.write(out); workbook.close(); }这段代码里的 HSSFWorkbook 是 POI 处理 .xls 格式的入口HSSFSheet 对应一张工作表。注意列头放在第 0 行数据从第 1 行开始这个起止关系容易搞混少一行对不上就会造成 Excel 打开后第一行行列错位。导出的数字直接用 setCellValue 传 double 或 int 就行POI 会自己处理成数字单元格但如果你提前把所有值拼成了字符串Excel 里就会出现“商品编号”是文本格式后续筛选排序全部失灵。导入时方向相反ExcelUtil 会读取 Workbook 的第一个 Sheet逐行创建 ImportInfo再交给 DBOper 写入数据库。导入最烦人的是单元格类型判断比如“库存”列在 Excel 里是数字POI 读出来可能是 double你要是直接强转成 int 就会抛异常常见做法是用 getCellType 先判断再取数。这一块做扎实了整个系统的业务闭环就算完整了。4. 部署与运行把下载来的源码在 IDEA Tomcat MySQL 下跑起来4.1 环境选型JDK 8、Tomcat 8.5、MySQL 5.7 的搭配理由这个项目的年龄感很明显但从课程设计角度讲它最适合跑在老三样上面JDK 8、Tomcat 8.5、MySQL 5.7。不是不能用新版而是越新的版本越容易踩坑比如 MySQL 8.0 默认的认证插件是 caching_sha2_password老项目里的 com.mysql.jdbc.Driver 连上去会直接报认证失败。下面是推荐搭配和理由组件推荐版本原因JDK1.8Servlet/JSP API 在 JDK8 下最稳定IDE 支持也最全面Tomcat8.5/9.0支持 Servlet 3.0兼容 JSP 2.3且对老 web.xml 兼容性好MySQL5.7默认认证插件是 mysql_native_password老驱动直接能用IDEIntelliJ IDEA对 Web 项目支持好社区版也能满足如果你手头只有 MySQL 8.0也不是完全不能用但需要把驱动升级到 mysql-connector-java 8.0.x并把 URL 里的驱动类改成 com.mysql.cj.jdbc.Driver。我一般会建议课设直接装 5.7省掉后面一排时区相关的报错。4.2 IDEA 导入项目与配置 Tomcat一步步操作拿到压缩包后先解压用 IDEA 的 Open 打开工程目录。如果项目不是一个 Maven 工程IDEA 会把它识别成普通 Java 模块这时候需要手动添加 Web 支持。先给出典型的项目目录结构和主流程命令unzip supermarket.zip # 得到 supermarket 目录里面包含 src、web、lib 等子目录 # 如果项目自带 WAR 包可以直接用 Tomcat 部署 cp supermarket.war $CATALINA_HOME/webapps/ startup.bat # Windows 启动 Tomcat如果选择 IDEA 图形化操作步骤是这样的打开 Project Structure在 Facets 里添加 Web把 web.xml 路径指向项目中的 web/WEB-INF/web.xml然后把 Artifacts 设置成 Web Application Exploded。接下来配置 Tomcat在 Run/Debug Configurations 里新增 Tomcat Server - Local选择 Tomcat 安装目录在 Deployment 里加上这个 Artifact。部署完后启动 Tomcat浏览器访问 http://localhost:8080/supermarket/ 就能看到首页。!-- web.xml 关键配置片段确认 Servlet 映射是否有问题 -- servlet servlet-nameAdminController/servlet-name servlet-classcom.supermarket.servlet.AdminController/servlet-class /servlet servlet-mapping servlet-nameAdminController/servlet-name url-pattern/admin/url-pattern /servlet-mapping注意 web.xml 里如果同时用了注解和 XML 映射并且两者冲突容器启动时可能直接报重复映射错误。看到这类报错先把注解拿掉或者先删 XML 片段二选一。4.3 数据库初始化建库建表语句与连接参数初始化数据库是整个部署里最不能偷懒的一步。我一般先用 MySQL 命令行建库再导入 SQL 脚本。下面是一个最小化的建库建表示例对应项目里的核心表CREATE DATABASE IF NOT EXISTS supermarket DEFAULT CHARACTER SET utf8mb4; USE supermarket; CREATE TABLE goods ( id INT PRIMARY KEY AUTO_INCREMENT, goods_name VARCHAR(100) NOT NULL, category_id INT NOT NULL, price_in DECIMAL(10,2), price_out DECIMAL(10,2), stock INT DEFAULT 0 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE admin_info ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL, admin_name VARCHAR(50) ); INSERT INTO admin_info (username, password, admin_name) VALUES (admin, 123456, 系统管理员);表结构要与 JavaBean 字段对应。注意我在建表时用了 utf8mb4 而不是 utf8因为 utf8mb4 能存 emoji 和一些生僻字虽然课设里不一定用得上但用 utf8 在某些 MySQL 5.7 版本上插入中文时会有“Incorrect string value”的报错utf8mb4 是更稳的选择。密码字段建议直接用 VARCHAR(64)为后面改造 MD5 留足长度。数据库连接参数在 DBOper 类里改主要是 URL、用户名、密码三项。如果测试环境和开发环境不是同一个数据库建议把这三项提取到 properties 文件里这样换配置不用重新编译代码。具体路径一般在 src/jdbc.propertiesDBOper 里用 ResourceBundle 读取即可。5. 避坑与排查本地编译通过但跑不起来的 5 条血泪经验5.1 现象启动 Tomcat 后访问项目控制台报 ClassNotFoundException: com.mysql.jdbc.Driver原因MySQL 驱动 jar 没有放到 WEB-INF/lib 目录。IDEA 里项目能编译是因为驱动在模块依赖里但 Tomcat 运行时只认 WEB-INF/lib。解决把 mysql-connector-java-5.1.49.jar 复制进 web/WEB-INF/lib然后重新构建 Artifact重启 Tomcat。注意 Tomcat 的 lib 目录里有没有都不算数必须跟着应用走。5.2 现象项目里明明写了 WebServlet(/login)但访问时 404原因项目没有切换成 Servlet 3.0 规范或者 IDEA 的 Facets 里 Web 版本选成了 2.5。Servlet 2.5 不支持注解扫描必须靠 web.xml 手动映射。解决在 Project Structure 的 Facets 设置里把 Web 版本改成 4.0 或 3.1确认 web.xml 的头部声明是 metadata-completefalse。如果不想折腾就在 web.xml 里手动补全每个 Servlet 的映射。5.3 现象导出 Excel 打开后中文列头全是问号商品编号成了 1.01E11原因列头乱码是 Excel 需要设置 cell 字符串编码通常是没有把列头放入 uniString 或者 workbook 没有设置 encoding。数字变科学计数法是单元格格式问题POI 默认数字被 Excel 显示成常规格式长数字会被缩写。解决列头创建后在 cell 上设置 cell.setCellType(CellType.STRING)或者直接用 setCellValue 传入 String。数字长度超过 11 位时强制这一列用文本格式cellStyle.setDataFormat(workbook.createDataFormat().getFormat(0))。最简单的方式是把长 id 拼接成字符串再写入。5.4 现象登录成功后跳转回首页一刷新又被踢回登录页原因Session 在两次请求之间丢失。常见原因有两个一是 Tomcat 的会话 Cookie 路径写在了 /supermarket 下而你访问时用了带后缀的 URL二是代码里用了 request.getSession(true) 之后没有把 attribute 传给正确的 key前后台读的 key 不一致。解决先统一 Session attribute 的 key后台登录写 adminId后台过滤器就只读 adminId。然后在浏览器开发者工具里看 Cookie 的 Path 是否为 /supermarket。如果 Cookie 丢失检查 Tomcat 是否配置了 context path 以外的路径。我那次就是因为项目部署名带了下划线Cookie Path 里却少了个下划线导致请求都带不上 JSESSIONID。5.5 现象连接 MySQL 8.0 报 Communications link failure 或时区错误 The server time zone value原因MySQL 8.0 默认的驱动类和时区要求都变了老项目里用 com.mysql.jdbc.Driver 和旧 URL 格式天然不兼容。解决把驱动换成 mysql-connector-java-8.0.33URL 改成 jdbc:mysql://localhost:3306/supermarket?serverTimezoneAsia/ShanghaicharacterEncodingutf8驱动类改成 com.mysql.cj.jdbc.Driver。如果是 5.7则保持原样。这一步是目前所有老 JavaWeb 项目升级数据库时最容易翻车的地方。6. 进阶改造Filter 统一编码与登录校验附验收验证清单6.1 用 Filter 取代 Servlet 里的重复编码/登录检查这个系统如果拿去做毕业设计最大的加分项不是再塞一个功能而是把代码里的重复逻辑收拢。我看了一下每个 Servlet 开头都会写 request.setCharacterEncoding(utf-8)登录后的每个页面也都在手工检查 Session。用 Filter 可以一次性解决这两件事// CharacterEncodingFilter.java - 统一编码过滤器 WebFilter(/*) public class CharacterEncodingFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(utf-8); response.setCharacterEncoding(utf-8); chain.doFilter(request, response); } }这段代码里的 /* 表示所有请求先经过它chain.doFilter 是放行。有了它原来每个 Servlet 开头的编码设置全部可以删掉代码能瘦一圈。登录校验也可以做成 Filter但要注意把 login.jsp、登录请求、静态资源放行否则会把自己人卡在外面。那时候你只需要在 web.xml 的 filter-mapping 里调整 url-pattern 的匹配范围就能做到入口统一拦截。6.2 用最少的用例验收系统端到端是否可用改造完以后我习惯用一张表做回归验证不至于等到答辩现场才被发现跑不通。别小看这一步很多课设看起来能启动但重启 Tomcat 之后 Session 失效、库存不对、Excel 导不出都是因为没做端到端验证。你可以照着下面这张表过一遍用例操作预期结果管理员登录输入 admin/123456跳转后台首页右上角显示管理员名登录校验输入错误密码停留在登录页并提示错误新增商品填写名称、分类、价格、库存商品列表出现新记录进货入库对商品执行进货 20 件库存增加 20进货表多一条记录导出商品点击导出按钮Excel 中行数和商品列表数一致重启恢复重启 Tomcat 后再登录商品和库存数据仍在这张表里的“重启恢复”最容易被漏掉。我当年交课设前为了赶时间从不重启 Tomcat结果验收那天老师直接当场重启服务器我的 Session 方案没处理好整个演示都在登录页面打转。从那以后我每次跑完一个 JavaWeb 项目都会强制走一遍“关闭 Tomcat → 重新启动 → 登录 → 新增 → 导出”的完整流程确认不是碰运气跑通的。希望这些经验能帮你在自己的项目上少踩几个坑。本文还有配套的精品资源点击获取
返回列表