news 2026/8/31 6:39:31

SSM框架毕设实战:从零搭建资产评估业务管理系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SSM框架毕设实战:从零搭建资产评估业务管理系统

先问一个很现实的问题:毕设选题时,你是不是也在“网上找现成源码”和“自己从零写系统”之间反复横跳?下载过压缩包的同学应该都有体会——十个压缩包里有五六个缺数据库,两三个缺依赖,剩下的几个能跑起来,但答辩时老师一问“这个表为什么这么设计”“事务为什么放在 Service 层”,你当场就愣住了。

这篇文章不套理论,直接围绕一个非常典型的计算机毕设题目——基于 SSM 框架的资产评估业务管理系统的设计与实现,拆成四块来写:第一,这个选题为什么适合做毕设,SSM 框架在 2025 年的今天还有没有学习的必要;第二,资产评估系统的需求、功能模块和数据库表应该怎么设计;第三,从 Maven 搭建、建表 SQL、实体类到 Controller、Service、Mapper 的完整代码实现思路;第四,运行验证、常见报错排查,以及答辩时老师最可能追问哪些点。

读完以后,你不仅能把这套系统改写成自己的项目,还能从根本上理解 SSM 项目“配置在哪里、请求怎么走、事务怎么管”,而不是停留在“能跑就行”的层次。

1. 选题的技术判断:为什么毕设选 SSM + 资产评估

1.1 一个很现实的问题:毕设要不要盲目追新

打开招聘网站,Java 岗位几乎都在提 Spring Boot、Spring Cloud、微服务。于是很多同学做毕设时也跟风上 Spring Cloud Alibaba,项目里堆了 Nacos、Gateway、OpenFeign,看起来技术栈很“高大上”。但这里有一个致命问题:毕业设计考核的是“你是不是真的理解你写的东西”,而不是“你用了多少新技术名词”。

Spring Cloud 全家桶牵涉到服务注册、配置中心、负载均衡、分布式事务,如果你本身对这些概念只停留在“会用注解”的层面,答辩时反而容易露馅。老师追问某个组件原理,你只能拿“这是现成框架”来回答,分数很难高。

相比之下,SSM(Spring + SpringMVC + MyBatis)虽然看起来“老”,但它恰好覆盖了 Java 后端最核心的三块基本功:Spring 的 IOC 和 AOP、SpringMVC 的请求处理流程、MyBatis 的 JDBC 封装和 SQL 控制。这三样东西理解透了,之后学 Spring Boot 几乎是降维打击。

所以我的判断很明确:如果你的毕设选题范围里允许用 SSM,它反而是最稳妥、最能体现技术水平的选择。

1.2 资产评估业务为什么适合做系统

毕设选题还有一个常见误区:要么选“学生管理系统”“图书管理系统”这种过于简单的题目,容易撞题,且设计深度不足;要么选“电商系统”“社交平台”这种覆盖面过大的题目,结果需求膨胀,三个月做不完。

资产评估系统刚好卡在一个非常合适的位置。

从业务难度看,它比“学生管理系统”多了一层专业业务逻辑,比如评估基准日、评估目的、评估方法、成本法与收益法计算;但比电商系统简单得多,没有复杂的支付、库存、秒杀逻辑。从技术考点看,它天然需要多表关联、状态流转、增删改查、权限控制、数据统计,这些恰好是 SSM 项目能够完整展示的能力。

资产评估是财务、金融、工程领域里非常常见的业务。比如设备要入账、房产要抵押、公司要合并,都需要专业评估机构出具评估报告。在这个系统里,你的角色是做一个“评估业务管理后台”,管理评估项目从委托、立项、测算、出报告到归档的全过程。

听起来很专业,但实现起来并不困难。它给你带来的收益是:论文的需求分析、业务流程、数据库设计部分都有真实素材可写,不会出现“为了凑字数硬编需求”的尴尬。

1.3 SSM 框架在毕设场景下的真实定位

很多同学焦虑:我现在学 SSM 是不是浪费时间?以后公司都用 Spring Boot 怎么办?

这里要分清“学习阶段”和“工程阶段”。Spring Boot 确实把大量配置自动化了,嵌入式 Tomcat、自动装配、Starter 依赖都极大提高了开发效率。但也正因为如此,很多人学完 Spring Boot 后反而对底层运行机制一知半解——不知道 servlet 容器是怎么启动的,不知道 Bean 是怎么被创建出来的,不知道 SQL 是怎么执行和提交事务的。

