简介:一套基于JavaWeb的房地产项目期末大作业设计源码,面向高校计算机专业学生与JavaWeb初学者,可作为课程设计、期末大作业或毕业设计的参考实现。项目围绕房地产信息管理场景,包含房源管理、用户交互、后台管理等常见业务模块,前端采用JSP、HTML、CSS与JavaScript,后端以Java为核心,形成完整的Web应用结构。资源压缩包共103个文件,大小3.12MB,涵盖57个Java源文件、11个JSP页面、12个GIF图片、6个CSS样式表、3个JavaScript脚本、2个HTML页面,以及字体文件、配置文件、Git忽略文件和LICENSE文件等,各文件按功能归类,便于对照学习前后端逻辑与页面美化。当前已有113人浏览学习。源码目录结构清晰,适合分层阅读,既能帮助理解JSP与Servlet的交互流程,也能参考JavaWeb项目的文件组织、配置管理及模块划分方式;同时,房产管理系统的业务场景贴近实际,可作为稳固JavaWeb基础、积累项目经验的实践素材。
1. 基于JavaWeb的房地产项目期末大作业设计源码:这题到底想让你交什么
到了学期末,老师发下一个题目:基于JavaWeb的房地产项目期末大作业设计源码。很多同学看到“源码”两个字就以为只要把代码交上去就行,实际上这门课验收的是三样东西——可运行的JavaWeb工程、能讲清设计思路的答辩、以及配套的数据库脚本和数据。题目本身并不难,核心是围绕“房源、客户、成交”三个业务对象,用Servlet、JSP、JDBC和MySQL把增删改查串起来;难点在于很多人到第14周才发现,IDEA里跑不起来的项目比没写完的项目更致命。这篇笔记就顺着“源码”这个交付物,把架构选型、表结构设计、本地启动步骤和踩坑点一次讲透,适合正在赶课设、想快速把一套JavaWeb工程模板改成租赁系统或二手房系统的读者。
2. 先把架构立住:Servlet+JSP+MySQL为什么是这类源码的最稳底座
2.1 选型理由:为什么不用Spring Boot当期末作业
每次看到有同学用Spring Boot交JavaWeb大作业,我都替他捏把汗。Spring Boot当然能实现功能,但它把Tomcat内嵌、注解扫描、依赖注入全包了,课设答辩老师最喜欢问的一句话是“请求从浏览器到数据库是怎么走的”,用Spring Boot的学生往往只能答出“启动类上加@SpringBootApplication,然后Controller里写接口”。一旦追问到Filter、Servlet、Session、JDBC连接,整段垮掉。
反观Servlet+JSP+JDBC这套组合,虽然代码啰嗦,但每一步都在明面上:请求进Tomcat,Tomcat按web.xml里的映射找到Servlet,Servlet调Service,Service调Dao,Dao里写JDBC连MySQL,查完结果set到request域里forward给JSP渲染。这个链路就是JavaWeb课程大纲本身,期末大作业考的就是它。搜“javaweb项目完整案例mysql”这类关键词的同学,真正需要的不是炫技框架,而是一条能连上数据库、能查房源列表、能说清每一行代码的完整链路,Servlet+JSP恰恰是这条链路的最低成本实现。
有人会说Spring Boot更好找工作,这话没错,但期末大作业的目的不是招工,是过答辩。等这套Servlet结构的源码跑通、原理讲透,再去看Spring Boot的封装,反而更容易理解它到底封装了什么。优先级排清楚:先保证能交、能讲,再谈技术先进性。
2.2 源码目录结构与包规划:照着建就不会乱
拿到一个JavaWeb房地产项目源码,第一件事不是看业务代码,而是看包结构。一个能让人看懂的课设源码,分包一定是有规律的。我一般会按“实体、数据访问、业务、控制、工具”五层拆:
estate ├── src │ ├── com.estate.entity # 实体类:Building、House、Customer、Deal、Admin │ ├── com.estate.dao # 数据访问接口 + JDBC实现 │ ├── com.estate.service # 业务逻辑接口 + 实现 │ ├── com.estate.web # Servlet:HouseServlet、CustomerServlet、DealServlet │ ├── com.estate.util # JDBCUtil、PageUtil、StringUtil │ └── com.estate.filter # EncodingFilter、AuthFilter ├── web │ ├── static # css、js、images │ ├── WEB-INF │ │ ├── lib # mysql-connector-java.jar,必须存在 │ │ └── web.xml # Servlet映射、欢迎页、过滤器声明 │ ├── login.jsp # 登录页 │ ├── house_list.jsp # 房源列表 │ ├── house_add.jsp # 新增房源 │ ├── customer_list.jsp # 客户列表 │ └── deal_list.jsp # 成交记录 └── db └── init.sql # 建库建表 + 测试数据这套结构对应的是最经典的三层架构。entity是“表映射”,一个类对应一张表;dao层只做SQL和结果集封装;service层处理业务判断,比如“房源已售就不能再挂到成交列表里”;web层的Servlet只干三件事——收参数、调Service、选JSP跳转。这样分的好处是,答辩时老师问“如果要加一个付款方式字段,改哪里”,你能秒答“entity加属性、数据库加列、表单加输入框”,这说明你真有分层意识。
项目里有个很容易被忽略的问题:WEB-INF/lib里如果没有mysql驱动jar,代码写得再对也启动不了。IDEA有时候不会自动把外部引入的jar同步到部署包里,这也是后面第5章要重点排查的坑。
2.3 一次房源查询的完整调用链:从JSP到MySQL再回显
把架构说成概念没用,得看一次真实请求怎么走。假设页面上要展示所有在售房源,最核心的两段代码长这样。
HouseServlet里的doGet方法:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 设置请求编码,解决中文乱码 req.setCharacterEncoding("UTF-8"); // 2. 从Service层拿房源列表,Service内部再调Dao HouseService service = new HouseServiceImpl(); List<House> houseList = service.queryAllAvailable(); // 3. 把数据放到request作用域,forward转发给JSP渲染 req.setAttribute("houseList", houseList); req.getRequestDispatcher("/house_list.jsp").forward(req, resp); }HouseDaoImpl里对应的方法:
@Override public List<House> queryAllAvailable() { List<House> list = new ArrayList<>(); String sql = "SELECT id, building_id, room_no, area, layout, " + "unit_price, total_price, status " + "FROM house WHERE status = 0"; try (Connection conn = JDBCUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { while (rs.next()) { House h = new House(); h.setId(rs.getInt("id")); h.setRoomNo(rs.getString("room_no")); h.setArea(rs.getBigDecimal("area")); h.setLayout(rs.getString("layout")); h.setUnitPrice(rs.getBigDecimal("unit_price")); h.setTotalPrice(rs.getBigDecimal("total_price")); list.add(h); } } catch (Exception e) { e.printStackTrace(); } return list; }代码逻辑没什么弯弯绕,但有几处细节是给答辩准备的。第一,req.setCharacterEncoding("UTF-8")必须放在第一次getParameter之前,否则POST提交的中文参数在Servlet里就已经是乱码了。第二,为什么用PreparedStatement而不是Statement?一定要能答出“预编译防止SQL注入,同时SQL结构固定、执行效率更高”,这是必问题。第三,查询用的是try-with-resources写法,Connection、PreparedStatement、ResultSet都能自动关闭,避免连接泄漏——期末项目里因为连接没关导致“运行一段时间后变卡”的情况非常多。
这段链路把它看懂了,整个房地产项目的其他功能都是同构的:新增房源就是INSERT,修改就是UPDATE,删除就是DELETE。核心不是SQL怎么写,而是“参数从哪里来、结果往哪里去”这两件事有没有想明白。
3. 数据库设计先行:房源、客户、成交三张核心表的建表SQL
3.1 房地产项目的实体关系与五张基础表
源码能跑是一回事,表设计能不能经受答辩是另一回事。房地产项目最核心的实体就三个:楼盘、房源、客户。外加一个成交记录用来把房源和客户关联起来,一张管理员表用来做登录。实体关系概括成一句话:一个楼盘下有多个房源,一个客户可以多次看房、最终对某套房源产生一条成交记录。所以表之间的外键集中在“房源归属于楼盘”和“成交记录关联了房源和客户”这两个点上。
五张基础表的角色要分清:admin管登录,building管楼盘基础信息(名称、地址、开发商、竣工日期),house管到具体房间(几栋几单元几号、面积、户型、单价、状态),customer管客户联系方式(姓名、电话、身份证),deal管成交(哪套房、哪个客户、成交价、成交时间、经办人)。deal里的house_id建议加唯一约束,因为一套房不可能被卖两次;customer_id不用加唯一约束,同一个客户买多套房是正常业务。这些约束细节写进建表SQL里,老师一眼就能看出你懂关系型数据库。
3.2 建表SQL:字段类型、外键与状态字段说明
下面这份init.sql是整个工程的地基,直接在Navicat或命令行里执行。表数量控制在五张,字段不贪多,每张表都能对应到页面上的一个表单。
CREATE DATABASE IF NOT EXISTS estate DEFAULT CHARACTER SET utf8mb4; USE estate; CREATE TABLE admin ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(30) NOT NULL UNIQUE, password VARCHAR(64) NOT NULL, real_name VARCHAR(30) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE building ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, address VARCHAR(100), developer VARCHAR(50), finish_date DATE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE house ( id INT PRIMARY KEY AUTO_INCREMENT, building_id INT NOT NULL, room_no VARCHAR(20) NOT NULL, floor INT, area DECIMAL(8,2), layout VARCHAR(20), unit_price DECIMAL(10,2), total_price DECIMAL(12,2), status TINYINT DEFAULT 0 COMMENT '0在售 1已预订 2已成交', CONSTRAINT fk_house_building FOREIGN KEY (building_id) REFERENCES building(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE customer ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(30) NOT NULL, phone VARCHAR(20), id_card VARCHAR(18), create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE deal ( id INT PRIMARY KEY AUTO_INCREMENT, house_id INT NOT NULL UNIQUE, customer_id INT NOT NULL, admin_id INT, deal_price DECIMAL(12,2), deal_date DATE, CONSTRAINT fk_deal_house FOREIGN KEY (house_id) REFERENCES house(id), CONSTRAINT fk_deal_customer FOREIGN KEY (customer_id) REFERENCES customer(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;几个参数说明值得记进笔记。字符集统一用utf8mb4,不要用utf8,因为utf8在MySQL里存不了emoji和部分生僻字,而utf8mb4是它的超集,在JDBC连接串里也要配套写上characterEncoding=utf8。金额字段用DECIMAL,绝不能用float或double,二进制浮点算金额会出现0.1+0.2不等于0.3的经典翻车现场,这是做房产系统的底线。status字段用TINYINT配COMMENT注释,比VARCHAR存“在售/已售”省空间,也比0/1裸数字更容易读懂。外键在这个项目里建议加上,虽然会带来一点插入性能损耗,但课设场景数据量小,外键能让表关系在Navicat里画出清晰的ER图,答辩时直接截图放PPT。
3.3 JDBC连接MySQL的工具类与db.properties配置
表建好之后,代码里怎么连?把数据库连接信息写死在Dao里是最容易被扣分的写法。常见做法是抽一个db.properties加一个JDBCUtil工具类,连接参数改一处,全项目生效。
db.properties如下:
jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/estate?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.username=root jdbc.password=123456JDBCUtil的核心代码:
public class JDBCUtil { private static String driver; private static String url; private static String username; private static String password; static { try { InputStream is = JDBCUtil.class.getClassLoader() .getResourceAsStream("db.properties"); Properties props = new Properties(); props.load(is); driver = props.getProperty("jdbc.driver"); url = props.getProperty("jdbc.url"); username = props.getProperty("jdbc.username"); password = props.getProperty("jdbc.password"); Class.forName(driver); } catch (Exception e) { e.printStackTrace(); } } public static Connection getConnection() throws Exception { return DriverManager.getConnection(url, username, password); } }这段代码有两个常被问到的点。Class.forName(driver)在MySQL 8.x的驱动下其实可以省略,因为JDBC 4.0之后驱动会通过META-INF/services自动注册,但保留它能让工程兼容MySQL 5.x旧驱动,答辩时也更稳妥。连接串里的serverTimezone=Asia/Shanghai必须写,MySQL 8.x不指定时区会直接报The server time zone value错误;useSSL=false是关闭SSL警告,本地开发不加密传输,减少无意义的握手开销。db.properties放在src根目录下,用类加载器读,这样打包进classes目录后依然能找到,比new FileInputStream("db.properties")这种依赖工作目录的写法可靠得多。
4. 用IDEA把JavaWeb项目跑起来:Tomcat配置与最小启动步骤
4.1 版本搭配:JDK、Tomcat、MySQL为什么不建议全用新版
搜“idea运行javaweb项目配置”的人,多半是卡在了版本搭配上。JavaWeb课设项目是出了名的对版本敏感,用错一个就可能启动失败。血泪经验总结成一句话:不要追求新版,要追求“教材和老师环境里验证过的组合”。最稳的一组是JDK 8 + Tomcat 9.0.x + MySQL 8.0 + mysql-connector-java 8.0.x。
最需要警惕的是Tomcat 10以上的版本。Tomcat 10把包名从javax.servlet改成了jakarta.servlet,而绝大多数期末大作业源码里写的还是import javax.servlet.http.HttpServlet。把老项目部署到Tomcat 10上,结果就是启动后访问任何Servlet都报ClassNotFoundException,这不是你代码的问题,是Tomcat版本和代码不兼容。遇到这种情况,与其改代码里所有import,不如直接换回Tomcat 9。另一组容易踩的坑是JDK 17配Tomcat 9,虽然能跑,但某些老项目用CGLIB反射时会报警告,没必要冒这个险。
MySQL方面,5.7和8.0都行,但驱动jar必须和MySQL版本对得上。MySQL 5.7用com.mysql.jdbc.Driver,MySQL 8.0必须用com.mysql.cj.jdbc.Driver,写成旧驱动会在Class.forName阶段直接失败。如果源码包里GBK编码,在IDEA里打开后中文全乱码,这种玄学问题基本都出在文件编码设置上,不涉及代码逻辑,后面会专门讲。
4.2 IDEA运行JavaWeb项目的配置步骤与部署细节
在IDEA里跑一个传统JavaWeb项目,和跑Spring Boot不一样,它需要经历“建项目→加Web框架→配Artifacts→配Tomcat→部署”五个步骤,缺一个都会出问题。
第一步,打开IDEA,选New Project,左侧选Java,SDK选1.8,不勾选任何模板,直接Next创建空项目。第二步,在项目上右键,选Add Framework Support,勾选Web Application,IDEA会自动生成web目录和web/WEB-INF/web.xml。第三步,把源码里的src下的java文件复制进来,把web里的JSP和静态资源覆盖过来,再把WEB-INF/lib里放上mysql-connector-java-8.0.x.jar。第四步,打开File → Project Structure → Artifacts,确认Web项目部署包的类型是Web Application: Exploded,如果右侧WEB-INF/lib里没有mysql驱动jar,手动点加号添加,这一步很多人漏掉。第五步,点Run → Edit Configurations,左侧加一个Tomcat Server → Local,Server标签页里选Tomcat 9的安装目录,Deployment标签页里点加号选Artifact,Application context填/estate。
# 在命令行中导入数据库脚本,注意先确认MySQL服务已启动 mysql -uroot -p123456 < db/init.sql # 启动Tomcat后,验证项目是否正常响应 curl -I http://localhost:8080/estate/login.jspApplication context的填写是个关键细节。如果填的是/,访问路径就是http://localhost:8080/login.jsp;如果填/estate,就必须用http://localhost:8080/estate/login.jsp访问。源码里所有JSP跳转、Servlet映射路径如果写的是/login.jsp这种以斜杠开头的绝对路径,那么context是/estate时就会被Tomcat拼成/estate/login.jsp,逻辑是通的;如果写的是相对路径login.jsp,在某些forward场景下会拼错。拿到源码后先看一遍JSP里的路径写法,再决定Application context填什么,能省半小时排查时间。
4.3 启动成功的验证与项目结构自查
Tomcat启动后,控制台出现Server startup in [xxx] milliseconds不代表项目就没问题,那只代表Tomcat起来了,你的Web应用可能已经在后台部署失败。这时候要盯着两处:一是启动日志里有没有SEVERE级别的报错,常见的是ClassNotFoundException或Deployment error;二是Deployment标签页里的Artifact是否处于Available状态。
项目成功部署后,用浏览器打开登录页,如果能正常显示、输入用户名密码能跳转到主页,就说明Servlet映射、JDBC连接、JSP渲染这三层都是通的。如果登录页能打开但登录后跳转失败,问题多半出在web.xml里的<url-pattern>路径配置。一个自查顺序:先看web.xml的Servlet映射和web目录结构是否一致,再看WEB-INF/lib里有没有jar,最后看数据库连没连上。这个排查顺序能覆盖九成启动问题,剩下的就是编码和路径细节,放进下一章集中讲。
5. 避坑:期末大作业最容易翻车的位置与排查方法
5.1 页面中文全部变成问号:编码不统一
现象:项目启动后,页面上的“房源”“客户”全是问号,或者控制台输出乱码。
原因:编码问题本质上是“三层不一致”。第一层是项目代码本身的编码,可能是GBK;第二层是IDEA文件读取编码,默认UTF-8;第三层是JSP页面里的pageEncoding声明。三层里只要两层不一致,中文必乱。很多从网上下载的源码是GBK编码的,IDEA用UTF-8打开后整个文件已经乱了,这时候改web.xml或Servlet都没用。
解决:先把IDEA的Settings → Editor → File Encodings里的Global Encoding、Project Encoding、Properties Files三个选项全部设为UTF-8,同时勾选Transparent native-to-ascii conversion。然后检查每个JSP头部有没有<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>,没有就补上。最后确认数据库端建表用的是utf8mb4,JDBC连接串带characterEncoding=utf8。这三处对齐之后,中文乱码基本绝迹。
5.2 启动后报ClassNotFoundException或页面404:Artifacts与lib目录
现象:Tomcat启动不报错,但访问项目路径时404;或者Logger里出现ClassNotFoundException: com.mysql.cj.jdbc.Driver。
原因:IDEA的Project Structure里,Artifacts的输出目录和源码实际路径不同步。最常见的情况是,你手动把jar包拖进了项目的WEB-INF/lib,但Artifacts那边没有重新构建,部署包里根本没有这个jar。另一个常见情况是,你把源码复制进项目后没有执行Build → Rebuild Project,class文件没生成,Servlet类找不到。
解决:进入File → Project Structure → Artifacts,找到对应Artifact,点开WEB-INF/lib,确认mysql驱动jar在列表里,不在就点+手动加。然后执行一次Build → Rebuild Project,重新启动Tomcat。如果依然找不到类,直接去看本地的Tomcat部署目录,webapps/你的项目名/WEB-INF/lib里有没有jar,部署包里没有,运行包里就不可能有。
5.3 数据库连接失败:驱动jar与连接串参数
现象:启动后点登录,报Access denied for user 'root'@'localhost',或者报Unknown database 'estate',又或者时区错误。
原因:这三条分别对应密码错误、数据库不存在、时区参数缺失。密码错误最直白,看db.properties的jdbc.password和本机MySQL root密码是否一致;Unknown database是没执行init.sql,光建了项目没建库;时区错误是MySQL 8.x的已知要求,连接串里必须带serverTimezone参数。
解决:用Navicat或命令行手动连一次MySQL,确认密码和库名没问题;db.properties里的jdbc.url末尾必须包含?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8。这三个参数缺一不可,少一个都可能报类如Communications link failure的迷惑错误。排查数据库问题,先脱离Java项目用客户端连一次数据库,能最大化缩小范围。
5.4 表单提交中文乱码:只设置GET不设置POST
现象:登录成功后进入房源页面,输入框里存进去的中文没问题,但新提交的房源名称在列表里显示为乱码。
原因:这是JavaWeb最经典的隐藏坑。GET请求的编码由Tomcat的server.xml里的URIEncoding控制,POST请求的编码则必须在Servlet里手动设置。很多源码只写了doGet里的编码,或者只在JSP里设置了pageEncoding,导致POST提交的中文到Servlet已经是ISO-8859-1解码后的乱码,回写库自然是错的。
解决:最省事的方案是在web.xml里注册一个编码过滤器,让所有请求在进入Servlet前强制统一为UTF-8。写一个EncodingFilter实现javax.servlet.Filter,核心代码就一句话:request.setCharacterEncoding("UTF-8")。在web.xml里配置<filter-mapping>时把<url-pattern>/*</url-pattern>放在最前面,保证它拦截所有请求。如果你不想写过滤器,就在每个Servlet的doPost第一行补上req.setCharacterEncoding("UTF-8"),但记住必须是第一行,放在getParameter之后就没用了。
5.5 JSP放在WEB-INF下访问404:路径规则没搞清
现象:直接在浏览器地址栏输入http://localhost:8080/estate/WEB-INF/xxx.jsp,结果是404。
原因:这不算bug,是Servlet规范的保护机制。WEB-INF目录下的资源对客户端是禁止直接访问的,只能通过Servletforward或include间接访问。很多下载的源码会把login.jsp放在web根目录,而把需要登录后访问的页面放在WEB-INF下,比如WEB-INF/house_list.jsp。如果跳转代码里写的是resp.sendRedirect("/house_list.jsp"),客户端请求的是根目录下的JSP,但文件实际在WEB-INF里,自然404。
解决:先看JSP里的跳转语句。需要转发到WEB-INF内页面时,必须用request.getRequestDispatcher("/WEB-INF/house_list.jsp").forward(req, resp),而不是sendRedirect。如果是登录页,就放在web根目录,不要放进WEB-INF。判断规则很简单:用户不登录也能看的页面放根目录,登录后才能看的页面放WEB-INF。这个设计本身就是加分项,答辩时主动说“我把受保护页面放在WEB-INF下防止直接访问”,老师会认同你有安全意识。
6. 期末JavaWeb答辩前必做的三个加分项:登录过滤、分页与README
6.1 写一个登录检查的AuthFilter
很多同学的源码里,登录功能做到了“能登录”,但没做到“必须登录”。这意味着浏览器直接访问house_list.jsp也能看到页面,功能上是通的,但安全性上不及格。加一个AuthFilter,在web.xml里配置拦截所有/jsp/*请求,判断session里有没有登录标记,没有就跳回登录页。这个过滤器代码不超过20行,但它一次性解决了三个答辩考点:Filter生命周期、Session机制、请求拦截路径配置。强烈建议加上。
6.2 分页查询用LIMIT实现
列表页一次性把全部房源查出来,课设能跑但很糙。给queryAll方法加两个参数pageNo和pageSize,SQL改为SELECT ... FROM house LIMIT ?, ?,再写一个统计总数的count方法。前端页码栏不必做得多精致,能翻页就行。这一步展示的是“数据量大时怎么设计查询”,答完这道题,几乎等于告诉老师你认真考虑过性能边界。
6.3 README和数据库脚本整理
把项目跑通之后,花半小时写一个README。内容包含:JDK/Tomcat/MySQL版本、导入IDEA的步骤、db.properties的修改位置、访问路径、初始账号密码。再确认db/init.sql里有没有测试数据——没有的话手动给building、house、customer各插几条,保证老师拿到源码一导入、一启动就能看到效果。
我自己的习惯是每次交付前,把源码压缩包解压到一个干净目录,从零开始按README走一遍,能走通才敢交。这个习惯救过我不少次,因为“在我电脑上是好的”这句话在答辩现场没有任何说服力。把环境建好、路径讲清、坑提前踩掉,剩下的交给临场发挥就好。希望帮到你。
本文还有配套的精品资源,点击获取