ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SSH人事管理系统源码解析:从环境搭建到迁移改造

SSH人事管理系统源码解析:从环境搭建到迁移改造 简介这是一套面向企业人事管理场景的Java Web完整项目基于Struts2、Spring、Hibernate和MySQL开发适合Java Web学习者、毕业设计者及需要快速搭建人事系统的开发者参考。系统覆盖员工档案、部门信息、职位变动、工资信息、福利计算、培训管理等核心模块并支持将统计结果按员工或全部导出为PDF、Excel文件便于日常办公与决策。压缩包共127个文件包含34个jar依赖库、21个java源码、20个xml配置、8个jsp页面、2个sql数据库脚本及说明文档等整体约16.9MB目录结构清晰。项目按Action、Service、DAO分层实现并配有视频指导教程讲解部署及版权信息修改便于二次开发。内含Eclipse项目配置与SQL脚本导入数据库后即可运行调试。已有164人学习适合需要完整可运行人事管理源码的开发者下载参考。1. SSH 人事资源管理系统的源码包到底装了些什么看到这个标题第一反应很可能是SSH 不是远程登录协议吗——但在人事资源管理系统源码这个组合里SSH 指的是 Java Web 时代最常见的框架搭配Struts2 Spring Hibernate。这类 rar 包常见于高校课程设计与中小公司遗留系统解压后多是 Eclipse 工程自带 SQL 脚本和部署说明。这套源码的价值不在代码新旧而在于把部门、职位、员工档案、考勤、薪资、权限这些业务在 SSH 三层架构里完整走了一遍新人能当学习样本老手能当踩坑手册。下文从环境搭建讲到迁移改造命令和参数按可复现的标准来。2. 环境选型与骨架把 SSH 人事系统跑起来的最小配置拿到一个 ssh 人事资源管理系统源码包最忌讳的是直接往 IDE 里拖。先花十分钟理清三个框架的职责和版本关系能省掉后面一整天的启动排错。2.1 先厘清 SSH 三个框架各管哪一层Struts2 负责 MVC 的 Controller 与视图调度Spring 用 IoC 装配对象、用 AOP 切面管声明式事务Hibernate 通过实体映射把 Java 对象落到 MySQL 表。一次员工查询的典型路径是JSP 发请求 → Struts2 按 struts.xml 找到 Action → Action 调 Spring 注入的 Service → Service 走 Dao 里的 Hibernate 模板 → 返回结果集渲染列表页。每一层各留一摊配置文件struts.xml 管路由applicationContext.xml 管 Bean 与事务hibernate.cfg.xml 管数据库连接各个 hbm.xml 管表到实体的映射。四份配置散落在不同目录任何一份出错都会在启动时以各种怪异异常暴露出来。提示老项目里 struts.xml 如果缺constant namestruts.i18n.encoding valueUTF-8/中文乱码几乎是必然的。拿到源码第一件事确认这一行在不在。2.2 解压后的目录结构与版本搭配参考解压后一般是 src 源码目录、WebRoot/WEB-INFweb.xml、lib、配置、以及 hrms.sql 建库脚本。约定俗成的代码分层是 action / service / dao / entity 四个包hrms/ ├── src/ │ ├── com/xxx/hrm/action/ # Struts2 Action接收页面参数 │ ├── com/xxx/hrm/service/ # 业务接口与实现 │ ├── com/xxx/hrm/dao/ # Hibernate DAO 与实现 │ ├── com/xxx/hrm/entity/ # 实体类与 hbm.xml │ ├── struts.xml # Action 路由 │ ├── applicationContext.xml # Spring Bean 与事务 │ └── hibernate.cfg.xml # 数据源配置 ├── WebRoot/ │ ├── WEB-INF/lib/ # 全部 jar 依赖 │ └── pages/ # JSP 页面 └── hrms.sql # 建库 初始数据导入 IDE 前先核对版本常见组合参照下表组件常见版本注意点Struts22.3.16 ~ 2.3.322.5 起 DTD 和拦截器有差异老配置要同步换Spring3.2.x / 4.3.x配 Hibernate 4 必须用 hibernate4 包下的 LocalSessionFactoryBeanHibernate3.6.x / 4.3.x3 和 4 的包名、事务 API 不兼容JDK / TomcatJDK 1.7/1.8 Tomcat 7/8JDK 8 配 Spring 3.2 需要补新版本 javassistMySQL / 驱动5.6/5.7 mysql-connector-java 5.1.x换 8.x 驱动后连接 URL 的写法要改版本不匹配是这类老框架源码启动失败的头号原因。判断方法很简单看 lib 目录里 spring-core 的版本号如 spring-core-3.2.18.RELEASE.jar再对照 hibernate-core 的版本。spring-orm 引用的是 org.springframework.orm.hibernate4 包而 lib 里放的是 hibernate-core-3.6.x启动必定抛 NoSuchMethodError。2.3 数据库初始化顺序先建库再按依赖顺序导脚本最后核对表结构。命令行方式最干净# 先建库指定 utf8避免表建到别的库里 mysql -uroot -p -e CREATE DATABASE hrms DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; # 再导入脚本此时库已存在 mysql -uroot -p hrms hrms.sql # 核对表是否都落在 hrms 库下 mysql -uroot -p -e SHOW TABLES FROM hrms;如果 hrms.sql 里带外键约束建议先把 CREATE TABLE 部分用sed -n /CREATE TABLE/,/;/p hrms.sql tables.sql拆出来单独执行再导入剩余数据。否则部门表还没建员工表就插数据直接撞外键报错。导入完成后用SHOW CREATE TABLE t_employee;核对字段与 hbm.xml 里的 column 是否一致重点看 emp_name 的长度和是否允许为空这两处不匹配会在运行时抛 SQLException 而不是启动报错。3. 从登录到员工 CRUD人事系统 SSH 三层代码怎么落地环境通了的下一步是读代码。人事系统的核心逃不开登录认证、部门树、员工增删改查而这三块恰好把 SSH 三层的协作方式展示得最完整。3.1 Action 层一次员工新增请求的完整入参Struts2 的 Action 是原型模式每个请求 new 一个实例成员变量可以直接接收表单参数这与 SpringMVC 的单例 Controller 正好相反也是老项目里并发写问题少的原因之一。新增员工的精简写法如下SuppressWarnings(serial) public class EmployeeAction extends ActionSupport { private EmployeeService employeeService; // 由 Spring 容器注入 private Employee employee; // 表单自动绑定 private Integer deptId; // 部门下拉框值 // Spring 通过 setter 注入业务层对象 public void setEmployeeService(EmployeeService employeeService) { this.employeeService employeeService; } public String save() { // 只带主键的临时部门对象用于更新外键列 employee.setDept(new Department(deptId)); employeeService.add(employee); return SUCCESS; // 由 struts.xml 决定跳转页面 } }save() 里先用 deptId 构造一个只有主键的 Department 临时对象再 set 进 employee这是只更新外键列的惯用做法比先查部门再 set 少一次查询。Struts2 默认按参数名匹配 setter表单里的 emp.name、emp.birthday 会逐层注入前提是 Employee 有对应 setter。返回 SUCCESS 后由 struts.xml 决定跳转Action 本身不写页面跳转代码这是 MVC 分层的基本纪律。3.2 Service 与 Dao事务边界和 HQL 查询怎么写Spring 的声明式事务把边界划在 Service 上applicationContext.xml 里常见的配置是这样bean idsessionFactory classorg.springframework.orm.hibernate4.LocalSessionFactoryBean property nameconfigLocation valueclasspath:hibernate.cfg.xml/ /bean bean idemployeeDao classcom.xxx.hrm.dao.impl.EmployeeDaoImpl property namesessionFactory refsessionFactory/ /bean bean idemployeeService classcom.xxx.hrm.service.impl.EmployeeServiceImpl property nameemployeeDao refemployeeDao/ /bean tx:advice idtxAdvice transaction-managertransactionManager tx:attributes tx:method nameadd* propagationREQUIRED/ tx:method nameupdate* propagationREQUIRED/ tx:method namefind* read-onlytrue propagationSUPPORTS/ /tx:attributes /tx:advice这段配置的核心意图add 和 update 开头的方法强制开启事务查询方法设为只读以节省开销。Dao 层老项目普遍继承 HibernateDaoSupport用 HibernateTemplate 直接写 HQLpublic class EmployeeDaoImpl extends HibernateDaoSupport implements EmployeeDao { Override public void add(Employee e) { getHibernateTemplate().save(e); // 插入一条记录 } Override SuppressWarnings(unchecked) public ListEmployee listByDept(Integer deptId) { return (ListEmployee) getHibernateTemplate() .find(from Employee e where e.dept.id ? order by e.id, deptId); } }HQL 里的e.dept.id沿对象导航直接取部门主键Hibernate 会自动生成带 join 的 SQL不需要手写关联条件。find 方法的 ? 占位符从 0 下标开始传参这是 Hibernate 3/4 时代模板方法的固定惯例换成 Spring 5 的 Criteria 时要特别注意下标差异。listByDept 返回的是整个 Employee 实体如果列表页只需要姓名和部门名这种写法会多查很多列。3.3 实体映射一对多关系与懒加载的两副面孔部门与员工是一对多在 Employee 这端配置 many-to-one 即可Department 端一般只配 Set 集合。Employee.hbm.xml 的关键片段class nameEmployee tablet_employee id nameid columnemp_id generator classnative/ /id property namename columnemp_name length32 not-nulltrue/ many-to-one namedept columndept_id classDepartment lazyproxy fetchselect/ /classlazyproxy 意味着只访问 dept.id 时不会查部门表一旦 Session 关闭后去读 dept.deptName立刻抛 LazyInitializationException。fetchselect 表示查员工时部门用另一条独立 select 查出单条数据无所谓列表超过 500 行时每行多一条 SQL 就是肉眼可见的性能问题。对这种老项目列表页建议直接改成 DTO 投影查询只查表格需要的列不要把整个关联图拖出来。4. SSH 三框架协作的经典坑配置文件、jar 冲突与事务失效排查三个框架各有各的配置文件协作起来问题最多的不是业务代码而是配置之间的衔接。这一章把高频事故和排查顺序串起来讲。4.1 struts.xml 通配符与 Spring 的 bean 衔接老系统对同类的增删改查一般不会逐个写 action而是用通配符收敛成一个模板package namehrms namespace/hrms extendsstruts-default action nameemp_* classemployeeAction method{1} result namesuccess/pages/employee/success.jsp/result result nameinput/pages/employee/edit.jsp/result /action /package请求 emp_save 时{1} 被替换成 saveStruts2 调用 employeeAction 的 save() 方法。class 属性写的是 applicationContext.xml 里定义的 bean id不是完整类名这依赖 struts2-spring-plugin 去 Spring 容器里查。web.xml 里必须配 ContextLoaderListener否则 Spring 容器根本没启动Action 里的 employeeService 字段全是 null运行时报空指针而不是启动报错这是最迷惑人的表现。input 结果对应表单校验失败后的回显页面。如果 Action 的 validate() 方法里调用了 addFieldError 而没配 input 结果Struts2 会抛 no result defined for action 的异常。老源码里经常漏这个 result补上即可。4.2 事务不生效的三个高频原因第一切面没织入。tx:advice 声明了 add* 方法进事务但 Service 实现类往往不在 Spring 的组件扫描路径下或者根本没有被bean声明Spring 管理不到这个对象事务自然无从谈起。第二自调用。EmployeeServiceImpl 的 save 方法内部调了同一个类的 add 方法Spring 事务基于 JDK 动态代理内部调用绕过了代理对象切面完全感知不到。第三Session 没绑定。HibernateTemplate 依赖事务同步的 Session如果调用处在事务范围之外getHibernateTemplate().save() 会报 could not obtain transaction-synchronized Session。排查顺序建议固定为先确认 Service 实现类被 Spring 管理再看事务方法是否由外部对象调用最后检查 transactionManager 用的 sessionFactory 与 dao 注入的是不是同一个实例。三步查完绝大多数事务没生效都能定位。4.3 常见启动与运行报错速查表报错直接原因处理办法LazyInitializationExceptionSession 关闭后访问懒加载属性关掉 many-to-one 的 lazy或改用 DTO 投影ClassNotFoundException: StrutsSpringObjectFactory缺 struts2-spring-plugin 依赖补与 struts 同版本的 struts2-spring-plugin jarNoSuchMethodError: javax.persistence.*hibernate 与 jpa jar 版本错位统一 hibernate-core 与 hibernate-entitymanager 版本BeanCreationException: Cannot resolve referenceSpring 引用了不存在的 bean id检查 IDE 编译输出目录是否残留旧 class中文全是问号页面、连接、库三层字符集不一致统一 utf8检查 URL 里 characterEncodingUTF-8这类问题在 JSP 时代还有个隐藏来源lib 目录里存在两个版本的同一个 jar比如 struts2-core-2.3.16 和 struts2-core-2.3.32 同时存在。部署前先数一遍 lib 下有没有重复 jar再用jar tf struts2-core-2.3.32.jar | grep -i spring确认插件版本与主框架配套。启动日志里任何一条 ClassNotFound都要去 lib 目录反向搜一遍确认不是幽灵依赖。5. 老架构实用改造给 SSH 人事系统加 JSON 接口与迁 Spring Boot 的取舍人事系统常要对接考勤机、企业微信或别的内部系统在不重写的前提下给这套 SSH 源码加 JSON 接口是最常见的改造需求。5.1 不换框架给员工列表加 JSON 接口最省事的做法是用 struts2-json-plugin。加 jar 后在 struts.xml 里这样配置action nameapi_emp classemployeeApiAction result typejson param namerootdata/param /result /actionAction 返回 SUCCESS 后插件把 root 参数指定的 data 字段直接序列化为 JSON 输出配合类public class EmployeeApiAction extends ActionSupport { private ListEmployee data; // json 插件只序列化这个字段 public String list() { data employeeService.listAll(); return SUCCESS; } public ListEmployee getData() { return data; } }注意 json 插件默认序列化所有 getterEmployee 里的 getDept 会连带把部门对象整个拖进 JSON响应体积翻几倍。处理方式是在 dept 的 getter 上加JSON(serializefalse)排除或者单独建一个 VO 只放员工编号、姓名、部门名三个字段。这个技巧在对第三方系统开放接口时非常常用比重起一套 SpringMVC 轻量得多。5.2 保留业务代码换一套接入壳如果决定向 Spring Boot 迁移最稳妥的路线是保留 Service 和 Dao 不动只替换接入层。Struts2 的 Action 换成 RestControllerHibernate 原来的 hibernate.cfg.xml 继续留着在启动类上用 ImportResource 把原 applicationContext.xml 引入。这样业务代码改动最小风险集中在 web.xml 的监听器和过滤器迁移上。切完接入层后先跑一遍原系统的登录、增删改查用例做对比确认结果一致再考虑把 HQL 换成 JPA Criteria 或 MyBatis。对只维护不再迭代的老系统动手迁移前先评估收益接口对接量小就按 5.1 的方式加 JSON 接口完全没人维护就保持原样只补上缺失的访问日志和 SQL 慢查询日志反而是性价比最高的处理。本文还有配套的精品资源点击获取
返回列表