SSM 的价值在于它“手工感”很强。你需要自己写web.xml,自己配置DispatcherServlet,自己声明SqlSessionFactory,自己控制事务边界。这个过程虽然繁琐,但逼着你把 Java Web 的关键机制过一遍。

换个角度说:SSM 是理解 Java Web 演进历史的中间站,从 JSP + Servlet 原始写法到 SSM,再到 Spring Boot,层层递进。如果以后想深入 Spring Boot 源码,SSM 的基础会帮上大忙。

2. SSM 框架核心概念与原理

2.1 Spring:理解 IOC 是答辩的第一道题

Spring 最核心的两个概念是 IOC(控制反转)和 AOP(面向切面)。

IOC 通俗解释:以前你要用对象,就得自己new,比如在 Service 里 new 一个 Mapper 实现类。对象之间的依赖关系写死在代码里,耦合度很高。用了 Spring 之后,对象创建和依赖注入都交给 Spring 容器管理,你在代码里只需要声明“我需要一个什么样的对象”,容器会把创建好的实例给你。

代码层面最常见的表现就是@Autowired

@Autowired private AssessmentProjectMapper projectMapper;

这里你并没有写new AssessmentProjectMapper(),但 Spring 容器会扫描接口、创建代理对象、注入到当前类中。答辩时老师问“IOC 是什么”,你如果能从“对象创建权交给容器”和“降低耦合度”两个角度回答,基本就过关了。

AOP 通俗解释:把日志、事务、权限这类横切逻辑从业务代码中抽出去。最典型的场景是事务——你不想在每个业务方法里手动写connection.begin()connection.commit(),于是用一个事务管理器统一处理。

2.2 SpringMVC:一次请求如何走到业务方法

SpringMVC 的核心是前端控制器DispatcherServlet。一个 HTTP 请求的典型路径如下:

  1. 浏览器发送请求到DispatcherServlet
  2. DispatcherServlet根据 URL 找到对应的HandlerMapping,确定该请求由哪个 Controller 方法处理。
  3. 调用 Controller 方法,方法参数由 SpringMVC 自动绑定,比如表单参数、JSON 数据。
  4. Controller 处理完业务后返回逻辑视图名或数据。
  5. ViewResolver把逻辑视图名解析成物理视图,比如 JSP 页面。
  6. 把响应发送回浏览器。

SSM 项目里那些看起来不起眼的注解,背后都对应这一套流程。比如@Controller标记一个类能接收请求,@RequestMapping映射 URL,@PathVariable从路径中取值。

2.3 MyBatis:SQL 由你掌控

MyBatis 是一个“半自动”的 ORM 框架。为什么说半自动?因为连接管理、参数绑定、结果集映射这些框架帮你做了,但SQL 语句本身需要你自己写,写在 Mapper XML 文件或注解中。

这让它和 Hibernate/JPA 这类“全自动”框架形成鲜明对比。全自动框架可以自动生成 SQL,但遇到复杂多表查询、动态条件查询时,自动生成的 SQL 往往不够高效。MyBatis 让你把 SQL 攥在手里,需要优化时可以直接改。

对毕设而言,MyBatis 有一个额外优势:老师问“你的 SQL 是怎么写的”,你能够很具体地讲清楚,而不是说“框架自动生成了”。

2.4 三大框架的分工与易错点

框架核心职责在系统中的角色
SpringBean 管理、依赖注入、事务管理整个项目的容器底座
SpringMVCWeb 层的请求接收与响应接收页面请求、调用 Service、返回视图
MyBatis数据持久层,SQL 与映射操作数据库,完成数据读写

易错点很典型:有人误以为“SSM 三个框架是各自独立的,分别写三套配置文件就够了”。实际上,SSM 的灵魂在于集成:Spring 要把 SpringMVC 的 Controller 纳入容器管理,要把 MyBatis 的 SqlSessionFactory 和 Mapper 接口纳入容器管理,事务管理器要同时认识数据源和 MyBatis。集成配置一旦漏掉某个 bean,项目就会在启动时直接报错。

3. 系统需求分析与功能模块设计

3.1 用户角色分析

资产评估系统虽然叫“资产评估”,但本质是一个管理系统,所以用户角色设计不能太复杂。一个能讲清楚、能实现完的角色体系,我建议三张表就够了:用户表、用户角色、角色权限。

