news 2026/9/19 14:50:24

基于SSH框架的Java固定资产管理系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于SSH框架的Java固定资产管理系统设计与实现

简介:基于Java的固定资产管理系统毕业设计文档,是一份完整的论文资料,面向计算机专业学生、毕业设计者及希望掌握SSH框架的开发者。文档以某公司固定资产管理为背景,采用浏览器/服务器模式,运用JSP、Struts、Hibernate、Spring技术栈,详细阐述了系统需求分析、架构设计、功能实现与权限管理,涵盖资产增删改查、报表打印、职工信息管理及员工权限分配等核心模块,并给出了清晰的数据库与界面设计思路。包体仅含1个doc文档,大小2.72MB,内容充实,目录结构完整,从摘要、Abstract、绪论到系统分析、详细设计等章节一应俱全,便于直接参考论文框架或提炼技术要点。目前已有45人学习,对于准备毕业设计或课程项目的读者具有较高参考价值,可帮助理解SSH整合原理、资产管理业务流程以及论文撰写规范,也能为实际信息系统开发提供切实可行的设计思路。

1. 为什么毕业设计都爱选SSH做固定资产管理

做管理系统类毕业设计时,固定资产管理是一个被反复验证过的好题目:业务边界清晰、角色分明、增删改查覆盖完整,还能带出报表和权限这类“加分项”。这个基于Java的公司固定资产管理系统,就是典型的SSH组合——JSP负责页面展示,Struts接住请求,Spring管对象,Hibernate做持久化。整套代码对初学者最友好的地方在于,它把MVC的每个环节都摆在了明面上:你在Action里写业务逻辑,在Service里调DAO,在Hibernate映射文件里定义表和对象的关系,每一步都能找到对应位置。

这套系统对应的是龙成公司的实际管理场景,资产从入库到借出、归还、维护都有记录,管理员的权限高于操作员。对于准备java毕业设计的人,它既是能直接跑的完整项目,也是一份看得懂的分层教材。适合两类人:第一是计算机专业学生,拿它理解SSH整合流程;第二是刚工作的Java工程师,想复盘传统B/S系统里数据流和控制流的组织方式。下面直接从架构选型说起。

2. 固定资产系统的SSH架构分层与B/S选型逻辑

2.1 为什么选JSP+Struts而不是Servlet

这个项目是2019年的毕业设计,但它背后的技术选型逻辑到现在仍然适用。先用一张图理解请求流转路径:浏览器发出HTTP请求,Tomcat根据web.xml把请求交给Struts的ActionServlet,ActionServlet读取struts-config.xml找到对应Action,Action调用Spring管理的Service,Service调用Hibernate的DAO接口,最终通过Hibernate模板操作MySQL数据库。数据返回时逆向走一遍,JSP负责渲染。

相比直接写Servlet,Struts的核心价值在于把请求分发和业务逻辑解耦。比如资产查询和资产删除是两个不同的Action,但它们的公共逻辑,比如字符编码过滤、权限校验,可以在Struts的拦截器或过滤器里集中处理。实际开发中,我一般会建议在Action里只做参数收集和视图跳转,真正的业务判断放到Service层,这样便于用Spring的AOP做事务控制。

代码层面的跳转配置如下:

<action path="/asset/add" type="com.company.sshaction.AssetAction" name="assetForm" scope="request" validate="true" parameter="method"> <forward name="success" path="/asset/list.jsp"/> <forward name="error" path="/asset/add.jsp"/> </action>

参数说明:path是浏览器访问的URL路径;type是对应的Action全类名;name引用表单Bean,Struts会自动把请求参数封装进AssetForm对象;parameter="method"是常用的DispatchAction技巧,同一个Action类可以通过?method=add?method=delete调用不同方法,减少Action类的数量。

2.2 Spring在系统中的角色:不只是粘合剂

很多人初学SSH时会把Spring当成一个“注册中心”,其实它在固定资产系统里承担了三件事:依赖注入、事务管理和AOP权限校验。比如资产借出时需要同时更新资产状态表和新增借还记录,这两步要么都成功要么都回滚,Spring声明式事务就能保证:

<bean id="assetService" class="com.company.service.AssetService"> <property name="assetDao" ref="assetDao"/> <property name="borrowDao" ref="borrowDao"/> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <aop:config> <aop:pointcut id="serviceMethods" expression="execution(* com.company.service.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/> </aop:config>

