☰
基于JavaWeb和MySQL的SSM企业人事管理系统实战开发指南
2026/9/29 15:44:27 网站建设 项目流程

这套技术栈组合,我在课设和真实的项目里都倒腾过不少次。用“基于javaweb和mysql的ssm企业人事管理系统”这个标题来做人资项目,是很多高校课设和毕业设计的经典选题。标题里提到的那一长串名词——java、ssm、jsp、h-ui、echarts、ztree、mysql,每个都不是凑数的。如果你正在做或准备做这个项目,这篇文章正好能帮你把整个技术路线和实操中的坑捋清楚,从环境配置到功能落地,从数据库设计到图表展示,照着走基本都能跑通。

1. 项目思路与整体架构拆解

很多人在拿到“企业人事管理系统”这类需求时,第一反应是急着去写代码。但我在做过几次课设指导和项目重构之后,越来越觉得:这类管理系统项目的核心竞争力不在“功能多么多”,而在“架构是否清晰、技术栈是否自洽、展示是否直观”。标题里的技术名词,其实就是一套完整的Web全栈解决方案。

1.1 技术选型:为什么这套组合契合JavaWeb课设场景

先逐个说说这些关键词在系统里的角色。

javaweb是整个系统的基础形态,说的是我们用Java技术栈来实现B/S架构的Web应用。mysql是底层数据库,负责所有业务数据的存储。ssm是Spring+SpringMVC+MyBatis的组合,这是经典的企业级开发框架,Spring管对象和事务,SpringMVC管请求分发和参数绑定,MyBatis管SQL和结果映射。jsp是视图层技术,配合JSTL和EL表达式,把后台的数据渲染到页面上。

h-ui是一套轻量级的前端后台管理模板,栅格系统、表单、表格、弹窗这些UI组件都是现成的,比我们从零写CSS效率高得多。echarts是百度开源的数据可视化图表库,用来做员工统计报表、部门人数分布、学历构成这类图表展示。ztree则是一款基于jQuery的树形控件,天然适合做公司部门树、组织架构图。

这套组合用在课设或毕设里,最明显的好处有两个。第一,技术栈足够主流,面试时聊起SSM、MySQL、JSP这些关键词,对方会有熟悉感,不至于觉得你在用冷门技术。第二,前端有开箱即用的模板,后端有框架分层,我们能把主要精力放在核心业务逻辑和数据库设计上,在有限时间内做出一个完整度高、能演示、能截图写进论文的系统。

1.2 功能模块划分与数据库设计心得

人事管理系统的模块划分,我习惯按“基础数据+业务流转+系统支撑”三层来切。基础数据就是员工信息、部门信息;业务流转就是考勤、请假、薪资计算这类流程性功能;系统支撑就是用户登录、权限管理、操作日志、数据统计。标题里没有出现“考勤”“薪资”这类细化功能词,但一个完整的人事管理系统,这些模块是绕不开的,只是实现深度可以自己把控。

数据库是这类系统的灵魂。我见过太多人一开始就堆字段、建表不设外键关联,到后期写SQL和调ECharts数据时痛不欲生。这里分享一下我认为最稳妥的表结构设计思路。

员工表(employee)核心字段:

  • id(主键,自增)
  • emp_no(员工工号,唯一索引)
  • name(姓名)
  • gender(性别)
  • birthday(出生日期)
  • dept_id(关联部门表,外键)
  • position(职位)
  • salary(工资,Decimal类型)
  • entry_date(入职时间)
  • status(在职/离职状态,用0和1表示)

部门表(department)核心字段:

  • id(主键)
  • dept_name(部门名称)
  • parent_id(父部门ID,用于zTree构造树形结构)
  • create_time(创建时间)

用户表(sys_user)核心字段:

  • id
  • username(登录名)
  • password(加密存储)
  • real_name(真实姓名)
  • role(角色编码)

考勤、请假、薪资这几张表,核心都是“关联员工主键ID + 时间字段 + 状态字段+流程记录字段”的模式。