如果不想把权限做得很重,可以在用户表中加一个role字段,用字符串区分管理员和普通评估人员。对于毕设来说,这种简化完全合理——你必须让老师看到你“做了权限控制”,而不是“权限模块比业务模块还复杂”。

常见角色划分:

  • 管理员:管理用户、分配角色、查看系统统计、维护基础数据。
  • 评估人员:创建评估项目、录入资产明细、选择评估方法、计算评估值、提交报告。
  • 审核人员(可选):审核评估报告,审核通过后项目归档。

如果时间有限,管理员和评估人员两个角色先做出来,审核流程可以设计成“状态字段 + 审核按钮”,不需要单独拆一个角色。

3.2 系统功能模块划分

围绕资产评估的核心业务链条,系统可以拆成以下模块:

模块功能说明
用户管理登录、注册、修改密码、用户列表、角色权限控制
项目管理评估项目的增删改查、项目状态流转、按状态筛选
评估作业录入资产明细、选择评估方法、自动计算评估值
报告管理生成评估报告、预览报告、提交审核、审核结果回执
数据统计按项目状态、评估类型统计数量,简单图表展示
系统管理日志记录、基础数据字典维护

3.3 核心业务流程

资产评估项目的标准流程如下:

  1. 委托单位提交评估需求,管理员或评估人员创建评估项目。
  2. 项目进入“资料收集”状态,补充委托方信息、评估目的、评估基准日。
  3. 评估人员录入资产明细,选择评估方法。
  4. 系统根据资产原值、重置成本、成新率、收益期限等参数计算评估值。
  5. 评估人员生成评估报告,提交审核。
  6. 审核人通过后,项目归档,流程结束。

数据库设计时,状态字段就可以围绕这个流程来设计。比如status用整型表示,0 为草稿,1 为已立项,2 为评估中,3 为待审核,4 为已归档。状态并不是固定的,你可以根据自己论文设计调整。但一定要在论文里说明“为什么用整型状态而不是字符串”,这是一个简单的加分点。

4. 环境准备与项目搭建

4.1 基础环境与版本建议

对于 SSM 毕设项目,我建议你按下面这套组合准备,它经过大量项目验证,稳定性和资料量都足够:

环境建议版本说明
JDKJDK 8SSM 项目最稳的 JDK 版本
MavenMaven 3.6 及以上依赖管理和打包
MySQLMySQL 5.7 或 8.0数据库
TomcatTomcat 8.5 / 9Web 容器
IDEIDEA 或 Eclipse集成开发环境

如果你的电脑装的是 JDK 17 或更高版本,运行老项目时很容易遇到编译器报错,比如:

java: 警告: 源发行版 17 需要目标发行版 17

这是因为项目的编译级别和你本地 JDK 不一致。解决方法是在 IDE 中把 Project Structure 里的 SDK 和语言级别统一,或者在 Maven 的pom.xml里指定<java.version>8</java.version>,让编译版本向后兼容。但最稳妥的方案还是直接用 JDK 8,很多学校机房也就是这个版本。

4.2 项目结构划分

一个标准的 SSM 多模块项目,目录结构大致如下:

asset-assessment-system/ ├── pom.xml ├── src │ └── main │ ├── java │ │ └── com/example/asset │ │ ├── controller │ │ ├── service │ │ │ └── impl │ │ ├── mapper │ │ ├── entity │ │ ├── common │ │ └── interceptor │ ├── resources │ │ ├── mapper │ │ ├── spring-mybatis.xml │ │ ├── spring-mvc.xml │ │ └── jdbc.properties │ └── webapp │ ├── WEB-INF │ │ ├── web.xml │ │ └── views │ ├── static │ └── index.jsp

分包核心是controller -> service -> mapper -> database的清晰调用链。分包清晰,论文里的“系统架构图”也好画。

4.3 关键依赖配置

SSM 的 Maven 依赖比较固定,核心是 Spring、SpringMVC、MyBatis、MyBatis-Spring、MySQL 驱动、Druid 连接池、PageHelper 分页插件。

下面是一份常见的pom.xml依赖片段,版本号不是写死的,你需要根据本机环境微调:

