尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

SSM图书角系统从环境配置到部署排错全指南

SSM图书角系统从环境配置到部署排错全指南 简介面向计算机专业学生的校园图书角管理系统毕业设计项目基于SSMSpringSpringMVCMyBatisJSPHTML开发前后端代码完整代码注释详细新手也能快速看懂。包内共1293个文件其中包含128个Java类、113个JSP页面、364个JavaScript脚本、146个CSS样式表以及PNG/JPG图片素材、MySQL数据库脚本和部署说明压缩包仅49.38MB。内容预览中可见ElementUI、Bootstrap等前端组件及多种备份文件便于对照学习与排错系统涵盖图书信息管理、借阅管理、分类管理等常用模块功能完善、界面美观部署时建议配合IDEA、Navicat等工具。已有59人浏览学习适合作为毕业设计、课程设计或SSM框架练手项目。按部署说明导入项目并配置数据库后即可运行体验项目采用分层架构代码结构清晰经严格调试可运行能帮助读者完整掌握从环境搭建到系统上线的全过程具备较高的实用和参考价值。1. 别等答辩前一晚才看这份 SSM 图书角系统拆解每年毕业季都有人问同一个问题基于 SSM 的图书角管理系统到底怎么跑起来我见过太多同学把压缩包解压后连数据库都导不进去卡在 Tomcat 端口、MyBatis 映射路径这类最基础的地方最后只能抱着笔记本去机房求老师帮忙。这类 SSMJSPHTML 的毕业设计项目本质上是一条从页面到数据库的完整请求链JSP 负责展示和交互SpringMVC 负责路由和传参Service 层处理业务MyBatis 和 MySQL 负责持久化。项目结构并不复杂真正让人头疼的是环境匹配、配置顺序和隐式约定。这篇博文就顺着这个管理系统的骨架把环境搭建、数据库设计、核心配置到部署排错整条链路讲透。适合手里有源码但跑不起来的人也适合想自己动手把系统重写一遍的初学者。2. 跑通 SSM 项目前先校准环境JDK、Maven、Tomcat 与 MySQL 的版本匹配2.1 SSM 框架耦合度低但运行环境对版本极其敏感SSM 是 Spring SpringMVC MyBatis 的组合。Spring 负责对象管理和事务SpringMVC 负责 HTTP 层的请求分发MyBatis 负责 SQL 与 Java 对象的映射。这套组合的好处是分层清晰、职责单一坏处是三个框架各自迭代版本交叉后容易出现莫名其妙的兼容问题。很多毕业设计源码传了不知道多少手pom.xml 里的依赖版本可能还是 2018 年前后的写法而你本地装的是 JDK 17Tomcat 10那基本是跑不动的。从我接触过的项目经验来看这类校园管理系统最稳妥的组合是 JDK 1.8 Maven 3.6.3 Tomcat 8.5 MySQL 5.7。这个组合经过了大量毕业设计项目的验证网上能找到的解决方案也最多。如果你机器上已经装了更高版本的 JDK可以不用卸载在 IDEA 里单独配置 Project SDK 为 1.8 即可具体路径是 File → Project Structure → Project → SDK下拉选择已安装的 1.8。如果没有需要去 Oracle 官网下载 JDK 8u 版本安装或者用较为轻量的 OpenJDK 8。注意环境变量 JAVA_HOME 要指向这个 JDK 8 的安装目录不然 Maven 和 Tomcat 可能拿不到正确的 Java 环境。2.2 导入源码前的三个关键检查点拿到压缩包后不要急着打开 IDEA先做三件事检查 pom.xml 里的依赖版本、检查 web.xml 的 Servlet 版本声明、检查数据库脚本的编码格式。Web.xml 中web-app标签的version属性如果是 3.1 或 4.0就要确保 Tomcat 8.5 以上支持如果是 2.5那 Tomcat 7 都行但需要 Java 7 以上。这里有一个常见的坑如果 web.xml 里声明的是 Servlet 4.0而你用的是 Tomcat 8.0启动时会直接报UnsupportedClassVersionError或者LifecycleException。数据库脚本也要提前看。用记事本或 VSCode 打开 SQL 文件检查第一行是否有SET NAMES utf8mb4或类似字符集设置。很多项目表结构里包含中文备注如果你的 MySQL 客户端默认字符集不是 utf8mb4导入时会出现一批警告虽然大部分不影响表结构但数据表里如果有中文种子数据就会直接变成乱码。最稳妥的做法是先用 Notepad 或 VSCode 把 SQL 文件转为 UTF-8 编码保存再用命令行或 Navicat 导入。版本确认后就可以用 IDEA 导入了。选择 File → New → Project from Existing Sources定位到解压后的目录选择 Maven 类型IDEA 会自动识别 pom.xml。首次加载时会下载大量依赖国内网络建议在 Maven 的 settings.xml 里配置阿里的镜像仓库配置方式是在mirrors节点下加这段mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这个镜像源配置在 settings.xml 的mirrors标签内配置后 Maven 对中央仓库的下载请求都会指向阿里云。如果项目已经下载到一半出现红叉可以在 IDEA 右侧 Maven 面板里点击刷新按钮重新解析依赖。2.3 JDK、Maven、Tomcat、MySQL 版本匹配参考表下面这张表是我在着手环境配置时常用的参考你也可以根据实际手头已有的软件灵活调整但要保证大版本不跳档组件推荐版本备选版本关键注意事项JDK1.88u1911.7仅配合 Tomcat 7高于 11 时部分老框架反射有问题Maven3.6.33.3.93.6 对 JDK 8 支持良好Tomcat8.5.x9.0.x9.0 需要 JDK 8 以上兼容 Servlet 4.0MySQL5.7.x8.0.x8.0 需要驱动com.mysql.cj.jdbc.DriverMySQL 驱动5.1.478.0.118.0 驱动必须加时区参数这个版本组合是踩过很多坑之后沉淀下来的经验值尤其是 MySQL 驱动这一点。如果你本地是 MySQL 8.0而 pom 里是 5.1.47 的驱动连接时八成会出现Communications link failure或者Public Key Retrieval is not allowed后者的解决办法是连接 URL 加allowPublicKeyRetrievaltrueuseSSLfalse但更省事的办法是直接把驱动版本升到 8.0.11 以上。驱动版本由 pom.xml 中的mysql-connector-java依赖版本号控制改完后重新加载 Maven 即可。3. 手写 SSM 核心配置从 web.xml 到 mybatis-config 的完整装配顺序3.1 web.xml 里的监听器、DispatcherServlet 与编码过滤器谁先谁后SSM 项目没有 Spring Boot 那样的自动配置一切靠 web.xml 手动装配。web.xml 是 Web 应用的入口描述文件它决定了 Spring 容器何时初始化、SpringMVC 的 DispatcherServlet 拦截哪些请求、字符编码过滤器是否全局生效。我见过很多系统启动后乱码或者 404问题往往就出在这里。一个标准的 SSM web.xml 需要依次完成以下几件事通过 ContextLoaderListener 初始化 Spring 根容器加载 classpath 下的 applicationContext.xml配置 DispatcherServlet 并加载 spring-mvc.xml配置 CharacterEncodingFilter 并设置 encoding 为 UTF-8、forceEncoding 为 true配置欢迎页和 session 过期时间。以下是常见的配置骨架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_3_1.xsd version3.1 display-namecampus-book-corner/display-name context-param param-namecontextConfigLocation/param-name param-valueclasspath: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 init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-nameencodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping servlet servlet-namespringmvc/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-namespringmvc/servlet-name url-pattern//url-pattern /servlet-mapping welcome-file-list welcome-fileindex.jsp/welcome-file /welcome-file-list /web-app这段配置文件的关键点有两个DispatcherServlet 拦截/而不是*.do意味着所有请求都进 SpringMVC静态资源要额外放行ContextLoaderListener 先初始化根容器DispatcherServlet 再初始化自己的子容器两个容器各管一部分 Bean。如果你发现 Controller 里的Autowired注入 Service 失败先检查 Service 是否被根容器扫描、Controller 是否被 spring-mvc.xml 扫描两个扫描范围重叠就会导致 Bean 重复定义不重叠就会导致找不到依赖。3.2 spring-mvc.xml 的组件扫描、注解驱动与静态资源放行spring-mvc.xml 是 SpringMVC 的核心它决定去哪里找 Controller、是否启用注解解析、视图解析器怎么拼 JSP 路径、静态资源怎么处理。常见的配置模板如下?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:mvchttp://www.springframework.org/schema/mvc xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd !-- 当前容器的组件扫描范围只扫 controller 包 -- context:component-scan base-packagecom.campus.book.controller/ mvc:annotation-driven/ mvc:resources mapping/static/** location/static// bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean /beans这里最容易出问题的是context:component-scan的包路径。如果 Controller 在com.campus.book.controller而你在注解类上写的是com.campus.book会把 Service 和 Mapper 也扫进来再由 MyBatis 的 MapperScannerConfigurer 扫一遍就会出现 Bean 冲突。mvc:annotation-driven/是必须的它负责注册默认的 HandlerMapping 和 HandlerAdapter没有这一行你写的RequestMapping全部不生效。视图解析器的 prefix 和 suffix 决定了 Controller 返回的字符串如何定位到 JSP。如果项目 JSP 放在 WebContent 或 webapp 根目录就写成/前缀如果像这个模板里放在 WEB-INF 下浏览器不能直接访问但 Controller 可以转发到该路径这种方式更安全也是推荐做法。3.3 MyBatis 的 Mapper 扫描、别名与 JDBC 连接参数MyBatis 侧的配置在 applicationContext.xml 或单独的 mybatis-spring.xml 里核心是 SqlSessionFactoryBean、MapperScannerConfigurer 和数据源三者之间的协作。很多系统启动报Invalid bound statement (not found)就是 SqlSessionFactoryBean 加载的 mapper XML 路径和 Mapper 接口包路径对不上。建议的方向是把数据源独立成 jdbc.properties复用性更好。项目中的 jdbc.properties 内容一般长这样jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/bookcorner?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password123456如果用 MySQL 8.0driver 要改成com.mysql.cj.jdbc.Driverurl 末尾还要加serverTimezoneAsia/Shanghai否则会报时区错误。接着在 applicationContext.xml 里注入数据源bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSource 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/campus/book/mapper/*.xml/ property nametypeAliasesPackage valuecom.campus.book.entity/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.campus.book.dao/ /beanMapperScannerConfigurer 的 basePackage 是 Mapper 接口所在的包它通过扫描接口生成动态代理然后注入到 Service 里。mapperLocations 指向 XML 文件注意 XML 的命名空间必须和接口全限定名一致select标签的 id 必须和接口方法名一致否则会启动失败。typeAliasesPackage 配置实体类所在的包这样就可以在 XML 里直接写resultTypeBook而不用写全路径。3.4 数据库表设计图书、用户、借阅记录三张表的字段与关联图书角管理系统数据库的表结构通常围绕三个核心实体图书、用户、借阅记录。图书表存书目信息用户表存学生和管理员借阅记录表存谁在什么时候借了什么书、什么时候还。一张完整的建表 SQL 大体是这样的CREATE DATABASE IF NOT EXISTS bookcorner DEFAULT CHARSET utf8mb4; USE bookcorner; CREATE TABLE book ( id INT PRIMARY KEY AUTO_INCREMENT, book_name VARCHAR(100) NOT NULL COMMENT 书名, author VARCHAR(50) DEFAULT NULL COMMENT 作者, publisher VARCHAR(80) DEFAULT NULL COMMENT 出版社, isbn VARCHAR(20) DEFAULT NULL COMMENT ISBN号, category VARCHAR(30) DEFAULT NULL COMMENT 分类, total INT DEFAULT 1 COMMENT 馆藏数量, remaining INT DEFAULT 1 COMMENT 可借数量, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB COMMENT 图书表; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE COMMENT 登录名, password VARCHAR(64) NOT NULL COMMENT 密码, role TINYINT DEFAULT 0 COMMENT 0学生 1管理员, student_no VARCHAR(20) DEFAULT NULL COMMENT 学号, phone VARCHAR(20) DEFAULT NULL COMMENT 联系电话 ) ENGINEInnoDB COMMENT 用户表; CREATE TABLE borrow_record ( id INT PRIMARY KEY AUTO_INCREMENT, book_id INT NOT NULL COMMENT 图书ID, user_id INT NOT NULL COMMENT 用户ID, borrow_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 借出时间, due_time DATETIME DEFAULT NULL COMMENT 应还时间, return_time DATETIME DEFAULT NULL COMMENT 实际归还时间, status TINYINT DEFAULT 0 COMMENT 0借出 1已还 2逾期, KEY idx_book_id (book_id), KEY idx_user_id (user_id), CONSTRAINT fk_borrow_book FOREIGN KEY (book_id) REFERENCES book(id), CONSTRAINT fk_borrow_user FOREIGN KEY (user_id) REFERENCES user(id) ) ENGINEInnoDB COMMENT 借阅记录表;这里值得留意的字段是remaining。很多系统更新库存时只做减法不检查是否为负用户连续点两次借阅就会把库存借成负数影响数据完整性。常见做法是在 Service 层先查 remaining 是否大于 0再用UPDATE book SET remaining remaining - 1 WHERE id ? AND remaining 0这样的语句保证原子性。外键在毕业设计里建议保留它能体现你对关系型数据库的建模理解但在高并发场景下外键会影响性能你可以在文末的答辩准备里说明你清楚这个取舍。4. 从 JSP 页面到数据库的完整请求链图书借阅功能的代码是怎么串联的4.1 JSP 里的表单如何提交到 ControllerJSP 在这个系统里负责两层事渲染数据和接收用户操作。图书借阅页面上有一个表格列出所有可借图书每行右侧一个“借阅”按钮。这个按钮可以是一个包含 bookId 的表单也可以是一个携带参数的链接。推荐后者的写法因为借阅操作理论上应该是 POST 请求但如果项目里没有做 CSRF 防护GET 也能跑通。下面是表格中借阅按钮的 JSP 片段form action${pageContext.request.contextPath}/borrow/add methodpost styledisplay:inline; input typehidden namebookId value${book.id} / input typehidden nameuserId value${sessionScope.loginUser.id} / button typesubmit借阅/button /form这段代码中${pageContext.request.contextPath}是 JSP EL 表达式作用是动态获取项目根路径避免因为部署时改了应用名导致路径 404。${book.id}是后端返回的图书对象属性。表单提交到/borrow/add这个 URL由 SpringMVC 的注解映射处理。不需要在 JSP 里写任何 Java 代码EL 表达式和 JSTL 标签已经够用。4.2 Controller、Service、Mapper 三层的编码顺序Controller 层只做参数接收和视图跳转业务逻辑下沉到 Service 层SQL 留在 Mapper XML。下面以借阅功能为例展示从 Controller 到 Mapper 完整的调用链写法。Controller 需要接收前端传来的 bookId 和 userId调用 Service 完成借阅逻辑然后重定向回列表页Controller RequestMapping(/borrow) public class BorrowController { Autowired private BorrowService borrowService; PostMapping(/add) public String addBorrow(Integer bookId, Integer userId, Model model) { try { borrowService.borrowBook(bookId, userId); return redirect:/book/list; } catch (RuntimeException e) { model.addAttribute(errorMsg, e.getMessage()); return forward:/book/list; } } }PostMapping是 Spring 4.3 之后引入的组合注解等价于RequestMapping(value/add, methodRequestMethod.POST)。方法参数中的Integer bookId由 SpringMVC 自动完成类型转换从前端表单取同名参数。重定向到/book/list可以避免表单重复提交这是 PRG 模式Post/Redirect/Get的常规操作。Service 里要处理库存扣减和借阅记录插入的原子性这不是一个简单的状态转移而是一组必须同时成功的写入操作。用 Spring 的声明式事务注解实现最简单Service public class BorrowServiceImpl implements BorrowService { Autowired private BookMapper bookMapper; Autowired private BorrowRecordMapper borrowRecordMapper; Override Transactional(rollbackFor Exception.class) public void borrowBook(Integer bookId, Integer userId) { Book book bookMapper.selectById(bookId); if (book null) { throw new RuntimeException(图书不存在); } if (book.getRemaining() 0) { throw new RuntimeException(图书已被借完); } int rows bookMapper.decreaseRemaining(bookId); if (rows 0) { throw new RuntimeException(库存扣减失败请重试); } BorrowRecord record new BorrowRecord(); record.setBookId(bookId); record.setUserId(userId); record.setDueTime(new Date(System.currentTimeMillis() 30L * 24 * 3600 * 1000)); borrowRecordMapper.insert(record); } }Transactional注解由 Spring 的 AOP 实现事务增强默认只在遇到 RuntimeException 时回滚。rollbackFor Exception.class表示任何异常都回滚。这里先查再扣再插入三步操作在同一个事务里任何一个失败都会整体回滚不会出现库存减了但借阅记录没生成的半截状态。Mapper 接口定义与 XML 映射是关键一环接口方法名与 XML id 必须一一对应public interface BookMapper { Book selectById(Integer id); int decreaseRemaining(Integer id); }对应的 BookMapper.xml 中decreaseRemaining使用了乐观锁式的条件更新update iddecreaseRemaining UPDATE book SET remaining remaining - 1 WHERE id #{id} AND remaining 0 /update这里的#{id}是 MyBatis 的预编译参数占位符可以防 SQL 注入。AND remaining 0是防止超借的关键条件如果返回行数为 0说明当前库存不足或图书不存在Service 层可以抛出异常并回滚事务。4.3 列表页查询的分页与搜索条件拼接图书列表页在毕业设计里通常要做到分页和模糊查询这也是答辩时老师会重点问的部分。用 PageHelper 插件最省事但如果项目里没集成插件手写 LIMIT 分页也就十来行代码。Controller 接收pageNum、pageSize和关键字keyword传给 ServiceService 构造查询条件传给 MapperGetMapping(/list) public String list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, String keyword, Model model) { int offset (pageNum - 1) * pageSize; ListBook bookList bookMapper.selectPage(keyword, offset, pageSize); int total bookMapper.countByKeyword(keyword); int totalPages (int) Math.ceil(total * 1.0 / pageSize); model.addAttribute(bookList, bookList); model.addAttribute(totalPages, totalPages); model.addAttribute(currentPage, pageNum); model.addAttribute(keyword, keyword); return book/list; }分页参数在前端由 JSP 拿到后渲染翻页按钮点击时拼接新的 query string 发起新的 GET 请求。这里有一个隐蔽的问题是 SQL 里的模糊查询写法MySQL 中用LIKE CONCAT(%, #{keyword}, %)而不要直接写%${keyword}%前者是预编译传参后者是做字符串拼接存在注入风险。列表页还有一种常见需求是导出 Excel。检索结果里有“jsp实现数据导出为excel”这个方向学生管理模块的老师通常会要求导出学生借阅明细。有两条路可以走一是后端用 Apache POI 生成 xlsx 响应给前端二是在 JSP 上直接响应Content-Type: application/vnd.ms-excel把表格内容以 CSV 或 HTML Table 形式输出。毕业设计够用的话用 POI 导出更显技术含量代码量也不大GetMapping(/export) public void export(HttpServletResponse response) throws IOException { ListBorrowRecordVO records borrowRecordMapper.selectAllWithBookAndUser(); response.setContentType(application/vnd.ms-excel;charsetutf-8); response.setHeader(Content-Disposition, attachment;filenameborrow_records.xls); try (Workbook workbook new HSSFWorkbook()) { Sheet sheet workbook.createSheet(借阅记录); // 创建表头行写入字段名 // 遍历 records逐行写入单元格 workbook.write(response.getOutputStream()); } }导出接口返回的是一份文件流不是 JSP 页面所以 Controller 方法上不需要ResponseBody直接写 response 输出即可。4.4 JSP 页面引用静态资源的相对路径问题图书角管理系统里登录页和管理端页面都会引用 CSS 和 JS如果你在 spring-mvc.xml 里配置了静态资源映射为/static/**在 JSP 页面里正确的引用方式是link relstylesheet href${pageContext.request.contextPath}/static/css/style.css / script src${pageContext.request.contextPath}/static/js/common.js/script不用${pageContext.request.contextPath}直接写static/css/style.css的话浏览器会基于当前 URL 拼路径。假如当前页面地址是/book/list浏览器会请求/book/static/css/style.css由于 DispatcherServlet 拦截了/这个请求会进入 SpringMVC匹配不到映射就直接 404。如果你在学生信息维护页面遇到过样式丢失、图片裂开优先怀疑的就是这个相对路径问题。5. 部署环节的实测排错乱码、404 和数据库连不上的三个高频问题5.1 Tomcat 启动成功但页面 404先查 Artifacts 和访问路径IDEA 里运行 SSM 项目大多数人卡在第一步Tomcat 能启动但浏览器访问http://localhost:8080跳出 Tomcat 默认首页访问/项目名就是 404。这种情况 90% 是 Artifacts 配置的问题。打开 File → Project Structure → Artifacts确认输出类型是Web Application: Exploded并且在 Deployment 标签页里已经把构建产物加入。更具体的说IDEA 里要把 Tomcat Server → Deployment 中的 Application context 和项目访问路径对应起来。应用上下文名称默认是项目名_war_exploded一长串很难记建议改成/bookcorner。然后浏览器访问http://localhost:8080/bookcorner就能打开首页。改完之后注意 URL 的大小写Linux 服务器上区分大小写Windows 上不区分如果部署到云服务器上路径写错就会白屏。还有一种 404 只针对部分页面比如/book/list能打开/borrow/export报 404。看 IDEA 控制台的日志如果出现No mapping found for HTTP request with URI [/borrow/export] in DispatcherServlet说明 Controller 里没有对应映射或者类被扫描到了但方法上的注解写错了。检查GetMapping(/export)是否拼错类上RequestMapping(/borrow)是否缺失。5.2 页面中文全是问号字符集链条要逐段排查乱码问题在 JSPSSM 项目里几乎是必考题。乱码分两种情况一种是从数据库读出来的中文变成问号另一种是页面提交的中文存进数据库变成问号。前者的根源在数据库连接 URL 上useUnicodetruecharacterEncodingutf8两个参数必须同时存在后者的根源在 JSP 页面编码和 Tomcat 对 POST 请求的解码方式。JSP 文件头部需要写上两行% page contentTypetext/html;charsetUTF-8 languagejava % meta charsetUTF-8同时 web.xml 里的CharacterEncodingFilter要放在所有 Filter 的最前面并且forceEncoding设为 true这样请求和响应都会被强制以 UTF-8 处理。如果这些都设置了还乱码检查物理机上的 Tomcat 配置conf/server.xml中 Connector 标签有没有加URIEncodingUTF-88.5 版本默认是 UTF-8但有的教学环境装的是老版本需要手动加上。数据库侧的检查位置是 URL 的characterEncodingutf8参数以及 MySQL 建表时的DEFAULT CHARSETutf8mb4两者字符集要一致。此外 MySQL 客户端在导入 SQL 文件时如果用了 Source 命令还要先执行SET NAMES utf8mb4;确保会话级字符集正确。5.3 数据库连接失败驱动、时区、密码三种情况连接失败一般会在启动 Tomcat 时通过异常堆栈暴露出来常见的报错是Cannot create PoolableConnectionFactory或Access denied for user。前者说明数据源创建连接失败后者说明账号或密码不对。先检查 jdbc.properties 中的用户名密码跟本地 MySQL 是否一致再检查 URL 的 host 和 port如果改了 MySQL 默认端口记得在 URL 里同步修改。MySQL 8.0 用户还会遇到一个独特的报错java.sql.SQLException: The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。这就是前文提到时区参数的原因解决方式是在连接 URL 上追加serverTimezoneAsia/Shanghai。如果还要消除 SSL 告警就顺手加上useSSLfalse。完整的 URL 写法jdbc.urljdbc:mysql://localhost:3306/bookcorner?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai最后一个容易碰到的问题是驱动 jar 包没打进去。用 IDEA 的 Maven 项目跑无所谓如果把项目打包成 war 再手动放进 Tomcat 的 webapps 目录就要去WEB-INF/lib下确认有没有 mysql-connector-java 的 jar。缺少这个 jar 时启动不报错但一旦有请求触发数据库操作就会报ClassNotFoundException: com.mysql.jdbc.Driver定位方法是查看部署目录里 lib 文件夹的大小正常 SSM 项目应该在 20MB 左右如果只有几百 KB 就是依赖没带全。5.4 本地能跑和部署到服务器是两个项目拿到源码后如果只是本地答辩按照上面的步骤就能跑通。但如果需要部署到云服务器演示还有一些额外注意点。首先 MySQL 的 root 用户默认只允许 localhost 登录需要新建用户并授权远程访问执行GRANT ALL PRIVILEGES ON bookcorner.* TO book% IDENTIFIED BY password;。其次防火墙要放行 3306 和 8080 端口。最后 jdbc.properties 里的数据库地址要改成服务器内网 IP 而不是 localhost因为你的 Java 程序和数据库在同一台机器上写 localhost 也行但写公网域名有时会因为安全组规则导致慢连接稳妥起见用内网 IP。最后一个建议是运行环境里保留 MySQL 5.7 JDK 8因为这个组合与绝大多数源码的依赖版本、驱动写法最匹配。如果本地已经装了 JDK 17 且不方便更换可以把 pom.xml 中 Spring 的版本升级到 5.3.x、MyBatis 保持 3.5.x、MySQL 驱动换成 8.0.33但这样做的工作量远比装一个 JDK 8 大还会引入新旧 API 不兼容的风险。对毕业设计来说能把一个稳定的组合跑透比追逐最新版本更有意义。本文还有配套的精品资源点击获取
返回列表