ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SSM框架从零搭建图书管理系统:Spring+SpringMVC+MyBatis整合实战

2026/8/31 13:51:11 拓冰建站 浏览量
SSM框架从零搭建图书管理系统:Spring+SpringMVC+MyBatis整合实战 简介这是一套面向Java Web初学者与课程设计者的SSM框架实战项目资源完整实现图书借阅全流程管理适用于高校Java开发实训、毕业设计参考及Spring生态入门学习。资源包含基于SpringSpringMVCMyBatis构建的后台系统、LayUI前端界面及MySQL数据库脚本涵盖借阅/还书、图书/读者/类型/公告/管理员六大核心模块并集成统计分析功能管理员默认账号为admin/123456。压缩包共919个文件44.35MB含40个Java业务类、75个JSP页面、123个JS交互脚本、45个CSS样式文件及39个XML配置文件另有Druid连接池、Tomcat部署WAR包及SQL建库脚本目录结构清晰Controller/Service/DAO分层明确便于理解SSM整合逻辑与MVC职责划分。目前已有840人学习下载可直接导入IDEA运行快速掌握企业级图书管理系统开发全流程。 图书管理系统是我接过的课程设计里最经典的题目没有之一。这次用SSMSpring SpringMVC MyBatis把这套系统从零到一搭起来源码和数据库我都整理好了。如果你是准备做JavaWeb课程设计、毕业设计或者想搞明白SSM框架到底怎么整合这篇文章值得你花二十分钟看完。整套系统麻雀虽小五脏俱全管理员登录、图书信息管理、借书还书、分页查询、条件检索、数据库初始化脚本全部包含。项目底层用了Spring做对象的统一管理SpringMVC负责请求转发和数据绑定MyBatis负责和MySQL打交道这是很多Java后端岗位面试都会问到的经典组合。文章会拆解设计思路、数据库建表、核心配置、常见报错最后直接告诉你源码和数据库怎么跑起来。1. 这套图书管理系统的整体设计与技术选型1.1 为什么选SSM而不是Spring Boot很多人会问现在新项目都上Spring Boot了为什么还折腾SSM我的看法是课程设计和毕业设计阶段SSM依然值得做。SSM把“配置”这件事摊开放在你面前你能看到Spring容器怎么装配、SpringMVC怎么拦截请求、MyBatis怎么把接口映射成SQL踩过一遍配置的坑再回头用SpringBoot你会知道它到底帮你省了什么。用一个类比来解释这三个组件Spring是总调度室所有对象的创建和依赖关系都由它管理SpringMVC是前台接待用户发来的请求先到它这里再由它分发给对应的ControllerMyBatis是仓库管理员负责把数据库里的数据搬进项目也把内存里的对象写回数据库。三者各管一段职责清晰。我选择SSM的另一个原因是它对Tomcat的部署方式非常传统能练到“手动打war包、手动部署Web容器”这些基础操作。现在很多同学用完Spring Boot内嵌Tomcat反而不知道应用是怎么部署到外部服务器上的这在实际工作中其实很容易吃亏。1.2 系统功能模块拆解这套图书管理系统的业务需求并不复杂核心就三类角色操作管理员、图书、借还记录。但功能模块划分得越清楚后面写代码越不容易乱。我按“先主数据、后业务流水”的方式拆分用户登录模块管理员和普通读者都走同一张用户表登录成功后把用户信息放进Session配一个拦截器统一校验未登录访问。图书管理模块图书的增删改查列表页支持分页支持按书名、作者、分类做模糊查询。读者管理模块维护读者信息包括姓名、联系方式、借书状态管理员可以新增、禁用读者账号。借阅管理模块管理员为读者办理借书生成借阅记录同时扣减图书库存还书时更新归还时间恢复库存。基础统计模块首页展示图书总量、读者总量、未归还记录数等统计值方便管理员一眼掌握核心数据。这里需要注意我把“借书”和“还书”设计成两条独立的Service方法而不是在一个方法里用状态字段硬切。原因是借书要校验库存、要创建借阅记录、要扣库存还书要校验是否有未还记录、要更新返回时间、要加库存。两个操作的事务边界不同混在一起会非常难维护。1.3 目录结构与分层设计源码的包结构如果不提前规划项目一变大就回天乏术。我采用标准的Maven Web工程分层包名统一以com.example.library开头library-ssm ├── pom.xml ├── src/main/java/com/example/library │ ├── controller # SpringMVC控制器 │ ├── service # 业务接口 │ │ └── impl # 业务实现 │ ├── mapper # MyBatis Mapper接口 │ ├── entity # 实体类 │ ├── interceptor # 登录拦截器 │ └── common # 公共类、分页结果封装 ├── src/main/resources │ ├── mapper # MyBatis XML文件 │ ├── spring # Spring主配置、SpringMVC配置 │ └── jdbc.properties # 数据库连接配置 └── src/main/webapp ├── static # 静态资源 └── WEB-INF/views # JSP页面Controller只负责接收参数、调用Service、封装结果返回页面Service只处理业务逻辑不直接写SQLMapper接口只做数据库操作声明SQL写在XML里entity就是数据库表结构对应的JavaBean。这套分层的好处是后续想加一个“图书导出”功能只需要在Controller和Service里各加一段代码不需要动数据库访问层。2. 数据库设计与初始化2.1 核心表结构设计数据库是整个系统的地基设计阶段多花一小时后面少加三天班。我在这里只保留了三张核心表用户表、图书表、借阅记录表。三张表之间的关系很清晰一个读者可以借多本图书一本图书可以被多个读者借阅借阅记录表就是它们之间的关联表。先看用户表我把它命名为t_user用来存放管理员和读者两种账号CREATE TABLE t_user ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(64) NOT NULL COMMENT 登录名, password varchar(128) NOT NULL COMMENT 登录密码MD5加密后保存, real_name varchar(64) DEFAULT NULL COMMENT 真实姓名, role int(1) DEFAULT 0 COMMENT 角色0-管理员 1-读者, status int(1) DEFAULT 1 COMMENT 状态1-正常 0-禁用, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;图书表t_book我放了几个关键业务字段数量和价格都用明确语义的命名避免使用count、number这种没有业务含义的词CREATE TABLE t_book ( id int(11) NOT NULL AUTO_INCREMENT, isbn varchar(32) DEFAULT NULL COMMENT ISBN编号, book_name varchar(128) NOT NULL COMMENT 书名, author varchar(64) DEFAULT NULL COMMENT 作者, publisher varchar(128) DEFAULT NULL COMMENT 出版社, price decimal(10,2) DEFAULT 0.00 COMMENT 定价, category varchar(32) DEFAULT NULL COMMENT 分类如Java、文学, stock int(11) DEFAULT 0 COMMENT 库存数量, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_book_name (book_name) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;借阅记录表t_borrow是关键业务流水必须记录借书人、图书、时间、状态CREATE TABLE t_borrow ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) NOT NULL COMMENT 读者ID, book_id int(11) NOT NULL COMMENT 图书ID, borrow_time datetime DEFAULT NULL, return_time datetime DEFAULT NULL, status int(1) DEFAULT 0 COMMENT 状态0-借出中 1-已归还, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_book_id (book_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这里有个设计细节日期时间字段我统一用datetime不用timestamp。原因很简单MySQL的timestamp有2038年问题虽然现在的数据量远远到不了那一刻但课程设计场景下datetime更稳定、最好理解排序和范围查询也都支持得很好。2.2 初始化数据与SQL脚本导入数据库脚本我建议按顺序执行先建库再建表最后插入测试数据。测试数据不要太多但一定要够演示分页功能所以我往图书表里插了20本左右不同类型的书用户表里插了管理员和读者账号。初始化SQL文件保存为library.sql里面包含完整的建库建表语句和INSERT语句。导入方法有两种命令行方式mysql -uroot -p source /你的路径/library.sql;Navicat方式更快新建连接后右键连接选择“运行SQL文件”选择library.sql直接执行。执行完成后在数据库中应能看到t_user、t_book、t_borrow三张表和数据。我建议在正式导数据之前先用SELECT * FROM t_user;确认一下表是否创建成功。宁可多执行一次验证也不要等到项目启动时报错再回头查数据库。2.3 数据库连接配置的坑SSM项目的数据库连接配置集中在jdbc.properties文件里我会在部署环节详细说但这里先提醒最关键的三个参数jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/library?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456第一useSSLfalse一定要加。MySQL 5.7及以上版本如果不显式关闭SSL控制台会频繁打警告甚至导致连接超时。第二characterEncodingutf8必须加否则插入中文数据后页面会显示“??”或者乱码。第三如果本机MySQL是8.x驱动类要改成com.mysql.cj.jdbc.Driver同时url里还要加时区参数serverTimezoneAsia/Shanghai这是我从MySQL5切到MySQL8时踩过的最实在的坑。3. 从零搭建SSM框架的核心配置3.1 Maven依赖与版本选择SSM整合的依赖版本不能乱配尤其是Spring、MyBatis、MyBatis-Spring三者之间版本不兼容会直接导致程序启动失败。下面是我验证过的一套版本组合依赖版本spring-context / spring-webmvc / spring-jdbc5.3.23mybatis3.5.13mybatis-spring2.1.2mysql-connector-java5.1.49pagehelper5.3.3jackson-databind2.13.4c3p00.9.5.5pom.xml里的核心依赖这样写dependencies dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.3.23/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.23/version /dependency dependency groupIdorg.springframework/groupId artifactIdspring-jdbc/artifactId version5.3.23/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.13/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.1.2/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper/artifactId version5.3.3/version /dependency dependency groupIdcom.fasterxml.jackson.core/groupId artifactIdjackson-databind/artifactId version2.13.4/version /dependency dependency groupIdc3p0/groupId artifactIdc3p0/artifactId version0.9.5.5/version /dependency /dependencies还要注意Maven默认编译级别可能跟JDK不匹配建议在pom里显式指定JDK版本properties maven.compiler.source1.8/maven.compiler.source maven.compiler.target1.8/maven.compiler.target /properties否则你用IDEA的JDK17跑项目会遇到“无效的目标发行版”之类的编译错误。3.2 Spring/SpringMVC/MyBatis整合配置SSM整合的关键在于Spring负责装配Service、Mapper和事务SpringMVC负责Controller层两者虽然都在同一个web容器里但配置文件要分开。先看applicationContext.xml这是Spring的主配置context:property-placeholder locationclasspath:jdbc.properties/ bean iddataSource classcom.mchange.v2.c3p0.ComboPooledDataSource property namedriverClass value${jdbc.driver}/ property namejdbcUrl value${jdbc.url}/ property nameuser value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property namemapperLocations valueclasspath:mapper/*.xml/ property nametypeAliasesPackage valuecom.example.library.entity/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.example.library.mapper/ /bean tx:annotation-driven transaction-managertransactionManager/ bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean再写spring-mvc.xml只扫描Controller不扫描Service和Mapper避免同一个Bean被创建两次mvc:annotation-driven/ context:component-scan base-packagecom.example.library.controller/ bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean mvc:resources mapping/static/** location/static//最后在web.xml里配置Spring的上下文参数、SpringMVC的DispatcherServlet、以及编码过滤器context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/applicationContext.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping servlet servlet-namedispatcher/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/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这里容易踩的坑是url-pattern。如果你写成*.do那所有不带.do的请求都会404写成/时静态资源必须靠mvc:resources放行否则页面样式全部丢失。3.3 登录模块与拦截器实现登录模块是系统的入口我把它放在Controller最前面实现主要代码流程是Controller public class UserController { Autowired private UserService userService; PostMapping(/login) public String login(String username, String password, HttpSession session, Model model) { User user userService.login(username, MD5Utils.md5(password)); if (user null) { model.addAttribute(msg, 用户名或密码错误); return login; } session.setAttribute(loginUser, user); return redirect:/book/list; } RequestMapping(/logout) public String logout(HttpSession session) { session.invalidate(); return redirect:/login.jsp; } }我这里对密码做了MD5加密后再去数据库比对这是最基础的防护至少能让明文密码不会直接存在数据库里。真正的生产环境肯定要用BCrypt加盐但课程设计阶段用MD5固定盐足够演示代码也简单。拦截器我单独建了一个LoginInterceptor类继承HandlerInterceptor重写preHandle方法public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); if (session.getAttribute(loginUser) ! null) { return true; } response.sendRedirect(request.getContextPath() /login.jsp); return false; } }然后在SpringMVC配置里注册拦截器放行登录页面和静态资源mvc:interceptors mvc:interceptor mvc:mapping path/**/ mvc:exclude-mapping path/login/ mvc:exclude-mapping path/login.jsp/ mvc:exclude-mapping path/static/**/ /mvc:interceptor /mvc:interceptors3.4 图书借阅的事务管理借书操作涉及两步数据库操作必须放在一个事务里先插入借阅记录再更新图书库存。如果中途某一步失败数据库会处于“记录已插入但库存没扣”的错误状态。我直接在Service实现类上加了注解Service public class BorrowServiceImpl implements BorrowService { Autowired private BorrowMapper borrowMapper; Autowired private BookMapper bookMapper; Transactional(rollbackFor Exception.class) Override public void borrowBook(Long userId, Long bookId) { Book book bookMapper.findById(bookId); if (book null || book.getStock() 0) { throw new RuntimeException(图书不存在或库存不足); } Borrow borrow new Borrow(); borrow.setUserId(userId); borrow.setBookId(bookId); borrow.setBorrowTime(new Date()); borrow.setStatus(0); borrowMapper.insert(borrow); bookMapper.decreaseStock(bookId); } }这里Transactional(rollbackFor Exception.class)一定不能简写成Transactional。默认情况下Spring事务只在抛出运行时异常时才回滚如果代码抛的是SQLException这类受检异常事务不会回滚那数据就脏了。另一个注意点事务要放在Service层不要放到Controller。Controller离业务太近容易把事务范围扩大导致长事务占用数据库连接并发高的时候很容易拖垮连接池。4. 实操过程图书CRUD与分页查询的实现细节4.1 图书管理页面的整体流程图书管理是整个系统的核心功能我以“图书列表页”为例走一遍完整的请求流程浏览器访问/book/list?pageNum1keywordJava。DispatcherServlet根据映射找到BookController。Controller调用BookService的pageQuery方法。Service先调PageHelper.startPage(pageNum, pageSize)再调BookMapper.selectList(keyword)。MyBatis执行XML里的SQL返回PageBook。Controller把PageInfo封装进Model转发到book/list.jsp。JSP使用JSTL和EL遍历数据渲染表格和分页栏。业务流程里最值得学习的是“分页查询”和“条件查询”如何组合我在下文单独展开。4.2 分页查询与条件检索分页我用了PageHelper这个插件好处是不用手写LIMIT和总记录数统计。用法很简单public PageInfoBook pageQuery(int pageNum, int pageSize, String keyword) { PageHelper.startPage(pageNum, pageSize); ListBook books bookMapper.selectList(keyword); return new PageInfo(books); }但这里有个非常隐蔽的坑PageHelper.startPage只对紧跟着它的第一条SQL生效。如果你在调用Mapper之前先查了一次用户、或者遍历了一个集合分页就会失效。所以我在Controller里只是拿到参数直接传给Service在Service里必须保证startPage和selectList之间不要夹任何其他数据库操作。对应的Mapper XMLselect idselectList resultTypecom.example.library.entity.Book SELECT id, isbn, book_name, author, publisher, price, category, stock, create_time FROM t_book where if testkeyword ! null and keyword ! AND (book_name LIKE CONCAT(%, #{keyword}, %) OR author LIKE CONCAT(%, #{keyword}, %) OR category LIKE CONCAT(%, #{keyword}, %)) /if /where ORDER BY id DESC /select这里条件拼接用了where和ifMyBatis会自动去掉多余的AND避免写出“WHERE 11”这种临时方案SQL看着更整洁。模糊查询用CONCAT(%, #{keyword}, %)绝对不能直接写LIKE %${keyword}%因为${}是字符串拼接存在SQL注入风险。4.3 图书新增与编辑的表单参数绑定新增图书的表单是POST提交表单字段名和Book实体属性名相同SpringMVC会自动绑定form action${pageContext.request.contextPath}/book/add methodpost input typetext nameisbn input typetext namebookName input typetext nameauthor input typetext namepublisher input typenumber nameprice step0.01 input typetext namecategory input typenumber namestock button typesubmit新增/button /formController的写法PostMapping(/add) public String add(Book book) { bookMapper.insert(book); return redirect:/book/list; }编辑和新增复用一个JSP页面是最常见的做法我用一个bookEdit.jsp页面上加载时判断book.id是否为空为空就显示“新增”不为空就显示“编辑”提交地址动态切换为/book/update。这里要注意修改操作必须携带id否则会更新到一条不存在的记录甚至报空指针。还有一个细节删除操作我建议用POST不要用GET。因为GET请求被搜索引擎、预加载工具访问后如果链接里带删除ID可能误删数据。虽然课程设计没有这么严格但养成用POST处理写操作的习惯是好的。4.4 JSP前端的几个细节处理JSP页面虽然传统但有一些特别影响体验的细节。第一页面顶部要用% page contentTypetext/html;charsetUTF-8 languagejava %并且最好在每个页面引入JSTL标签库否则EL表达式$ {}在Tomcat低版本下可能不生效。第二项目根路径要动态获取。在JSP里尽量不要写死/library/xxx否则部署时改了上下文路径所有链接都会404。我是在页面顶部写一行c:set varctx value${pageContext.request.contextPath}/之后所有链接都写成${ctx}/book/list。第三列表页要处理“没有数据”的情况。我用c:forEach遍历数据配合c:if test${empty pageInfo.list}显示“暂无数据”的提示行比直接显示空表格强很多。分页栏我做的比较简单上一页、下一页、总数、当前页/总页数。用PageInfo自带的属性当前第 ${pageInfo.pageNum} 页 / 共 ${pageInfo.pages} 页 / 共 ${pageInfo.total} 条 a href${ctx}/book/list?pageNum${pageInfo.prePage}keyword${keyword}上一页/a a href${ctx}/book/list?pageNum${pageInfo.nextPage}keyword${keyword}下一页/a这里有个容易遇到的问题翻页时如果带了keyword分页链接里必须把它带到下一页否则用户搜完“Java”后翻到第二页条件就丢了看到的会变成全部图书。5. 常见问题与排查技巧实录5.1 启动和部署问题SSM项目跑不起来80%的问题集中在Maven依赖、Tomcat部署、Spring扫描三个层面。我把自己踩过和帮别人排查过的典型问题整理成了速查表报错或现象最常见原因处理建议ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet依赖未下载或未打包进WAR检查pom中spring-webmvc是否引入IDEA中执行mvn clean package确认lib目录有jar包Failed to configure a DataSourcejdbc.properties没被加载确认applicationContext.xml里有context:property-placeholder且文件路径正确java.lang.NoClassDefFoundError: org/springframework/jdbc/datasource/...缺少spring-jdbc依赖加上spring-jdbc依赖后重新导入访问项目显示404且控制台无日志项目没有正确部署到Tomcat检查IDEA的Artifacts和Deployment配置确认application context设置为/libraryIDEA提示“源服务器找不到目标资源”部署时没选“war exploded”最好用war exploded修改JSP不用重新打包我建议所有Maven依赖拉完之后先执行一次mvn clean package看打包是否成功。如果打包成功项目基础配置基本没问题如果打包时就有红色报错优先看编译错误别急着启动Tomcat。5.2 数据库连接与中文乱码问题数据库连接问题通常分两类一类是连不上一类是连上了但数据错乱。连不上的典型报错是Access denied for user rootlocalhost或者Communications link failure。前者是账号密码错后者一般是端口不对、MySQL没启动、或者url写错。最笨但有效的方法先用数据库客户端连一次MySQL能连上再让项目连。如果数据库客户端能连项目连不上重点检查jdbc.properties里的driverClass和jdbcUrl。MySQL5.7和8.x的驱动类不一样前面已经提过。这个坑我印象很深有一次项目换到MySQL8漏加了serverTimezone启动报了一长串时区错误最后在url后面拼上serverTimezoneAsia/Shanghai才解决。中文乱码分三个层面解决数据库层面建表时指定DEFAULT CHARSETutf8mb4数据导入时确认连接字符集是utf8。连接层面jdbc.url中加上characterEncodingutf8。Web层面web.xml配置CharacterEncodingFilterJSP页面contentTypetext/html;charsetUTF-8。这三个地方缺一不可。我见过有人只改了JSP页面显示正常但插入数据库后还是乱码就是因为漏了jdbc.url的编码参数。5.3 框架配置与代码问题速查除了启动问题运行时最烦人的几个报错我也单独列出来报错原因处理Invalid bound statement (not found)Mapper接口没有找到对应的XML或XML的namespace不对检查mapperLocations是否指向mapper目录XML里namespace是否等于接口全限定名No qualifying bean of type BookServiceService实现类没加Service或没被扫描检查context:component-scan扫描的包是否包含service包Could not autowire. No beans of type BookMapperMapper接口没有扫描到检查MapperScannerConfigurer的basePackage是否正确PageHelper分页无效插件没注册或startPage后不是紧接查询语句在SqlSessionFactoryBean里配置插件把PageHelper.startPage放到Mapper调用之前一行HTTP 405 Request method POST not supported控制器只写了GetMapping但表单用了POST提交把方法改成对应的RequestMethodproperty stock not found on objectJSP属性名和实体属性名不一致检查实体类有没有getStock()方法或者是否加了Lombok注解如果用的是IDEA我建议启动时把日志级别调到DEBUG至少先看到MappingThe request URL这样的信息能快速判断请求是否进到了Controller。6. 源码导入与数据库初始化实战步骤6.1 源码导入IDEA的完整流程拿到源码后不要急着双击启动。我先说一套稳妥的导入流程适用于最新的IDEA版本打开IDEA选择File - New - Project from Existing Sources选中源码根目录选择Maven项目。等待右下角Maven依赖下载。这一步如果长时间卡住先检查自己本地的Maven仓库settings.xml是否配置了阿里云镜像没有的话大概率下载得很慢。依赖下载完成后先不要运行打开Project Structure确认Project SDK选择的是本机JDK8或更高版本Language level设置为8。在Project Structure - Modules里把项目标记为Web项目选中模块点“”添加Web配置Web Resource Directory指向src/main/webapp。我遇到过的典型问题是项目导入后没有Maven“刷新”按钮或者代码全部爆红但报错信息又不明确。这种时候最简单有效的办法是右键pom.xml - Maven - Reload project等左下角进度条走完大部分爆红都会消失。6.2 初始化数据库并修改配置文件数据库初始化前面提过用Navicat或命令行执行library.sql即可。执行后重点检查三张表是否建好、管理员账号是否存在。接着修改src/main/resources/jdbc.properties把三样改成你本机的实际值jdbc.username、jdbc.password、jdbc.url。如果你的MySQL在本地端口3306没变只有用户名密码需要改。修改完成后我建议先写一个简单的测试方法用Spring的JdbcTemplate或者直接启动项目到登录页验证数据库连接没问题。千万不要等到运行到借书功能才发现数据库没连上到那时候排查成本就高很多了。6.3 部署到Tomcat并验证功能在IDEA里配置Tomcat非常简单但有一个选项要特别注意。选择Run - Edit Configurations点击“”选Tomcat Server - Local。在Deployment标签页点击“”选择Artifact...然后选library-ssm:war explodedApplication context我填的是/library。Tomcat端口设置成 8080与MySQL不相干两个服务可以同时运行。启动之前确认Tomcat自身没有报端口占用如果8080被占用可以在Server标签页改成8081。启动成功后浏览器访问http://localhost:8080/library/login.jsp输入源码里初始化的管理员账号应该能进入系统后台看到首页统计数字、图书列表、分页按钮。到这一步整套基于SSM的图书管理系统就真正跑起来了。我个人建议如果你是第一次跑SSM项目先不要急着改功能按原样跑通一遍再在图书管理模块加一个“导出Excel”之类的小功能练手。这套源码里的配置都可以直接复用。我在实际部署中踩得最多的还是Tomcat应用上下文路径和数据库时区两个问题把这两点记住基本就顺了。本文还有配套的精品资源点击获取