这里有个关键点:AssetService里同时注入了assetDaoborrowDao,事务切面拦截所有com.company.service包下的方法。当一个Service方法内部多次调用DAO时,它们共享同一个数据库连接,如果中间抛出运行时异常,事务自动回滚,不需要手写try-catch

2.3 Hibernate映射文件的设计细节

资产表和员工表是Hibernate的核心映射对象。早期SSH项目习惯用.hbm.xml文件而不是注解,因为这种方式可以更精细地控制字段类型和关联关系。看资产表的一个映射片段:

<class name="com.company.entity.Asset" table="t_asset"> <id name="id" type="java.lang.Integer"> <column name="id"/> <generator class="native"/> </id> <property name="assetNo" type="java.lang.String"> <column name="asset_no" length="50" not-null="true"/> </property> <property name="assetName" type="java.lang.String"> <column name="asset_name" length="100" not-null="true"/> </property> <property name="status" type="java.lang.Integer"> <column name="status"/> </property> <!-- status字段含义:0=在库,1=已借出,2=维修中,3=报废 --> <many-to-one name="employee" class="com.company.entity.Employee" fetch="select"> <column name="employee_id"/> </many-to-one> </class>

映射文件里最容易被忽略的是many-to-one关系。资产表通过employee_id外键关联员工表,表示“当前保管人”。实际查询时,如果直接访问asset.getEmployee().getName()会触发Hibernate的懒加载,在Session关闭后报LazyInitializationException。解决办法是在Service层内把需要展示的数据查询完成,或者将关联对象设为fetch="join",这要根据业务场景权衡。

3. 数据库设计与核心功能模块实现

3.1 数据表结构设计要点

固定资产管理的数据模型并不复杂,但表之间的关系值得拆解。从论文中的功能描述看,系统至少需要五张核心表:用户表、员工表、资产表、资产借还表、资产维护表。下面给出资产和借还表的基本设计:

字段名类型约束说明
idint主键,自增资产ID
asset_novarchar(50)非空,唯一资产编号
asset_namevarchar(100)非空资产名称
categoryvarchar(50)可空资产分类,如电子设备、家具
pricedecimal(10,2)非空资产原值
statusint默认00在库 1借出 2维修 3报废
employee_idint外键当前保管人ID
buy_datedatetime可空购入日期
remarkvarchar(255)可空备注

注意status字段设计了枚举值,查询时不需要关联表就能知道资产状态。asset_no加唯一约束可以防止重复录入。员工表和用户表是分离的,用户表存登录账号密码和角色,员工表存姓名、部门等基本信息,这种设计保证了操作员账号被删除时员工历史记录仍保留。

3.2 资产录入的Action实现流程

资产入库是整个系统的操作入口。前端JSP表单通过AssetForm收集参数,Struts负责参数校验,校验通过后交给Service。看一个简化的Action方法:

public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { AssetForm assetForm = (AssetForm) form; Asset asset = new Asset(); asset.setAssetNo(assetForm.getAssetNo()); asset.setAssetName(assetForm.getAssetName()); asset.setCategory(assetForm.getCategory()); asset.setStatus(0); // 新入库资产默认在库 // 用SimpleDateFormat处理日期字符串,避免中文环境下的格式问题 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { asset.setBuyDate(sdf.parse(assetForm.getBuyDate())); } catch (ParseException e) { e.printStackTrace(); return mapping.findForward("error"); } // 保存人从Session中获取,保证操作可追溯 User operator = (User) request.getSession().getAttribute("currentUser"); asset.setCreateUser(operator.getUsername()); assetService.addAsset(asset); return mapping.findForward("success"); }

这段代码里有两个工程习惯值得学习:一是保存操作人信息到数据表而不是只靠日志,后续审计时能直接从数据库查出谁在什么时间录入了哪些资产;二是日期解析单独处理,Hibernate的日期类型与MySQL的datetime字段对应时容易产生时区偏移,统一使用SimpleDateFormat并明确格式可以减少这类问题。实际项目中,AssetForm里还应该加ActionErrors做必填项校验,比如资产编号为空时返回错误信息而不进入Service层。

3.3 管理员与操作员的权限控制

论文中提到“操作员只可对资产和用户进行基本操作,管理员可以为每位员工赋权限”,这就是典型的基于角色的访问控制。Struts中实现权限控制有两种常见做法:在Action执行前用Servlet过滤器拦截,或者在Spring的AOP里做方法级拦截。

更推荐的是在Struts的RequestProcessor里做统一校验,这样不需要在每个Action中重复写权限判断逻辑:

public class SecurityProcessor extends RequestProcessor { @Override protected boolean processPreprocess(HttpServletRequest request, HttpServletResponse response) { String path = request.getServletPath(); // 登录和公共页面直接放行 if ("/login.jsp".equals(path) || "/login.do".equals(path)) { return true; } HttpSession session = request.getSession(); User user = (User) session.getAttribute("currentUser"); if (user == null) { try { response.sendRedirect(request.getContextPath() + "/login.jsp"); } catch (IOException e) { e.printStackTrace(); } return false; } // 管理员角色可以访问以manage开头的路径 if ("/manage_".contains(path) && !"admin".equals(user.getRole())) { try { response.sendRedirect(request.getContextPath() + "/error.jsp"); } catch (IOException e) { e.printStackTrace(); } return false; } return true; } }

注意这个类实现的processPreprocess是Struts1.2之后提供的方法,相比直接继承ActionServlet,它更轻量。配置时需要在struts-config.xml里替换controller属性:

<controller processorClass="com.company.security.SecurityProcessor"/>

这样做的好处是权限逻辑集中且可测试。如果项目里再引入Spring Security,思路也是类似的:定义资源与角色的映射关系,在请求进入控制器之前完成认证和授权。

4. 资产借还、报表打印与中文乱码实战

4.1 借出与归还的状态管理

资产借还模块最容易出现的数据问题是不一致:资产记录显示在库,但借还表里没有对应记录。为了避免这种情况,借出操作必须在一个事务里完成两件事:插入一条借还记录,同时更新资产表的statusemployee_id。对应的Service方法:

public void borrowAsset(Integer assetId, Integer employeeId, Date borrowDate) { Asset asset = assetDao.findById(assetId); // 校验资产当前状态,已借出或维修中的资产不能再借 if (asset == null || asset.getStatus() != 0) { throw new BusinessException("资产不存在或当前状态不可借出"); } BorrowRecord record = new BorrowRecord(); record.setAsset(asset); record.setEmployee(employeeDao.findById(employeeId)); record.setBorrowDate(borrowDate); borrowDao.save(record); asset.setStatus(1); asset.setEmployee(employeeDao.findById(employeeId)); assetDao.update(asset); }

这里有一个容易被忽略的坑:asset是Hibernate的持久化对象,在事务内修改它的属性后,即使不显式调用update,事务提交时也会自动更新数据库。但为了明确表达意图,代码里还是保留了assetDao.update(asset)。借出时校验状态是必须的,如果不校验,同一台设备可能被借给两个人。

HQL查询借出记录时,我一般使用以下写法:

String hql = "from BorrowRecord r where r.returnDate is null"; Query query = session.createQuery(hql); List<BorrowRecord> list = query.list();

这个HQL只查询尚未归还的借出记录。returnDate为空表示还在借出状态,这是最直观的状态标记。实际运行中要注意HQL中的类名和属性名大小写,BorrowRecord对应Java类名,returnDate对应属性名而不是数据库的return_date列名,写错会直接抛QuerySyntaxException

4.2 使用JavaReport生成打印报表

论文中提到的外部包JavaReport-V3-Enterprise-Released.jar是当时的报表组件。打印报表的流程可以拆成四个步骤:从数据库查出要打印的数据集合,把数据填充到报表模板,设置输出格式,最后通过Response输出流写回浏览器。

public void printAssetList(HttpServletRequest request, HttpServletResponse response) { List<Asset> assets = assetService.findAllAssets(); request.setAttribute("assets", assets); // 报表组件通过JSON或XML接收数据,这里用字符串拼接简化 StringBuilder json = new StringBuilder(); json.append("["); for (Asset a : assets) { json.append(String.format( "{\"assetNo\":\"%s\",\"assetName\":\"%s\",\"price\":\"%.2f\",\"status\":\"%s\"},", a.getAssetNo(), a.getAssetName(), a.getPrice(), a.getStatus())); } if (assets.size() > 0) { json.deleteCharAt(json.length() - 1); } json.append("]"); // 转换JSON为报表组件需要的DTO response.setContentType("application/pdf"); response.setCharacterEncoding("UTF-8"); // 调用JavaReport的ReportManager输出PDF // ReportManager.createReport(json.toString()).exportPDF(response.getOutputStream()); }

实际项目中不建议手写JSON,可以用fastjsonGson替代。报表打印的注意点在于中文显示,PDF报表引擎默认字体可能不支持中文,需要在报表模板或代码里指定中文字体,比如STSong-Light,否则导出的PDF中文会是乱码或方块。

4.3 中文乱码的三层过滤方案

中文乱码是所有老Java Web项目绕不开的话题,这个系统也不例外。乱码会产生在三个位置:页面显示乱码、请求参数乱码、数据库存储乱码。工程上常用的做法是统一编码为UTF-8。

第一层,在JSP页面顶部声明:

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

第二层,使用过滤器统一处理POST请求编码:

public class EncodingFilter implements Filter { private String encoding = "UTF-8"; @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); response.setCharacterEncoding(encoding); chain.doFilter(request, response); } }

第三层,修改MySQL连接URL和环境变量,这是最容易被忽略的环节:

jdbc:mysql://localhost:3306/assetdb?useUnicode=true&characterEncoding=UTF-8

useUnicode=truecharacterEncoding=UTF-8必须同时出现,否则Hibernate连接MySQL时中文写入会变??。另外,如果使用的是MySQL 5.7及以上版本,还需要在my.ini中设置character-set-server=utf8mb4,因为utf8mb4才是完整的四字节UTF-8支持。

5. 从论文到可演示系统:复现与答辩的实操技巧

5.1 将MyEclipse项目迁移到IDEA

论文指定的开发环境是MyEclipse 8.0和Tomcat 6.0,如果你现在打开这个项目,很可能会遇到编译不兼容的问题。我的建议是迁移到IntelliJ IDEA和Tomcat 8.5以上版本。迁移时重点检查三处:项目结构是否为src/main/java布局;.classpath中是否残留MyEclipse的容器引用;web.xml中servlet版本是否与Tomcat匹配。Struts1和Spring3在Tomcat 8上运行没有问题,但要注意删除xercesImpl.jar这类可能引起冲突的XML解析包。

5.2 功能测试的关键数据准备

测试这个系统时不要只登录管理员账号随便点两下。建议按照真实流程准备三组数据:第一组是正常数据,比如“笔记本-001”从入库到借出再到归还;第二组是边界数据,比如资产编号为空、价格超过百万、员工姓名为生僻字;第三组是异常操作,比如重复删除已报废资产、操作员尝试访问管理员页面。验收时重点观察三件事:操作是否产生预期记录、借出后资产状态是否变化、错误提示是否清晰定位到具体字段。

5.3 答辩时把三个技术点讲透

面试官或答辩老师通常不会只问“你做的是什么”,而是追问“为什么这么设计”。这个固定资产系统有三个技术点可以提前准备。

第一个是Hibernate的一级缓存和懒加载。回答时要说到Session范围内的缓存机制,以及打开懒加载后Session关闭导致LazyInitializationException的解决方案。

第二个是Spring的事务管理粒度问题。你可以在答辩时说:不是所有方法都需要事务,查询方法设置只读事务readOnly=true可以提升性能,而borrowAsset这样涉及两次写操作的方法必须开启默认的REQUIRED传播行为。

第三个是权限控制的边界。只在前端隐藏“管理员管理”按钮是不够的,因为请求还是可以直接发到后台。你的SecurityProcessor在服务端做了二次校验,这才是安全的做法。把这一点讲清楚,整个项目的技术深度会立刻提升一个档次。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 14:50:01

QT 串口助手从零开发:QSerialPort 收发、HEX 与打包发布

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 14:46:48

ROS机器人平台搭建:从一键安装到工程交付的6道硬坎

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 14:44:13

Multisim单相半波可控整流仿真:从原理到波形分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/19 14:37:38

Dynamics CRM零售分销解决方案:数据模型、订单流转与权限性能

简介&#xff1a;面向零售分销行业管理者、业务负责人及客户关系管理实施顾问的解决方案文档&#xff0c;聚焦传统分销费用高、网络零售冲击、渠道管控难等行业痛点。内容从行业现状与挑战切入&#xff0c;详细梳理渠道进销存管理、客户拜访、会员管理、促销管理、报表分析、全…

作者头像 李华
网站建设 2026/9/19 14:37:30

从程序员到高级技师:计算机程序设计员职业标准与技能等级指南

简介&#xff1a;计算机程序设计员&#xff08;师&#xff09;国家职业标准是一份权威的职业技能认定参考文档&#xff0c;面向从事或准备从事软件编制与设计工作的人员&#xff0c;以及职业院校师生、培训机构和人力资源管理者。内容围绕程序员、高级程序员、程序设计师三个等…

作者头像 李华