在设计时记住一个原则:能用数字类型就不用字符串,能用外键关联就一定要关联,时间字段统一用datetime,金额字段用decimal(10,2)。有个印象很深的教训:有次做Salary表时图省事把salary金额字段设成了varchar,结果写SUM聚合函数时MySQL直接报语法错误,白白浪费了一晚上排查时间。所以建表这一步,宁可多花半小时想清楚,也不要后期改表结构。

2. 开发环境搭建与配置细节

环境搭建和框架整合,是这个项目里劝退新手最多的一个环节。很多人的项目代码逻辑没问题,就是卡在IDE配置、框架版本冲突、依赖缺失这些地方。这里把关键版本选择和配置细节摊开来说清楚,基本上照着做就能跳过那些坑。

2.1 环境版本选型:JDK、Tomcat、MySQL、Maven怎么搭配

关于版本,我的建议很明确:JDK用1.8,Tomcat用8.5或9.0,MySQL用5.7(用8.0也行但要注意驱动和时区配置),Maven用3.6.3。这里解释一下原因。

JDK 1.8虽然已经是“老古董”了,但它和SSM框架的兼容性几乎是完美的。Spring 5.x在JDK 8上运行极其稳定,Tomcat 8.5也支持到Java 8。如果选JDK 11甚至JDK 17,Spring的CGLIB代理、JSP编译这些环节偶尔会蹦出一些奇奇怪怪的兼容问题,对课设项目不友好。

MySQL选5.7的原因更实际:驱动类名是com.mysql.jdbc.Driver,不需要关心serverTimezone和SSL连接参数。而MySQL 8.0的驱动类名变成了com.mysql.cj.jdbc.Driver,还必须显式配置时区,否则报错。如果你已经装了MySQL 8.0也没关系,下文有对应的配置方式,只是建议没装的人直接用5.7。

2.2 Spring、SpringMVC、MyBatis三件套整合配置要点

这三件套的配置可以拆成三个文件来理解:applicationContext.xml负责Spring容器的全局配置,springmvc.xml负责控制器和视图解析,mybatis-config.xml负责MyBatis的全局属性。

先说applicationContext.xml里的几个核心配置。第一是组件扫描,把service和dao层交给Spring管理:

<context:component-scan base-package="com.company.hrms"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>

注意这里要排除Controller注解,因为Controller由SpringMVC的配置文件来管理,两边都扫描会造成Bean重复实例化的问题。

第二是数据源配置。我习惯用Druid连接池,它比Spring自带的DriverManagerDataSource要可靠,还带监控页面:

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="initialSize" value="5"/> <property name="maxActive" value="20"/> </bean>

第三是将数据源交给MyBatis的SqlSessionFactoryBean,同时配置MyBatis的mapper扫描路径:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <property name="typeAliasesPackage" value="com.company.hrms.entity"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.company.hrms.dao"/> </bean>

再来说springmvc.xml。视图解析器是JSP项目的关键,InternalResourceViewResolver会把Controller返回的字符串逻辑视图名解析成真实的JSP路径:

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/"/> <property name="suffix" value=".jsp"/> </bean>

同时要开启SpringMVC的注解驱动,并把静态资源(js、css、图片)放行,否则浏览器请求的静态资源会被DispatcherServlet拦截:

<mvc:annotation-driven/> <mvc:default-servlet-handler/>

最后是事务配置。在applicationContext.xml里加一个事务管理器,开启基于注解的事务即可。代码里Service层的方法上加上@Transactional注解,就能保证数据库操作的原子性。

这点被很多人忽略,但非常重要。没有事务时,一旦薪资计算过程在中间某条数据上抛异常,前面已执行的SQL照样提交,数据就处于半更新状态;有了事务,任何一步出错整批回滚,系统才真正可靠。

2.3 MySQL连接的关键参数:SSL、时区与驱动类名

这里重点讲一下jdbc.properties里的细节,因为报错的重灾区都在这里。我用的是MySQL 8.0时:

jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/hrms?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8 jdbc.username=root jdbc.password=123456

