基于SSM框架的企业资产信息管理系统 - 源码深度解析

JavaJavaScriptMavenHTMLCSSSSM框架MySQL
2026-02-254 浏览

文章摘要

本项目是一款基于SSM(Spring+SpringMVC+MyBatis)框架构建的企业资产信息管理系统,旨在帮助企业实现资产全生命周期的数字化、规范化管理。系统核心解决了传统资产管理中信息孤立、盘点效率低下、状态更新不及时等痛点,通过集中化的信息平台,将资产采购、入库、领用、维修、报废等环节串联起...

在企业数字化转型的浪潮中,资产管理作为企业运营的核心环节,其信息化水平直接关系到资源利用效率和成本控制能力。传统依赖纸质台账或零散电子表格的管理方式,普遍存在数据更新滞后、信息孤岛、盘点工作繁重等痛点,难以满足现代企业精细化管理的要求。针对这一市场需求,开发了一套基于SSM(Spring + SpringMVC + MyBatis)架构的企业级资产信息管理平台,旨在实现资产从采购、入库、领用、维修到报废的全生命周期数字化管控。

该平台采用经典的三层架构设计,确保了系统的高内聚、低耦合。表现层由SpringMVC框架负责,通过@Controller注解定义请求处理器,并利用@RequestMapping映射HTTP请求路径。SpringMVC的核心调度器DispatcherServlet统一拦截请求,经由处理器映射器、适配器最终调用业务逻辑,处理完成后通过视图解析器渲染视图或直接返回JSON数据。为了提供RESTful风格的API接口,控制器方法广泛使用@ResponseBody注解,结合Jackson库实现Java对象与JSON格式数据的自动序列化与反序列化。

业务逻辑层由Spring框架的IoC(控制反转)容器托管。各类业务服务(Service)组件以@Service注解标识,通过@Autowired注解实现依赖注入,从而解耦组件间的依赖关系。对于资产转移、状态变更等关键操作,系统采用Spring的声明式事务管理,使用@Transactional注解确保数据库操作的原子性和一致性。数据持久层则基于MyBatis框架构建,通过Mapper接口与XML映射文件将Java对象与数据库表进行灵活映射。MyBatis的动态SQL功能(如<if>, <choose>, <foreach>等标签)有效支持了资产多条件组合查询等复杂场景。

数据库选用MySQL,其事务特性(ACID)保证了资产流水记录等核心数据的完整性。围绕资产管理的核心业务域,数据库设计了11张主要数据表,包括资产主表、资产分类表、部门表、员工表、供应商表、资产流水表等,通过外键约束维护数据间的关联完整性。

数据库设计亮点解析

数据库设计是系统稳定性的基石。以下重点分析几个核心表的结构设计。

1. 资产主表 (asset) 该表记录了企业所有资产的核心静态信息,是系统最重要的数据实体。其设计不仅包含了资产的基本属性,还通过外键关联了分类、部门、存放地等信息,确保了数据的规范性与可查询性。