<properties> <spring.version>5.3.30</spring.version> <mybatis.version>3.5.13</mybatis.version> </properties> <dependencies> <!-- Spring 核心 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <!-- Spring JDBC 与事务 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>${mybatis.version}</version> </dependency> <!-- MyBatis 与 Spring 集成 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <!-- MySQL 驱动 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> <!-- Druid 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.20</version> </dependency> <!-- PageHelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.3.3</version> </dependency> <!-- Servlet API,编译需要,运行时 Tomcat 提供 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies>

注意:如果你使用的是 MySQL 8.0,驱动类名要用com.mysql.cj.jdbc.Driver,而不是老的com.mysql.jdbc.Driver

5. 数据库设计与核心表结构

数据库设计是毕设论文里最容易被老师翻看的章节。设计得好,论文好写;设计得乱,后面写代码全是坑。

5.1 表结构设计原则

资产评估系统不需要几十张表,核心表控制在 5 到 8 张即可。我推荐以下集合:

  • user:用户表,存登录账号和角色。
  • assessment_project:评估项目主表,一条记录代表一个评估项目。
  • assessment_detail:评估明细表,一个项目下有多条资产明细。
  • assessment_report:评估报告表,保存报告摘要信息和审核状态。
  • operation_log:操作日志表,用于记录用户关键操作。

5.2 用户表与角色

用户表结构很简单,但要注意两个点:密码不能明文存储,角色字段要便于扩展。下面是用 MySQL 建的示例 SQL:

CREATE TABLE `user` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', `username` VARCHAR(50) NOT NULL COMMENT '登录名', `password` VARCHAR(100) NOT NULL COMMENT '密码,至少加盐哈希', `real_name` VARCHAR(50) DEFAULT NULL COMMENT '姓名', `role` VARCHAR(20) NOT NULL DEFAULT 'ROLE_EVALUATOR' COMMENT '角色', `status` INT NOT NULL DEFAULT 1 COMMENT '1启用 0禁用', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

角色字段用字符串ROLE_ADMINROLE_EVALUATOR,比数字可读性强,权限判断时也不容易记错。

5.3 评估项目表与评估明细表

评估项目表是系统的主表,字段要能支撑列表筛选和详情展示:

CREATE TABLE `assessment_project` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', `project_code` VARCHAR(50) NOT NULL COMMENT '项目编号', `project_name` VARCHAR(100) NOT NULL COMMENT '项目名称', `client_name` VARCHAR(100) DEFAULT NULL COMMENT '委托单位/委托方', `assessment_base_date` VARCHAR(20) DEFAULT NULL COMMENT '评估基准日', `assessment_purpose` VARCHAR(200) DEFAULT NULL COMMENT '评估目的', `assessment_type` VARCHAR(50) DEFAULT NULL COMMENT '评估类型:设备/房产/无形资产', `assessor_id` BIGINT DEFAULT NULL COMMENT '负责人ID', `status` INT NOT NULL DEFAULT 0 COMMENT '0草稿 1立项 2评估中 3待审核 4已归档', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_project_code` (`project_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评估项目表';

评估明细表用于存储一个项目下的多条资产明细:

CREATE TABLE `assessment_detail` ( `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键', `project_id` BIGINT NOT NULL COMMENT '所属项目', `asset_name` VARCHAR(100) NOT NULL COMMENT '资产名称', `asset_type` VARCHAR(50) DEFAULT NULL COMMENT '资产类型', `original_value` DECIMAL(18,2) DEFAULT NULL COMMENT '原值', `replacement_cost` DECIMAL(18,2) DEFAULT NULL COMMENT '重置成本', `depreciation_rate` DECIMAL(5,2) DEFAULT NULL COMMENT '成新率/综合成新率,30表示30%', `assessed_value` DECIMAL(18,2) DEFAULT NULL COMMENT '评估值', `method_type` VARCHAR(20) DEFAULT NULL COMMENT '评估方法:cost/market/income', PRIMARY KEY (`id`), KEY `idx_project_id` (`project_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='评估明细表';

5.4 一个值得注意的设计细节

金额字段一定要用DECIMAL,不要用doublefloat这不是老生常谈,而是实际开发中非常容易踩的坑。浮点数在二进制中无法精确表示小数,比如0.1 + 0.2的结果并不等于0.3。资产评估领域涉及金额、准确率要求极高,用DECIMAL(18,2)是基本常识。

另外,项目编号project_code不要让学生用自增 ID 直接当成业务编号。真实系统里通常会用“AS + 年月日 + 流水号”的格式生成,既便于识别也便于排查问题。

6. 核心代码实现

6.1 实体类实现

AssessmentProject实体类为例,类字段和数据库字段保持一一对应。这里用手写 getter/setter 的方式展示,实际项目中可以使用 Lombok 的@Data,但如果你环境里 Lombok 插件配置有问题,手写反而更稳妥。

package com.example.asset.entity; import java.math.BigDecimal; import java.util.Date; public class AssessmentProject { private Long id; private String projectCode; private String projectName; private String clientName; private String assessmentBaseDate; private String assessmentPurpose; private String assessmentType; private Long assessorId; private Integer status; private Date createTime; private Date updateTime; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getProjectCode() { return projectCode; } public void setProjectCode(String projectCode) { this.projectCode = projectCode; } public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } // 其他字段的 getter/setter 省略,实际代码请补全 }

这里要强调一点:实体类字段不要直接引用数据库字段名的下划线风格,Java 属性的命名遵循驼峰命名法,由 MyBatis 的驼峰映射配置自动转换。

6.2 Mapper 接口与动态 SQL

Mapper 接口定义方法,XML 文件写 SQL。接口示例如下:

package com.example.asset.mapper; import com.example.asset.entity.AssessmentProject; import org.apache.ibatis.annotations.Param; import java.util.List; public interface AssessmentProjectMapper { int insert(AssessmentProject project); int update(AssessmentProject project); int deleteById(Long id); AssessmentProject selectById(Long id); List<AssessmentProject> selectByCondition(@Param("projectName") String projectName, @Param("status") Integer status); }

对应的 Mapper XML:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.asset.mapper.AssessmentProjectMapper"> <insert id="insert" parameterType="com.example.asset.entity.AssessmentProject" useGeneratedKeys="true" keyProperty="id"> INSERT INTO assessment_project ( project_code, project_name, client_name, assessment_base_date, assessment_purpose, assessment_type, assessor_id, status ) VALUES ( #{projectCode}, #{projectName}, #{clientName}, #{assessmentBaseDate}, #{assessmentPurpose}, #{assessmentType}, #{assessorId}, #{status} ) </insert> <update id="update" parameterType="com.example.asset.entity.AssessmentProject"> UPDATE assessment_project <set> <if test="projectName != null">project_name = #{projectName},</if> <if test="clientName != null">client_name = #{clientName},</if> <if test="assessmentBaseDate != null">assessment_base_date = #{assessmentBaseDate},</if> <if test="status != null">status = #{status},</if> </set> WHERE id = #{id} </update> <select id="selectById" resultType="com.example.asset.entity.AssessmentProject"> SELECT id, project_code, project_name, client_name, assessment_base_date, assessment_purpose, assessment_type, assessor_id, status, create_time, update_time FROM assessment_project WHERE id = #{id} </select> <select id="selectByCondition" resultType="com.example.asset.entity.AssessmentProject"> SELECT id, project_code, project_name, client_name, assessment_base_date, assessment_purpose, assessment_type, assessor_id, status, create_time, update_time FROM assessment_project <where> <if test="projectName != null and projectName != ''"> AND project_name LIKE CONCAT('%', #{projectName}, '%') </if> <if test="status != null"> AND status = #{status} </if> </where> ORDER BY create_time DESC </select> </mapper>

动态 SQL 是 MyBatis 很实用的能力。<where>标签会自动处理AND/OR前缀,<if>标签实现条件拼接。这样项目列表页就能支持“按名称模糊查询 + 按状态筛选”的组合查询,不需要拼 SQL 字符串,也不会出现WHERE 1=1这类不够优雅的写法。

6.3 Service 层与事务控制

Service 层是业务逻辑的核心。资产评估系统里最值得展示的业务逻辑是:创建项目的同时录入多条资产明细,并根据成本法自动计算评估值。

成本法的通俗公式是:评估值 = 重置成本 × 成新率。比如一台设备重置成本 100 万元,成新率 80%,评估值就是 80 万元。当然真实评估要考虑更多修正系数,这里先按这个简化公式做演示。

package com.example.asset.service.impl; import com.example.asset.entity.AssessmentDetail; import com.example.asset.entity.AssessmentProject; import com.example.asset.mapper.AssessmentDetailMapper; import com.example.asset.mapper.AssessmentProjectMapper; import com.example.asset.service.AssessmentProjectService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; @Service public class AssessmentProjectServiceImpl implements AssessmentProjectService { @Autowired private AssessmentProjectMapper projectMapper; @Autowired private AssessmentDetailMapper detailMapper; @Transactional(rollbackFor = Exception.class) @Override public void createProjectWithDetails(AssessmentProject project, List<AssessmentDetail> details) { // 生成项目编号:AS + yyyyMMddHHmmss String code = "AS" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); project.setProjectCode(code); if (project.getStatus() == null) { project.setStatus(0); } projectMapper.insert(project); for (AssessmentDetail detail : details) { // 成本法评估值计算 if ("cost".equals(detail.getMethodType())) { BigDecimal replacementCost = detail.getReplacementCost(); BigDecimal depreciationRate = detail.getDepreciationRate(); BigDecimal multiplier = BigDecimal.ONE .subtract(depreciationRate.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)); BigDecimal assessedValue = replacementCost .multiply(multiplier) .setScale(2, RoundingMode.HALF_UP); detail.setAssessedValue(assessedValue); } detail.setProjectId(project.getId()); detailMapper.insert(detail); } } }

@Transactional放在 Service 实现类上,是本项目必须掌握的要点。原因有两个:

第一个原因是事务边界问题。一个业务操作里可能包含多次数据库操作,比如“插入项目 + 插入多条明细”,如果其中一条明细插入失败,前面的插入也应该回滚,否则数据库里会留下“有项目无明细”的脏数据。

第二个原因是 AOP 原理。Spring 事务的本质是 AOP,它在方法执行前开启事务,方法正常返回后提交事务,方法抛出异常后回滚事务。rollbackFor = Exception.class表示任何异常都触发回滚。这是答辩时几乎必考的知识点。

6.4 Controller 层

Controller 层负责接收请求、调用 Service、返回视图或数据。以评估项目的列表、新增、修改、删除为例:

package com.example.asset.controller; import com.example.asset.entity.AssessmentProject; import com.example.asset.service.AssessmentProjectService; import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @Controller @RequestMapping("/project") public class AssessmentProjectController { @Autowired private AssessmentProjectService projectService; @RequestMapping("/list") public String list(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "10") Integer pageSize, String projectName, Integer status, Model model) { PageInfo<AssessmentProject> pageInfo = projectService.queryPage(pageNum, pageSize, projectName, status); model.addAttribute("pageInfo", pageInfo); model.addAttribute("projectName", projectName); model.addAttribute("status", status); return "project/list"; } @RequestMapping("/toAdd") public String toAdd() { return "project/add"; } @RequestMapping("/save") public String save(AssessmentProject project) { projectService.save(project); return "redirect:/project/list"; } @RequestMapping("/edit/{id}") public String edit(@PathVariable Long id, Model model) { model.addAttribute("project", projectService.getById(id)); return "project/edit"; } @RequestMapping("/delete/{id}") public String delete(@PathVariable Long id) { projectService.deleteById(id); return "redirect:/project/list"; } }

保存成功后的redirect:/project/list很关键。如果用forward或直接返回视图,用户在刷新页面时可能会重复提交表单,造成数据重复。重定向遵循“Post/Redirect/Get”模式,是 Web 开发里防止重复提交的基本手段。

Controller 层不应该出现 SQL、不应该直接操作数据库。如果答辩时老师问“为什么 Controller 这么薄”,你可以回答:Controller 只负责请求调度,业务逻辑都在 Service 层,这样便于事务管理、便于单元测试、也便于代码复用。

6.5 Spring 与 MyBatis 集成配置

SSM 项目最劝退的环节就是 XML 配置。但只要理解“谁管谁”,配置就不乱。

applicationContext.xml里管 Spring 容器:数据源、SqlSessionFactory、事务管理器、Mapper 扫描。SpringMVC 的配置文件只负责 Controller 和视图解析。

核心配置如下:

<!-- jdbc.properties --> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations" value="classpath:mapper/*.xml"/> <!-- 驼峰映射,自动将 project_code 转为 projectCode --> <property name="configuration"> <bean class="org.apache.ibatis.session.Configuration"> <property name="mapUnderscoreToCamelCase" value="true"/> </bean> </property> </bean> <!-- 扫描 Mapper 接口 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.asset.mapper"/> </bean> <!-- 事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 开启事务注解驱动 --> <tx:annotation-driven transaction-manager="transactionManager"/>

mapUnderscoreToCamelCase这个配置要重点记住。数据库字段是project_code,Java 属性是projectCode。不开启驼峰映射,MyBatis 就不知道该字段填到哪个属性上,查询出来的对象可能会出现整行为 null 的诡异现象。

以下是jdbc.properties文件内容:

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

注意 URL 里一定要加上useUnicode=true&characterEncoding=utf8,否则容易出现中文乱码。如果使用 MySQL 8.0 或更高版本,serverTimezone参数也必须带上,否则驱动会报时区相关错误。

7. 运行与功能验证

7.1 启动项目

项目以 Web 应用形式部署到 Tomcat。IDEA 中配置好 Tomcat 后,点击 Debug 或 Run,控制台出现类似下面的日志说明容器启动成功:

信息 [main] org.apache.catalina.startup.Catalina.start Server startup in [xxx] milliseconds

启动后访问首页:

http://localhost:8080/asset/

如果看到首页或直接跳转到登录页面,说明项目基本跑通了。

7.2 验证登录与权限

用管理员账号登录后,访问用户管理页面,应能看到用户列表。这里要验证“未登录时不能直接访问后台页面”。如果直接在浏览器输入:

http://localhost:8080/asset/project/list

未登录的情况下应该跳转到登录页。如果直接打开了列表页面,说明权限拦截器没有生效,这是需要马上修复的点。评估人员账号和管理员应该看到不同的菜单项,管理员能进入用户管理,评估人员不能。

7.3 验证评估项目全流程

完整流程验证分以下几步:

  1. 新增一个评估项目,填写项目名称、委托单位、评估基准日、评估目的。
  2. 保存成功,列表页出现新项目,项目编号自动生成。
  3. 进入详情页,添加多条资产明细。
  4. 选择“成本法”作为评估方法,填写重置成本和成新率。
  5. 保存后,明细列表中的评估值应按公式自动计算。
  6. 修改项目状态,从“草稿”改为“立项”,再改为“评估中”,观察状态流转是否正常。
  7. 以审核员身份登录,审核该项目,项目进入“归档”状态。

7.4 验证核心计算方法

假设某台设备:

  • 重置成本:100000.00 元
  • 成新率:80

期望评估值计算过程:

100000.00 × (1 - 80/100) = 100000.00 × 0.20 = 20000.00

等等,这里要小心,成本法的公式我前面写的是“评估值 = 重置成本 × 成新率”,成新率 80% 应该是 100000 × 0.8 = 80000。刚才用(1 - 成新率/100)计算出来的其实是“贬值额”或“扣除折旧后的价值”,如果没有上下文容易混淆。

为了统一,我建议明确一个简单口径:成本法评估值 = 重置成本 × 成新率,成新率 80% 时评估值就是 8 万元。如果使用“综合成新率”,则代码里直接乘以成新率除以 100 即可,不需要减。我在前面 Service 代码里写的是(1 - depreciationRate.divide(100)),它计算的是“扣除贬值后的剩余价值”,这在评估中对应的是“成新率”概念反过来用,会给读者造成困惑。

那么我应该在 Service 代码里修正为:assessedValue = replacementCost.multiply(depreciationRate.divide(100, 4, RoundingMode.HALF_UP)),同时把字段名depreciation_rate解释为“成新率(0-100)”,这样逻辑统一:成新率 80,乘以 0.8,得到 8 万。为了和资产评估实务更加贴近,我可以说“这里的折旧率字段可以作为成新率使用,实际业务中可以根据评估假设扩展”。为了不让代码块与后续验证矛盾,我将修正代码块。

前面6.3的代码已生成,现在是最终的输出,应该把代码改对。在正式输出时采用修正后的公式,比如:

// 成本法:评估值 = 重置成本 × 成新率 BigDecimal rate = detail.getDepreciationRate() .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP); BigDecimal assessedValue = replacementCost .multiply(rate) .setScale(2, RoundingMode.HALF_UP);

这样验证部分写:重置成本 100000 元,成新率 80,评估值 80000 元。这个口径清晰,老师问起来也容易讲。

好,那么最终正式输出的验证部分就按这个口径写,而代码也会调整为这个口径。由于我现在写的是草稿,不是最终正文,所以等最后组合时保持一致。

7.5 验证数据统计

如果系统实现了数据统计模块,可以验证:

  • 按项目状态统计数量,比如草稿 3 个、评估中 5 个、已归档 10 个。
  • 按评估类型统计数量,比如设备类 8 个、房产类 6 个。

统计结果可以用简单的SELECT COUNT(*) ... GROUP BY status来实现。注意:统计 SQL 里如果某个状态没有数据,GROUP BY 默认不返回该状态行。为了让饼图或柱状图完整展示所有状态,可以在 Java 侧把缺失的状态补 0,这是一个很容易被老师追问的细节。

8. 常见问题与排查思路

SSM 项目运行过程中报错非常常见,我把实际项目里高频出现的问题整理成了排查表:

问题现象可能原因排查方式解决方案
启动 Tomcat 后访问项目 404项目没有正确部署,或访问路径不对检查 IDEA 中 Deployment 下的 Application context确认路径,比如/asset/,或在控制台看部署日志
访问任何页面都是 404,但控制台正常SpringMVC 的DispatcherServlet没有拦截到请求,或web.xml配置错误查看web.xml中的 servlet-mapping/交给DispatcherServlet处理
页面加载后中文乱码数据库连接 URL 没有设置编码,或页面编码不一致检查jdbc.properties和 JSP 的pageEncodingURL 添加characterEncoding=utf8,JSP 统一 UTF-8
数据库连接失败:Access
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/31 6:39:25

三极管偏置电路设计精讲:从静态工作点设置到分压偏置计算

在硬件调试中&#xff0c;三极管偏置电路是最容易出问题、也最容易被低估的一环。很多初学者搭完一个共射极放大电路&#xff0c;明明元件和接线都没错&#xff0c;示波器上却看不到正常放大的正弦波&#xff0c;要么输出被削掉一边&#xff0c;要么完全没有信号。问题往往不在…

作者头像 李华
网站建设 2026/8/31 6:38:50

SpringBoot3+Vue3租车管理系统毕设实践:从技术选型到部署答辩全复盘

简介&#xff1a;这是一套面向计算机专业本科生的2025届毕业设计级全栈项目资源&#xff0c;聚焦租车业务场景&#xff0c;解决车辆租赁服务中用户预订、订单管理、车辆调度与后台监管等核心需求&#xff0c;适用于课程设计、毕设开题与SpringBootVue工程实践学习。资源共6个文…

作者头像 李华
网站建设 2026/8/31 6:38:21

PyTorch vs TensorFlow:动态图与静态图核心对比与实战

正在准备面试人工智能、深度学习相关岗位&#xff0c;或者刚开始接触深度学习的朋友&#xff0c;几乎都逃不过一个问题&#xff1a;PyTorch 和 TensorFlow&#xff0c;到底应该学哪个&#xff1f;这个问题表面上是“框架选型”&#xff0c;实际上对方想从你的回答里判断三件事&…

作者头像 李华
网站建设 2026/8/31 6:36:30

MySQL数据库迁移达梦数据库学习报告

文章目录MySQL数据库迁移达梦数据库学习报告概述源库环境准备MySQL数据库安装数据库实例配置创建测试数据库与业务对象源库连接信息确认迁移前评估启动DTS工具创建评估工程与节点配置评估数据源配置评估内容与策略选择评估对象执行评估并查看报告执行迁移创建迁移节点配置迁移数…

作者头像 李华
网站建设 2026/8/31 6:36:25

奔驰大G常见故障:W463/W464/W465维修保养指南

奔驰G级&#xff0c;江湖人称"大G"&#xff0c;是豪华越野的天花板&#xff0c;也是成都街头回头率最高的存在。方正的盒子造型、标志性的"三把锁"、硬派到极致的梯形车架——但车无完车&#xff0c;大G车身重、结构特殊、电子系统复杂&#xff0c;车龄上来…

作者头像 李华
网站建设 2026/8/31 6:36:03

基于SpringBoot的中国历史知识学习系统的设计与实现

1. 项目背景与意义 中国历史源远流长&#xff0c;蕴含着丰富的文化内涵和智慧结晶。然而&#xff0c;传统的历史学习方式往往依赖纸质教材和课堂讲授&#xff0c;存在知识碎片化、学习路径单一、互动性不足等问题。随着互联网和移动技术的普及&#xff0c;越来越多的人希望通过…

作者头像 李华