有几个参数必须解释清楚。useSSL=false表示关闭SSL连接,MySQL 8.0默认开启SSL。如果不显式关掉,控制台会输出一堆SSL连接警告,有的版本甚至会直接报ssl connection error。serverTimezone=Asia/Shanghai是指定服务器时区为东八区。一开始我不理解这个参数的含义,后来才明白MySQL 8.0驱动会把本地时区信息传给服务器,两边时区不一致就会抛异常。characterEncoding=utf8确保应用程序和数据库之间传输的都是UTF-8编码的中文,这直接关系到中文会不会乱码。

如果你用的是MySQL 5.7,记得把驱动类名改回com.mysql.jdbc.Driver,url也可以不用加serverTimezone参数,其他保持不变即可。

3. 核心功能实现与前端框架集成

后端框架搭好之后,真正的苦活是页面展示和前后端衔接。这一部分会集中讲清楚H-ui模板怎么整合进项目、zTree怎么生成部门树、ECharts怎么做统计图、以及登录拦截和分页查询的落地方式。这些功能一旦个个都能在浏览器里流畅跑起来,你的项目就赢过一大半人了。

3.1 H-ui后台模板与JSP页面的整合方式

h-ui这套模板的核心价值在于,它把后台管理系统的布局、表格、按钮、弹窗、表单验证等UI组件都封装好了。我们要做的不是从零画页面,而是把它的静态资源引入项目,然后把自己写的JSP页面套进它的框架布局里。

实际整合时,我推荐用iframe布局。首页(index.jsp)负责整体框架:左边是菜单栏,右边是一个iframe区域,所有功能页面都在这个iframe里打开。这样做的好处是菜单区域不用每次刷新,切换功能模块时只重载内容区,体验很接近原生应用。

目录结构建议这样组织:

webapp/ ├── static/ │ ├── h-ui/ │ ├── jquery/ │ ├── ztree/ │ └── echarts/ ├── WEB-INF/ │ ├── views/ │ │ ├── employee/ 员工管理页面 │ │ ├── department/ 部门管理页面 │ │ ├── statistics/ 统计报表页面 │ │ └── index.jsp 主框架页 └── index.jsp 入口重定向页

有一个很容易犯的低级错误需要提醒:JSP页面里引入静态资源时,路径最好像这样写:

<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <base href="<%=basePath%>">

然后所有CSS和JS引用都用相对路径:

<link rel="stylesheet" href="static/h-ui/css/H-ui.min.css"> <script src="static/jquery/jquery-3.6.0.min.js"></script>

如果你不设置base标签,直接写相对路径,在“localhost:8080/项目名/employee/list”这种二级路径下,浏览器会把这个相对路径解析成localhhost:8080/项目名/employee/static/...,导致静态资源全部404。这个坑在iframe嵌套页面里尤为隐蔽,因为页面内容区域可能显示正常,但样式全丢了。

3.2 zTree实现部门组织架构树

zTree是做部门树的最好选择,它的API清晰、文档齐全,而且渲染性能对课设规模的节点量完全没有压力。它的核心是两件事:数据格式和事件回调。

后端返回给前端的部门数据,必须是标准的zTree节点JSON格式。比如:

[ {"id":1, "pId":0, "name":"总公司"}, {"id":2, "pId":1, "name":"技术部"}, {"id":3, "pId":1, "name":"人事部"}, {"id":4, "pId":2, "name":"前端组"} ]

前端初始化zTree的代码很简单:

var setting = { data: { simpleData: { enable: true, idKey: "id", pIdKey: "pId" } }, callback: { onClick: function(event, treeId, treeNode) { // 点击部门节点后,刷新右侧员工列表 loadEmployeeByDept(treeNode.id); } } }; $.ajax({ url: 'department/tree', type: 'GET', dataType: 'json', success: function(data) { $.fn.zTree.init($("#deptTree"), setting, data); } });

点击某个部门节点后触发loadEmployeeByDept,相当于把当前部门的id传到后台,后台查询该部门下的员工并刷新iframe里的员工列表。这种感觉很直观:左边选择部门,右边展示对应员工。答辩时的演示效果也比较好,评委一眼就能看懂你的数据联动逻辑。

3.3 ECharts实现人事统计可视化报表

ECharts是这个项目的又一大亮点,也是标题里明确出现的关键词。数据可视化是很多人喜欢在答辩时着重展示的部分,因为它最直观。

先说引入方式。虽然可以用CDN,但我建议你下载ECharts的min.js文件放到本地static目录下。课设答辩现场的电脑不一定有外网,如果用了CDN又断网,图表直接空白,那种尴尬我见过太多次。

以一个员工性别分布饼图为例,核心option配置如下:

var chart = echarts.init(document.getElementById('genderChart')); var option = { title: { text: '员工性别分布', left: 'center' }, tooltip: { trigger: 'item' }, legend: { orient: 'vertical', left: 'left' }, series: [{ name: '性别分布', type: 'pie', radius: '60%', data: [ {value: 35, name: '男'}, {value: 27, name: '女'} ] }] }; chart.setOption(option);

这里的几个配置项需要理解清楚。title是图表标题;tooltip配成trigger: item表示鼠标悬停在扇区时显示对应的数据信息;legend是图例,说明不同扇区对应的含义;series里的type: pie指定了图表类型为饼图,radius控制饼图大小,data是真实的数据源。

实际操作中,数据通常不是写死的,而是从后台查询出来。做法是Controller返回一个JSON数组,前端用ajax接收后再setOption。例如统计各部门人数的柱状图数据,可以封装成一个Map列表返回:

@RequestMapping("/statistics/deptCount") @ResponseBody public List<Map<String, Object>> deptCount() { // 调用service层,按部门分组统计员工数量 return employeeService.countByDept(); }

前端拿到结果后,遍历数组,把名称和数量分别塞进xAxis和series:

var xAxisData = []; var seriesData = []; for (var i = 0; i < data.length; i++) { xAxisData.push(data[i].deptName); seriesData.push(data[i].count); }

图表部分的进阶技巧,可以在答辩时加分。比如柱状图用渐变色填充,是用echarts的LinearGradient来实现的:

color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ {offset: 0, color: '#4facfe'}, {offset: 1, color: '#00f2fe'} ])

再比如折线图的x轴刻度标签,如果部门名称太长会重叠,可以加axisLabel的rotate参数让文字旋转显示。这些细节都是体现你真正用过ECharts、而不仅仅是调个demo的好证据。

3.4 登录拦截器与PageHelper分页查询实现

登录拦截是这类系统不能缺少的基础功能。不用Spring Security那种重量级框架,写一个简单的HandlerInterceptor就够了。

拦截器代码如下:

public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user = request.getSession().getAttribute("loginUser"); if (user == null) { // 未登录,重定向到登录页 response.sendRedirect(request.getContextPath() + "/login"); return false; } return true; } }

然后在SpringMVC配置里注册拦截器,并设置放行规则。放行登录页面、登录请求、静态资源:

<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/login"/> <mvc:exclude-mapping path="/user/login"/> <mvc:exclude-mapping path="/static/**"/> </mvc:interceptor> </mvc:interceptors>

分页查询用PageHelper插件,配置非常简单。在MyBatis的配置里引入插件,然后在Service层查询前调用PageHelper.startPage即可:

PageHelper.startPage(pageNum, pageSize); List<Employee> list = employeeMapper.selectByDeptId(deptId); PageInfo<Employee> pageInfo = new PageInfo<>(list);

把pageInfo返回给页面后,页面上展示PageInfo里的list数据、总记录数total、当前页码pageNum,以及上一页/下一页按钮即可。PageHelper的底层原理是利用MyBatis的拦截器接口,在执行SQL前自动拼接LIMIT语句。虽然“分页插件自动为我们拼接SQL”听起来很省事,但使用时要注意一个关键问题:PageHelper.startPage之后必须紧跟第一条查询语句,中间不能插入其他数据库操作,否则分页会作用到错误的那条SQL上。

4. 常见问题与排查实录

这个部分是把我在多个SSM项目里踩过的坑整理成一份速查笔记。很多问题看似五花八门,其实根子就那几个。把原因和解决方式列成表格,方便你直接对照排查。

4.1 MySQL连接报错:2002、SSL与时区问题

先从MySQL连接层的错误说起。下面这张表是最常见的几类报错。

报错信息原因解决方案
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock'MySQL服务未启动,或因为安装权限问题导致无法读取socket文件确认本机MySQL服务已启动。Linux下执行systemctl status mysqld查看状态
java.sql.SQLException: The server time zone value is unrecognizedMySQL 8.0的时区配置问题在jdbc.url后追加serverTimezone=Asia/Shanghai
SSL connection error: protocol version mismatchMySQL开启SSL但驱动与服务器协议不匹配在jdbc.url后追加useSSL=false
ClassNotFoundException: com.mysql.jdbc.Driver驱动包版本与MySQL版本不匹配,或pom.xml未引入mysql-connector-javaMySQL 8.0改为com.mysql.cj.jdbc.Driver;检查Maven依赖是否成功下载

4.2 中文乱码的三种场景与统一处理

中文乱码是JavaWeb系统绕不开的老问题。它的产生原因无非是“编码不一致”,但要处理到位,需要把三层全部设成UTF-8。

第一层是JSP页面编码。页面头部必须有:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>

第二层是HTTP请求的编码过滤器。在web.xml中配置Spring提供的CharacterEncodingFilter:

<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

第三层是数据库连接URL。这个在前文已经提过,jdbc.url中加上characterEncoding=utf8。

如果这三个位置都设为UTF-8了,中文依然乱码,再检查一个地方:MySQL数据库表本身的字符集。打开数据库管理工具,确认表结构中的字段字符集是utf8mb4而不是latin1。utf8mb4是utf8的超集,能存储emoji表情和更多特殊字符,这是最推荐使用的字符集。

4.3 JSP页面数据不显示:EL表达式与JSTL陷阱

JSP页面里用${employee.name}取不到值,是另一个高频问题。原因通常是web.xml声明版本太老,导致Servlet容器默认把EL表达式忽略掉。

我在早期就用过Tomcat 7,当时的web.xml声明为2.5版本,JSP页面里${xxx}始终原样输出。解决办法是在JSP页面头部显式开启EL:

<%@ page isELIgnored="false" %>

同时,在页面引入JSTL核心标签库:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

引入后,遍历员工列表就是:

<c:forEach items="${pageInfo.list}" var="emp"> <tr> <td>${emp.empNo}</td> <td>${emp.name}</td> <td>${emp.deptName}</td> </tr> </c:forEach>

注意JavaBean的属性名要和getter方法对应。比如实体类字段是empNo,对应getEmpNo(),页面上才能用${emp.empNo}获取。如果实体类里写的是getEmpno()或者数据库字段映射没配置好,这里也会取不到值。检查顺序先去实体类,再去看MyBatis的resultMap。

4.4 404与500报错定位技巧

404和500是Web开发中最常见的两类错误,排查思路完全不同。

404表示页面或资源不存在。出现404时,先去确认三件事:访问的URL路径是否正确、Controller的@ResponseMapping是否匹配、JSP物理路径是否在视图解析器配置的目录下。一个我印象非常深刻的案例是:请求路径写的是/employee/list,Controller里映射也是/employee/list,但视图解析器的prefix配置成了/WEB-INF/jsp/,JSP文件却放在/WEB-INF/views/下,结果每次跳转都404。这个问题的排查思路是:把prefix改成实际存放JSP的目录,或者把JSP移动到配置的目录,二选一。

500表示服务器内部错误。出现500时,最有效的操作是查看IDEA的Console窗口,异常堆栈信息会直接告诉你是空指针、SQL语法错误,还是类型转换问题。如果你在跑打包后的项目,就去Tomcat的logs/catalina.out文件里找。

这里再分享一个特别的排错经验:如果ajax请求的URL返回了500,但浏览器页面却显示空白,优先按F12打开开发者工具,切到Network选项卡,直接点击那条红色的请求记录,里面的Response内容就是最直接的错误信息。

5. 从“能跑”到“能答辩”的完善与扩展

把上面这些做完,系统已经是一个能完整运行的SSM人事管理系统了。但从我的经验看,课设项目的评分差异往往不在“能不能跑”,而在“完成度高低”和“答辩时能不能讲清楚”。所以这最后一节,专门聊聊怎么把项目从基础版提升成高分项目。

5.1 那你做了什么东西——答辩前的体系化梳理

答辩时评委最常问的问题就是:“这个系统你做了哪些功能,技术上有哪些难点?”如果你上来就报菜名一样把增删改查念一遍,大概率拿不到高分。我建议你用“一个项目三句话”来准备:

第一句话,说清楚系统的业务价值:这是一个面向企业HR的企业人事管理系统,覆盖了员工信息维护、部门管理、考勤请假审批、薪资管理和统计报表等核心人事工作流程。

第二句话,讲清技术架构:后端采用SSM三层架构,前端基于H-ui后台框架,用zTree渲染动态部门树,用ECharts实现人事数据的可视化分析,数据层使用MySQL存储。

第三句话,突出个人亮点:比如“在ECharts中使用了自定义渐变色柱状图,使部门人数分布更加直观”、“通过PageHelper优化了员工列表的分页查询性能”、“通过登录拦截器实现了统一的访问控制”。

这样三句话下来,评委很容易抓住你的项目重点,也就更容易给高分。

5.2 功能扩展建议:让项目超出课程预期

如果时间和精力允许,以下几个扩展方向的性价比很高。

一是文件导入导出功能。导入Excel批量添加员工,导出员工花名册。这个功能在企业场景里非常实用,技术实现上用Apache POI操作Excel,前后不过一百多行代码。答辩时现场导出一份Excel,效果非常实在。

二是操作日志模块。用Spring AOP面向切面编程技术,在不侵入业务代码的情况下记录每个用户的关键操作。AOP技术是JavaWeb面试的高频考点,在项目里用到AOP,展示的技术深度立刻不一样。

三是数据权限的控制。不同角色的管理员登录后,看到的数据范围不同。人事专员只能看本部门员工,人事经理能看全公司员工。这涉及到SQL语句的动态拼装,需要熟练MyBatis的动态SQL功能。

这些扩展并不是为了炫技,而是让你在答辩时面对“项目还有什么可改进的地方”这类问题时,有话可说,说得出有价值的思考。

5.3 打包部署的最后一公里

由于这是Maven项目,打包部署其实很成熟。右键项目执行Maven的package命令,就会在target目录下生成一个war包。把这个war包放到Tomcat的webapps目录下,启动Tomcat就能自动解压部署。

这里需要提醒几点。第一,war包里的数据库配置是写在jdbc.properties里的,打包前务必确认数据库账号密码、URL主机名和端口号与部署环境一致。有一次我帮朋友排查他部署后连不上数据库的问题,结果发现他把配置写成了localhost,但数据库跑在另一台服务器上。这个要提前替换成实际环境的值。

第二,部署后原来的URL访问路径会发生变化。比如本地IDEA运行时路径是http://localhost:8080/,打war包部署后变成了http://localhost:8080/项目名/。如果你没有在JSP里设置base标签或使用contextPath拼路径,页面里的链接和静态资源会全部失效。这时候base标签的作用就体现出来了,这也是我前面强调它的原因。

第三,如果你用的是Tomcat 9,有一个比较容易被忽略的地方:web.xml的schema版本要改成Servlet 4.0对应的版本,否则Tomcat启动时可能报版本错误。

个人实际操作中的一点体会

把整个项目从零做通之后,有一个体会特别深:这类SSM管理系统最大的难点,其实从来不是某个独立的技术点,而是“各个技术栈之间的衔接处”——Spring怎么跟MyBatis对接、Controller怎么把数据传给JSP、zTree的数据格式怎么从数据库映射出来、ECharts的数据怎么从后端Service层取到。任何一个环节的知识盲区,都可能消耗很长时间。

最后分享一个小技巧:开发过程中尽量保持“前后端联调”的节奏,不要等后端全部写完再开始做页面。每完成一个模块,就立即把这个模块对应的JSP页面和ajax调通,眼见为实。这样做的好处是,问题会在产生的同时就被发现和解决,而不是积压到最后集中爆发。我自己最开始开发时习惯“全写完再统一调试”,结果一次排查了整整两天才把攒下的错误清干净。后来改成“模块化开发、小步提交”,整个项目的推进效率提升了不止一倍。希望这篇基于项目标题的实战梳理,能帮你少走这些弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询