CREATE TABLE `asset` (
  `asset_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '资产ID',
  `asset_name` varchar(255) NOT NULL COMMENT '资产名称',
  `asset_category_id` int(11) NOT NULL COMMENT '资产分类ID',
  `specification` varchar(500) DEFAULT NULL COMMENT '规格型号',
  `sn` varchar(100) DEFAULT NULL COMMENT '序列号/唯一标识',
  `department_id` int(11) NOT NULL COMMENT '所属部门ID',
  `custodian` varchar(100) DEFAULT NULL COMMENT '保管人',
  `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '资产状态(1:在库,2:在用,3:维修中,4:待报废,5:已报废)',
  `purchase_date` date DEFAULT NULL COMMENT '购置日期',
  `purchase_price` decimal(15,2) DEFAULT NULL COMMENT '购置金额',
  `warehouse_id` int(11) DEFAULT NULL COMMENT '仓库ID',
  `location` varchar(200) DEFAULT NULL COMMENT '具体位置',
  `notes` text COMMENT '备注',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`asset_id`),
  KEY `idx_category` (`asset_category_id`),
  KEY `idx_department` (`department_id`),
  KEY `idx_status` (`status`),
  KEY `idx_sn` (`sn`),
  CONSTRAINT `fk_asset_category` FOREIGN KEY (`asset_category_id`) REFERENCES `asset_category` (`category_id`),
  CONSTRAINT `fk_asset_department` FOREIGN KEY (`department_id`) REFERENCES `department` (`department_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产主表';

设计亮点:

  • 状态字段枚举化status字段使用TINYINT类型,并预定义状态值(1-5),代码层面可通过枚举类进行映射,使状态管理清晰且易于扩展。
  • 唯一标识索引:对序列号(sn)建立唯一索引(idx_sn),确保资产标识的唯一性,并提升基于序列号的查询效率。
  • 审计字段create_timeupdate_time字段自动记录数据的创建和更新时间,便于追踪数据变更历史。
  • 外键约束:通过外键约束(fk_asset_category, fk_asset_department)强制保证分类和部门ID的引用完整性,避免脏数据。

2. 资产流水表 (asset_flow) 此表用于记录资产每一次关键状态变更的流水,是实现资产全生命周期追踪的核心。其设计采用了类似日志表的结构,记录了操作前后状态的变化。

CREATE TABLE `asset_flow` (
  `flow_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '流水ID',
  `asset_id` int(11) NOT NULL COMMENT '资产ID',
  `operation_type` tinyint(4) NOT NULL COMMENT '操作类型(1:入库,2:领用,3:退库,4:维修,5:报废,...)',
  `operator_id` int(11) NOT NULL COMMENT '操作人ID',
  `operate_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
  `previous_status` tinyint(4) DEFAULT NULL COMMENT '操作前状态',
  `current_status` tinyint(4) DEFAULT NULL COMMENT '操作后状态',
  `previous_department_id` int(11) DEFAULT NULL COMMENT '操作前部门',
  `current_department_id` int(11) DEFAULT NULL COMMENT '操作后部门',
  `previous_custodian` varchar(100) DEFAULT NULL COMMENT '操作前保管人',
  `current_custodian` varchar(100) DEFAULT NULL COMMENT '操作后保管人',
  `notes` varchar(500) DEFAULT NULL COMMENT '操作备注',
  PRIMARY KEY (`flow_id`),
  KEY `idx_asset_id` (`asset_id`),
  KEY `idx_operate_time` (`operate_time`),
  CONSTRAINT `fk_flow_asset` FOREIGN KEY (`asset_id`) REFERENCES `asset` (`asset_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='资产流水表';

设计亮点:

  • 全量变更追踪:通过previous_*current_*系列字段,精确记录了资产关键属性(状态、部门、保管人)在每次操作前后的变化,为审计和追溯提供了完整数据链。
  • 操作类型枚举operation_type字段定义了资产生命周期的所有关键事件,使得流水记录语义清晰。
  • 复合索引策略:对asset_idoperate_time分别建立索引,能够高效支持“查询某个资产的所有历史记录”和“按时间范围查询所有操作流水”这两种典型查询场景。

核心功能实现与代码解析

1. 资产多条件动态查询

资产查询是管理员最高频的操作之一,需要支持根据资产名称、分类、状态、部门等多个条件的灵活组合查询。后端通过MyBatis的动态SQL功能实现这一复杂查询逻辑。

Mapper接口定义:

public interface AssetMapper {
    List<AssetVO> selectAssetByCondition(AssetQueryDTO queryDTO);
    long countAssetByCondition(AssetQueryDTO queryDTO);
}

对应的XML映射文件片段:

<!-- 资产查询结果映射 -->
<resultMap id="AssetVOResultMap" type="com.example.vo.AssetVO">
    <id column="asset_id" property="assetId"/>
    <result column="asset_name" property="assetName"/>
    <result column="specification" property="specification"/>
    <!-- 关联查询部门名称、分类名称等 -->
    <result column="department_name" property="departmentName"/>
    <result column="category_name" property="categoryName"/>
</resultMap>

<!-- 动态查询SQL -->
<select id="selectAssetByCondition" resultMap="AssetVOResultMap">
    SELECT 
        a.asset_id, a.asset_name, a.specification, a.sn, a.status,
        a.purchase_date, a.purchase_price, a.custodian, a.location,
        d.department_name, ac.category_name
    FROM asset a
    LEFT JOIN department d ON a.department_id = d.department_id
    LEFT JOIN asset_category ac ON a.asset_category_id = ac.category_id
    <where>
        <if test="assetName != null and assetName != ''">
            AND a.asset_name LIKE CONCAT('%', #{assetName}, '%')
        </if>
        <if test="categoryId != null">
            AND a.asset_category_id = #{categoryId}
        </if>
        <if test="status != null">
            AND a.status = #{status}
        </if>
        <if test="departmentId != null">
            AND a.department_id = #{departmentId}
        </if>
        <if test="custodian != null and custodian != ''">
            AND a.custodian LIKE CONCAT('%', #{custodian}, '%')
        </if>
        <if test="sn != null and sn != ''">
            AND a.sn = #{sn}
        </if>
    </where>
    ORDER BY a.update_time DESC
    <if test="offset != null and limit != null">
        LIMIT #{offset}, #{limit}
    </if>
</select>

Controller层处理分页请求:

@RestController
@RequestMapping("/api/asset")
public class AssetController {

    @Autowired
    private AssetService assetService;

    @GetMapping("/list")
    public PageResult<AssetVO> getAssetList(AssetQueryDTO queryDTO) {
        // 查询总记录数
        long total = assetService.countAssetByCondition(queryDTO);
        // 查询当前页数据
        List<AssetVO> records = assetService.selectAssetByCondition(queryDTO);
        return new PageResult<>(total, records);
    }
}

此功能通过AssetQueryDTO对象封装前端传递的查询参数,MyBatis的<where><if>标签会根据参数是否为null或空字符串来动态拼接SQL的WHERE条件,避免了字符串拼接带来的SQL注入风险和代码冗余。同时,通过LEFT JOIN关联查询出部门名称、分类名称等扩展信息,避免在VO对象中多次查询关联表,提升了查询效率。前端页面呈现效果如图:

资产查询与管理界面

2. 资产领用与状态变更事务处理

资产领用是核心业务流程,涉及资产状态的更新和流水记录的插入,必须在一个事务中完成,以保证数据一致性。

Service层业务逻辑:

@Service
public class AssetServiceImpl implements AssetService {

    @Autowired
    private AssetMapper assetMapper;
    
    @Autowired
    private AssetFlowMapper assetFlowMapper;

    @Override
    @Transactional(rollbackFor = Exception.class) // 声明式事务管理
    public boolean borrowAsset(AssetBorrowDTO borrowDTO) {
        // 1. 根据ID查询资产当前信息
        Asset asset = assetMapper.selectById(borrowDTO.getAssetId());
        if (asset == null) {
            throw new BusinessException("资产不存在");
        }
        if (asset.getStatus() != AssetStatus.IN_STOCK.getCode()) {
            throw new BusinessException("资产当前状态不可领用");
        }

        // 2. 更新资产状态、保管人、部门等信息
        asset.setStatus(AssetStatus.IN_USE.getCode());
        asset.setCustodian(borrowDTO.getBorrowerName());
        asset.setDepartmentId(borrowDTO.getDepartmentId());
        asset.setUpdateTime(new Date());
        int updateCount = assetMapper.update(asset);
        if (updateCount <= 0) {
            throw new BusinessException("更新资产信息失败");
        }

        // 3. 记录资产流水
        AssetFlow flow = new AssetFlow();
        flow.setAssetId(borrowDTO.getAssetId());
        flow.setOperationType(FlowOperationType.BORROW.getCode());
        flow.setOperatorId(borrowDTO.getOperatorId());
        flow.setOperateTime(new Date());
        flow.setPreviousStatus(AssetStatus.IN_STOCK.getCode());
        flow.setCurrentStatus(AssetStatus.IN_USE.getCode());
        flow.setPreviousDepartmentId(asset.getDepartmentId()); // 记录原部门
        flow.setCurrentDepartmentId(borrowDTO.getDepartmentId());
        flow.setPreviousCustodian(asset.getCustodian());
        flow.setCurrentCustodian(borrowDTO.getBorrowerName());
        flow.setNotes(borrowDTO.getNotes());

        int insertCount = assetFlowMapper.insert(flow);
        if (insertCount <= 0) {
            throw new BusinessException("记录操作流水失败");
        }

        return true;
    }
}

此段代码展示了Spring声明式事务的典型应用。@Transactional注解确保borrowAsset方法中的所有数据库操作(更新资产表和插入流水表)要么全部成功,要么在发生异常时全部回滚。这种设计有效防止了资产状态已更新但流水记录未生成的数据不一致情况。业务逻辑中包含了必要的校验,如资产存在性检查和状态验证,确保了业务的严谨性。前端领用申请界面如下:

资产领用管理界面

3. 供应商管理与数据交互

供应商信息是资产采购环节的重要基础数据。系统提供了供应商信息的增删改查功能,并通过RESTful API与前端交互。

Controller层实现供应商CRUD操作:

@RestController
@RequestMapping("/api/supplier")
public class SupplierController {

    @Autowired
    private SupplierService supplierService;

    @PostMapping
    public ResponseEntity<Void> addSupplier(@RequestBody @Valid SupplierDTO supplierDTO) {
        supplierService.addSupplier(supplierDTO);
        return ResponseEntity.ok().build();
    }

    @PutMapping("/{id}")
    public ResponseEntity<Void> updateSupplier(@PathVariable Long id, @RequestBody @Valid SupplierDTO supplierDTO) {
        supplierDTO.setSupplierId(id);
        supplierService.updateSupplier(supplierDTO);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/{id}")
    public ResponseEntity<SupplierVO> getSupplierById(@PathVariable Long id) {
        SupplierVO supplier = supplierService.getSupplierById(id);
        return ResponseEntity.ok(supplier);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteSupplier(@PathVariable Long id) {
        supplierService.deleteSupplier(id);
        return ResponseEntity.ok().build();
    }
}

Service层参数校验与业务处理:

@Service
public class SupplierServiceImpl implements SupplierService {

    @Autowired
    private SupplierMapper supplierMapper;

    @Override
    public void addSupplier(SupplierDTO supplierDTO) {
        // 检查供应商名称是否已存在
        Supplier existing = supplierMapper.selectByName(supplierDTO.getSupplierName());
        if (existing != null) {
            throw new BusinessException("供应商名称已存在");
        }

        Supplier supplier = new Supplier();
        BeanUtils.copyProperties(supplierDTO, supplier);
        supplier.setCreateTime(new Date());
        supplier.setUpdateTime(new Date());
        
        supplierMapper.insert(supplier);
    }
}

该模块使用了SpringMVC的注解驱动开发模式。@RestController组合了@Controller@ResponseBody,使得每个方法返回值直接序列化为JSON响应体。@PathVariable用于获取URL路径中的参数,@RequestBody将请求体中的JSON数据绑定到Java对象。@Valid注解触发了对SupplierDTO中JSR-303校验注解(如@NotBlank, @Email等)的验证,保证了输入数据的有效性。供应商管理界面提供了清晰的信息维护入口:

供应商管理界面

4. 用户登录与权限控制

系统通过基于Session的拦截器实现了简单的权限控制,确保用户只能访问其授权范围内的功能。

登录认证逻辑:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User login(String username, String password) {
        User user = userMapper.selectByUsername(username);
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        }
        
        // 密码加密比对(实际项目中应使用BCrypt等安全哈希算法)
        String encryptedPassword = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!encryptedPassword.equals(user.getPassword())) {
            throw new BusinessException("用户名或密码错误");
        }
        
        if (user.getStatus() != 1) {
            throw new BusinessException("账户已被禁用,请联系管理员");
        }
        
        return user;
    }
}

权限拦截器实现:

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 检查登录状态
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("currentUser");
        
        if (user == null) {
            // 未登录,返回错误或重定向到登录页
            response.sendRedirect("/login.html");
            return false;
        }
        
        // 简单的角色权限检查(可根据URL和用户角色进行更精细的控制)
        String requestURI = request.getRequestURI();
        if (requestURI.startsWith("/admin/") && user.getRole() != UserRole.ADMIN) {
            throw new BusinessException("权限不足");
        }
        
        return true;
    }
}

此认证机制通过拦截器检查Session中是否存在用户信息来判断登录状态。对于管理员路径(/admin/)的访问,会进一步校验用户角色。虽然这是一个相对简单的实现,但为系统提供了基础的安全保障。登录界面是系统入口:

用户登录界面

实体模型与

本文关键词
SSM框架企业资产信息管理系统源码解析SpringMVCMyBatis

上下篇

上一篇
没有更多文章
下一篇
没有更多文章