SSM+JSP宠物医院信息管理系统:从框架整合到毕业设计实战

发布时间:2026/10/31 19:23:37
SSM+JSP宠物医院信息管理系统:从框架整合到毕业设计实战 简介一份面向计算机、数学、电子信息等专业学生的Java毕业设计完整源码实现基于SSM框架与JSP技术的宠物医院信息管理系统功能涵盖患者信息管理、预约管理、药品库存与财务报表等模块并配套毕业论文和答辩PPT。压缩包共1347个文件整体约21.45MB内容以Java源码、JSP页面、JS脚本、CSS样式和数据库SQL为主同时包含用于前端展示的图片、图标及备份模板素材目录结构清晰便于按模块查阅。代码经严格调试可直接部署运行适合作为课程设计、期末大作业或毕设的参考资料也可作为二次开发的基础工程。已有103人浏览/学习对有钻研精神的学习者而言可通过阅读源码理解SSM整合逻辑、JSP交互方式与Mysql数据设计在此基础上扩展在线支付、健康咨询等更多功能。1. 宠物医院信息管理系统凭什么值得做SSMJSP的毕业设计定位“宠物医院信息管理系统”这类题目在课程设计和毕业设计里出现频率很高但真正从零把它搭起来的人会知道它把 SSM 框架里最容易出问题的几件事全占齐了Spring 容器怎么装配、SpringMVC 怎么分发请求、MyBatis 怎么和 MySQL 打交道以及 JSP 页面怎么把数据渲染出来。这套基于 java 的后端项目核心是解决宠物医院的日常业务流转前台给宠物建档挂号、医生写病历和处方、药房扣库存、收费处结算。选它做毕设或课设的人大多带着一个朴素诉求把课堂上零散的框架知识点拼成一个能演示、能写进论文的完整项目。源码只是起点真正值钱的是你对配置、表结构和业务的逻辑描述。2. 为什么是 SSMJSP技术选型与运行原理2.1 SSM 三件套的分工Spring 容器、SpringMVC 路由、MyBatis 持久化SSM 是 Spring SpringMVC MyBatis 的缩写在 java 课程设计里几乎成了标准套餐。Spring 负责管理对象也就是把 Service、Mapper 这些类交给容器创建和注入SpringMVC 负责接收浏览器请求按 URL 找到对应 Controller 方法MyBatis 负责把 Java 对象映射成 SQL 参数再结果集映射回对象。三个框架各管一段分层清晰这也是答辩时最好讲的一点。实际写代码时这一套的典型调用链是浏览器发起请求DispatcherServlet 根据 URL 找到 RequestMapping 标注的方法Controller 调 Service 接口Service 实现类通过 Autowired 注入 Mapper 接口Mapper XML 里写 SQL 查数据库结果逐层返回最后 Controller 把数据塞进 ModelAndView由 JSP 渲染成 HTML。这套方式对 java 基础的要求其实不高核心是理解“容器”和“约定”这两个词。Spring 容器接管了对象创建你不需要 new ServiceImplSpringMVC 约定了 URL 到方法的映射你只需要在方法上写注解MyBatis 约定了接口方法和 XML 里 SQL 的对应关系。这些约定如果之前没接触过开始时容易觉得是黑匣子但把配置打通后逻辑就顺了。这里顺手列一下最常用的几个注解基本每个模块都会用到Controller标注在类上声明这是一个 SpringMVC 控制器。RequestMapping写在类或方法上指定 URL 路径。Service标注业务层实现类交给 Spring 管理。Autowired按类型自动注入依赖不用写 setter。Repository标注数据访问层实现。Transactional声明事务挂号、收费这类多步操作必须加。这些是 SSM 里最常见的一组注解也是面试题里常出现的考点。记住一个原则注解只是配置的简写真正起作用的是 Spring 容器启动时扫描哪些包、加载哪些配置。2.2 JSP 在系统里的角色服务端渲染与页面交互标题里带 JSP说明这套系统不是前后端分离的而是 JSP 服务端渲染。JSP 页面本身就是一个 Java Web 资源运行在 Tomcat 里它可以直接写 HTML也可以用 JSTL 标签和 EL 表达式把 Controller 传来的数据展示出来。在宠物医院系统里JSP 主要干三件事一是渲染列表比如今日挂号列表、药品库存列表用c:forEach循环输出二是处理表单提交挂号表单、处方表单提交后由 Controller 接收三是在页面上展示操作结果比如挂号成功后刷新列表并显示“挂号成功”提示。对比现在流行的前后端分离用 JSP 的好处是少了一道联调成本Controller 里往 Model 塞一个对象JSP 里直接用${petName}就能取出来。坏处也很明显页面一旦复杂HTML 和 Java 代码混在一起很难维护。对课设/毕设来说这个缺点反而成了优点因为导师能直观看到数据是怎么从数据库走到页面的论文里也好截图说明。另外要注意JSP 文件本身不要直接放在 webapp 根目录建议放在/WEB-INF/views/下这样浏览器无法直接访问 JSP 源码只能通过 Controller 转发进入这也是一个安全防护点后面配置章节会写。2.3 需要准备的环境与依赖版本这个项目我用的是 Java 8 Tomcat 9 MySQL 5.7 Maven 3.6 这套组合比较稳。Java 11 也能跑但要注意部分老版本 JSP 标签库不兼容。Tomcat 这里是个大坑Tomcat 10 把javax.servlet换成了jakarta.servlet很多老项目直接部署会报错建议老老实实用 Tomcat 9。环境项推荐版本说明JDK1.8稳定兼容 SSM 全系Tomcat9.0.x依然是 javax 命名空间老项目不报错MySQL5.7 或 8.08.0 要改驱动类名和时区参数Maven3.6.x管理依赖打包 warIDEIDEA自带 Tomcat 集成调试方便依赖方面核心就是 spring-webmvc、mybatis、mybatis-spring、mysql-connector-java再加上 JSTL 和 Jackson。注意 mybatis 和 mybatis-spring 版本要配套否则启动时会出现 MapperScannerConfigurer 找不到类的错误。3. 先画功能再写代码模块划分与数据库表设计3.1 功能模块从挂号到收费的完整闭环写代码之前一定要先盘功能。宠物医院的业务场景比想象中复杂一只宠物可能反复就诊一个主人可能带多只宠物来一次就诊会产生病历、处方、收费多个关联数据。如果只按 CRUD 来设计后面写 SQL 会散架。我一般把系统分成六个模块用户登录与权限管理员、前台、医生三种角色登录后跳转不同首页。宠物主人管理录入主人姓名、电话、地址支持按手机号搜索。宠物档案管理一条主人记录下面挂多条宠物记录记录品种、性别、生日。挂号管理选择宠物和值班医生生成当天的挂号记录。病历与处方医生选中挂号记录填诊断意见开处方明细。药品与收费药品库存增减收费单汇总处方金额记录支付方式。这六个模块串起来就是一条完整业务链建档 → 挂号 → 接诊 → 开具处方 → 收费 → 药房发药减库存。代码里每个模块对应一个 Controller 和一组 Mapper 方法模块之间通过主键 ID 关联不写物理外键只在 SQL 里 JOIN。这种设计的好处是答辩时老师问“为什么这张表不用外键”时你可以回答外键约束会影响高并发插入性能系统在 Service 层做逻辑校验保证数据一致性。这个回答在课设里基本不会有人追问。3.2 主要数据表结构与字段设计数据库是这个系统的地基我建议建 8 张核心表表名用单数小写字段用下划线命名MyBatis 里开启驼峰映射就能自动对应。下面这个表结构可以直接拿去用字段已经够支撑整个系统。表名用途关键字段sys_user系统用户id, username, password, real_name, rolepet_owner宠物主人id, name, phone, address, id_cardpet宠物档案id, owner_id, name, species, breed, gender, birthdayregistration挂号记录id, pet_id, doctor_id, visit_date, statusmedical_record病历id, registration_id, diagnosis, advice, create_timeprescription处方主表id, record_id, total_amount, create_timeprescription_item处方明细id, prescription_id, medicine_id, quantity, unit_pricemedicine药品id, name, specification, inventory, unit_price, status字段类型上主键统一用 INT AUTO_INCREMENT金额用 DECIMAL(10,2)时间用 DATETIME布尔状态用 TINYINT比如挂号记录里 status 用 0 待诊、1 就诊中、2 已完成。密码字段要注意不能存明文MD5 虽然不够安全但课设里够用答辩时能说出“实际项目会用 bcrypt”就行。这里给出registration表的完整建表 SQL其他表可以参照同样风格写CREATE TABLE registration ( id INT NOT NULL AUTO_INCREMENT, pet_id INT NOT NULL COMMENT 宠物ID, doctor_id INT NOT NULL COMMENT 接诊医生ID对应sys_user, visit_date DATETIME NOT NULL COMMENT 就诊时间, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待诊 1就诊中 2已完成, remark VARCHAR(255) DEFAULT NULL COMMENT 备注, PRIMARY KEY (id), KEY idx_visit_date (visit_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT挂号记录表;这个表里我没建外键但加了一个普通索引idx_visit_date因为系统首页和挂号列表都要按日期查询这个索引在数据量上来后能明显加快查询速度。这个细节写进论文里的“数据库优化”部分非常加分。3.3 表关系与 E-R 要点画 E-R 图时按照实体关系把表分组pet_owner和pet是一对多一个主人可以带多只宠物pet和registration是一对多一只宠物可以有多次挂号registration和medical_record是一对一一次挂号对应一份病历设计上允许空病历临时来取药的情况medical_record和prescription是一对一prescription和prescription_item是一对多。PPT 和论文里画 E-R 图时不用把所有字段都画出来只需画每个实体的主键和对外的关联字段比如pet实体只画id、owner_id、name然后用连线把pet_owner和pet连起来标注“1:N”。这样答辩时一眼能看懂表关系不会被细节淹没。4. 从配置到跑通SSM 整合与核心代码实现4.1 配置文件怎么写web.xml、spring-mvc.xml、mybatis 与数据源SSM 项目最先要打通的是配置文件配置不对代码写得再好也启动不了。我按“入口 → MVC → 容器 → 持久层”的顺序来配置这一节照着敲就能跑起来。首先是web.xml它是整个应用的入口声明 DispatcherServlet 和 Spring 容器加载路径?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 加载 SpringMVC 配置 -- servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcher/servlet-name url-pattern//url-pattern /servlet-mapping !-- 加载 Spring 根容器包含 Service 和 Mapper -- listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener context-param param-namecontextConfigLocation/param-name param-valueclasspath:applicationContext.xml/param-value /context-param welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list /web-app注意servlet-mapping里的 URL 模式用/而不是/*。用/表示所有请求都进入 DispatcherServlet但 JSP 文件本身不经过它用/*会把 JSP 也拦住导致页面无法访问。这是源码里最常见的翻车点之一。然后是spring-mvc.xml负责扫描 Controller、开启注解驱动、配置视图解析器和静态资源context:component-scan base-packagecom.pet.controller/ mvc:annotation-driven/ !-- JSP 视图解析器 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean !-- 静态资源放行 -- mvc:resources mapping/static/** location/static//视图解析器的作用是Controller 里返回字符串registration/list时自动拼接成/WEB-INF/views/registration/list.jsp。JSP 放 WEB-INF 下是安全做法也能避免浏览器直接访问 JSP 源码。applicationContext.xml里装配数据源、MyBatis 和事务context:component-scan base-packagecom.pet.service,com.pet.dao/ context:property-placeholder locationclasspath:jdbc.properties/ bean iddataSource classorg.apache.commons.dbcp2.BasicDataSource property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:com/pet/mapper/*.xml/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.pet.dao/ /bean bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean tx:annotation-driven/这套配置把 Mapper 接口扫描和 XML 绑定在一起接口在com.pet.dao包XML 在classpath:com/pet/mapper/下两者同名同 namespace 才能绑定。事务管理器配好后Service 里加Transactional就能自动提交和回滚。4.2 实体类与 Mapper以挂号记录为例配置打通后先写实体类。实体类要尽量贴近表结构但也可以加几个非表字段用来接收联合查询结果。以Registration为例public class Registration { private Integer id; private Integer petId; private Integer doctorId; private Date visitDate; private Integer status; private String remark; // 关联查询冗余字段非表字段 private String petName; private String doctorName; // getter/setter 略 }实体类里petName和doctorName在表里不存在但在页面列表要展示所以通过查询 SQL 关联出来。MyBatis 开启驼峰映射后pet_id会自动对应petId。Mapper 接口和 XML 是 MyBatis 的核心。接口定义方法XML 写 SQL。挂号模块至少需要两个方法按条件查列表、插入新挂号public interface RegistrationMapper { ListRegistration selectByCondition(MapString, Object params); int insert(Registration registration); }对应的RegistrationMapper.xmlselect idselectByCondition parameterTypemap resultTypecom.pet.entity.Registration SELECT r.id, r.pet_id, r.doctor_id, r.visit_date, r.status, r.remark, p.name AS petName, u.real_name AS doctorName FROM registration r LEFT JOIN pet p ON r.pet_id p.id LEFT JOIN sys_user u ON r.doctor_id u.id where if testpetName ! null and petName ! AND p.name LIKE CONCAT(%, #{petName}, %) /if if testvisitDate ! null AND DATE(r.visit_date) #{visitDate} /if /where ORDER BY r.visit_date DESC, r.id DESC /select insert idinsert parameterTypecom.pet.entity.Registration INSERT INTO registration(pet_id, doctor_id, visit_date, status, remark) VALUES(#{petId}, #{doctorId}, #{visitDate}, #{status}, #{remark}) /insert这里有一个关键选择列表查询用了resultTypecom.pet.entity.Registration没有用resultMap。因为实体类的属性和表字段已经通过驼峰映射对齐关联字段用AS petNameAS doctorName也能直接映射到属性。如果遇到多表字段同名冲突才需要写resultMap做显式映射。参数方面动态 SQL 里petName是字符串visitDate是日期传 null 或空串时会被if过滤掉实现条件查询。#{petId}是预编译参数能防 SQL 注入这条在答辩时经常被问到一定要能说出来。4.3 Service 与 Controller把业务串起来Service 层负责写业务规则。挂号这个场景里一个宠物当天不能重复挂号这个校验放在 Service 层做而不是依赖数据库唯一约束Service public class RegistrationService { Autowired private RegistrationMapper registrationMapper; Transactional public void register(Registration registration) { // 校验同一宠物当天是否有待诊或就诊中的挂号 int count registrationMapper.countByPetAndDate( registration.getPetId(), registration.getVisitDate()); if (count 0) { throw new RuntimeException(该宠物当天已有挂号记录请勿重复挂号); } registration.setStatus(0); // 待诊 registrationMapper.insert(registration); } public ListRegistration queryToday(String petName, Date visitDate) { MapString, Object params new HashMap(); params.put(petName, petName); params.put(visitDate, visitDate); return registrationMapper.selectByCondition(params); } }Transactional在这里很关键如果后面业务扩展成“挂号同时扣一次挂号费”没有事务的话挂号插入成功但费用插入失败数据就不一致了。答辩时可以说这个注解实现了声明式事务Spring 自动管理提交回滚。Controller 是浏览器和 Service 之间的桥它负责接参数、调服务、返回视图Controller RequestMapping(/registration) public class RegistrationController { Autowired private RegistrationService registrationService; RequestMapping(/list) public String list(RequestParam(required false) String petName, Model model) { model.addAttribute(list, registrationService.queryToday(petName, null)); return registration/list; } RequestMapping(/add) public String add(Registration registration, RedirectAttributes attr) { try { registrationService.register(registration); attr.addFlashAttribute(msg, 挂号成功); } catch (RuntimeException e) { attr.addFlashAttribute(error, e.getMessage()); } return redirect:/registration/list; } }RedirectAttributes是个细节点短信提示的“挂号成功”在重定向后仍能带到列表页显示。如果用普通 Model重定向后数据就丢了这个问题很多新手会踩。addFlashAttribute的原理是把数据放在 session 里一次重定向后立刻取出清除。4.4 JSP 页面表单提交与列表展示后端接口写完最后用 JSP 把页面拼出来。挂号列表页的代码结构% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % % taglib prefixfmt urihttp://java.sun.com/jsp/jstl/fmt % html body h3今日挂号列表/h3 c:if test${not empty msg} p stylecolor:green${msg}/p /c:if c:if test${not empty error} p stylecolor:red${error}/p /c:if table border1 tr th单号/thth宠物/thth医生/thth时间/thth状态/th /tr c:forEach items${list} varr tr td${r.id}/td td${r.petName}/td td${r.doctorName}/td tdfmt:formatDate value${r.visitDate} patternyyyy-MM-dd HH:mm//td td c:choose c:when test${r.status 0}待诊/c:when c:when test${r.status 1}就诊中/c:when c:otherwise已完成/c:otherwise /c:choose /td /tr /c:forEach /table form action/registration/add methodpost 宠物IDinput namepetId typetext required/br/ 医生IDinput namedoctorId typetext required/br/ 时间input namevisitDate typedatetime-local required/br/ button typesubmit挂号/button /form /body /html这里把列表展示和新增表单放在一个页面操作路径短演示方便。fmt:formatDate用于格式化日期Controller 里传过来的visitDate是 java.util.Date直接输出会带毫秒格式化成yyyy-MM-dd HH:mm才符合医院场景。注意表单提交到/registration/add后Controller 返回的是redirect:/registration/list所以浏览器地址栏会变成列表页用户刷新不会出现“确认重新提交表单”的重复挂号问题这也算一个隐藏细节。5. 避坑手册SSMJSP 项目从启动到答辩的常见问题排查写这个系统最大的血泪经验是配置问题远多于业务问题。下面这 5 条是我在跑 SSM 项目时反复遇到、也帮别人排过的坑每一条都可以直接对照排查。1. Tomcat 10 部署后启动报 NoClassDefFoundError: javax/servlet/…现象日志里出现NoClassDefFoundError提示找不到javax.servlet.ServletException等类。 原因Tomcat 10 和更高版本已经把 Java EE 改名成 Jakarta EEjavax.*变成了jakarta.*老项目里所有 servlet 相关依赖都会失效。 解决最省事的方式是换 Tomcat 9并保持 pom 里 servlet-api 是javax.servlet坐标。如果你的 Tomcat 版本必须更高只能全局替换 import 和依赖工作量略大不建议课设阶段折腾。2. 数据库连接失败报 Access denied 或 Communications link failure现象启动时提示Access denied for user rootlocalhost或者连接一会儿后报Communications link failure。 原因前一种是密码/用户名写错后一种常见于 MySQL 8 认证插件不兼容、URL 没写时区。 解决MySQL 8 的驱动类要写com.mysql.cj.jdbc.DriverURL 加serverTimezoneAsia/ShanghaiuseSSLfalse。同时检查 MySQL 8 里root用户是否用了caching_sha2_password是的话用ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 密码;换回兼容插件。3. 页面中文全部显示为?数据库存进去也是??现象插入宠物姓名后列表页显示乱码数据库里直接是问号。 原因连接串没指定字符集或者建库时默认字符集不是 utf8mb4。 解决JDBC URL 里加characterEncodingutf8建库语句用CREATE DATABASE pet_hospital DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;。代码里 JSP 顶部也要有contentTypetext/html;charsetUTF-8前端表单提交才会用 UTF-8 编码。4. 访问页面 404但 Controller 明明写了路径现象请求/registration/list返回 404控制台也没有打印对应日志。 原因换汤不换药的两个位置出问题一是web.xml用了/*拦截了 JSP二是视图解析器前缀/后缀配错比如 JSP 实际在views/registration/下但解析器拼成了/WEB-INF/views/registration/list.jsp路径就差一个目录。 解决先看控制台有没有请求日志有日志说明 Controller 进来了问题在视图解析器没日志说明 URL 映射不对检查web.xml里是否把 DispatcherServlet 映射成了/以及RequestMapping值是否多写了斜杠。5. 启动时报 Invalid bound statement (not found): com.pet.dao.RegistrationMapper现象Spring 启动成功但一调用 Mapper 方法就报绑定错误。 原因applicationContext.xml里mapperLocations路径写错XML 没被加载或者 XML 文件的 namespace 不是接口全限定名。 解决确认mapperLocations写成classpath:com/pet/mapper/*.xml且 XML 的mapper namespacecom.pet.dao.RegistrationMapper和接口路径完全一致。这一步写错MyBatis 就会认为接口没有实现。6. 论文和 PPT 怎么配得上这套源码从 ER 图到答辩演示6.1 论文目录先对齐代码模块标题里带了毕业论文和 PPT说明交付物不只是源码。论文目录建议按“绪论 → 需求分析 → 系统设计 → 系统实现 → 系统测试”五章写每一章都和代码模块对应。需求分析里写六个功能模块的角色和流程系统设计里放 8 张表的表结构清单和 ER 图系统实现里按登录、挂号、病历、药品、收费五个小节配界面截图和核心代码片段测试部分写登录校验、重复挂号拦截、药品库存扣减三个典型用例。6.2 PPT 演示顺序按业务链路走别按模块走PPT 不用把每个页面都放截图而是按一条完整业务线演示先放登录页截图说明三种角色权限然后放“新建主人档案 → 新建宠物档案 → 挂号”这三张截图串成“建档挂号”链路再接医生看诊、开处方最后放收费页面强调药品库存从 100 减到 99 的前后对比截图。这条链路讲完业务闭环就立住了。答辩提问环节容易问“为什么用 SSM 而不用 Spring Boot”可以答SSM 配置显式、能够体现 Spring 容器和 MyBatis 的底层原理毕业设计选它能更完整地展现 java 基础。这套系统我前后带过几个学弟跑通印象最深的一次是数据库没建库直接启动日志报错报了一屏最后发现只是 jdbc.url 里少了数据库名。项目本身不难难的是一步一步按配置走、按表结构建库很多翻车都是跳过某一步造成的。我现在做这类系统一定先建库再写配置先跑通一个最小查询再扩展业务模块这样出了问题能快速定位。你拿到源码后也按这个顺序来能省下大量排查时间。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询