尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

保险公司售后服务管理系统实战:SSM框架与MySQL部署全解析

保险公司售后服务管理系统实战:SSM框架与MySQL部署全解析 简介这是一份保险公司售后服务管理系统完整源码包面向保险行业软件开发者、毕业设计学生及系统运维人员解决保单管理、理赔处理、客户服务、核保风控、财务结算等售后流程一体化管理问题。资源共909个文件包含184个html页面、152个class编译类、134个css样式、122个js脚本、120个java源码及121个png图片等压缩包整体约1.61MB覆盖前端展示、后端逻辑与静态资源目录结构清晰。从内容预览可见SaleListAdminController、GoodsAdminController等控制类能帮助读者快速理解订单、商品、用户等模块的后台管理实现。已有54人学习下载适合用于保险业务系统课程设计、代码学习或二次开发参考可借此了解保险售后业务流程的代码实现与系统架构。1. 保险公司售后服务管理系统从保单签出之后的烂摊子说起一张保单签出去业务员的活儿只算干了一半。真正的麻烦从售后开始客户出险要报案、到期要续保、对理赔不满意要投诉、新产品上线要回访。这些事要是还靠 Excel 登记业务员离职带走一张表整个服务链条就断了。保险公司售后服务管理系统就是接管签单之后的这一整套动作登记服务工单、跟踪理赔进度、自动生成续保提醒、记录回访和满意度。这类压缩包里通常是一套 Java Web 项目SSM 框架加 MySQL 数据库前端页面直接跑在 Tomcat 上。适合中小保险分支机构和代理网点内部用也常被当作毕业设计和实训项目的底子。重点别急着点启动按钮先把这个系统的数据模型读明白再谈怎么跑起来。2. 拆开压缩包看数据设计保单、理赔、回访、续保四组核心表拿到压缩包之后第一件事不是往 IDE 里导而是先看目录结构和数据库脚本。这类项目一般包含几样固定的东西一个 Eclipse 或 IDEA 工程目录、一个 .sql 数据库脚本、一份说明文档。脚本是整套系统的灵魂我习惯先读表结构再读代码因为售后系统的业务逻辑几乎全部体现在表设计上状态怎么流转、费用怎么记录、提醒怎么触发。表结构没吃透后面改代码等于在黑匣子里瞎试。这四张表建议按顺序去看先主表后子表把依赖关系一层层拉出来。2.1 售后工单主表以保单号为中心把每件事串起来售后模块几乎都以工单为中心。一次理赔报案、一通投诉电话、一次主动回访都生成一条工单记录挂到对应的保单下面。主表设计大致是这样CREATE TABLE aftersale_order ( id INT PRIMARY KEY AUTO_INCREMENT, order_no VARCHAR(32) NOT NULL COMMENT 工单号, policy_no VARCHAR(32) NOT NULL COMMENT 保单号, customer_id INT NOT NULL COMMENT 客户ID, service_type TINYINT NOT NULL COMMENT 1理赔 2投诉 3咨询 4续保 5回访, status TINYINT NOT NULL DEFAULT 1 COMMENT 1待处理 2处理中 3已完成 4已关闭, assignee VARCHAR(32) COMMENT 处理人, apply_time DATETIME COMMENT 申请时间, finish_time DATETIME COMMENT 完成时间, remark VARCHAR(500) COMMENT 备注, KEY idx_policy (policy_no), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT售后工单主表;建表的关键点全在索引上。售后页面里最常见的查询就是某个保单下的全部服务记录和当前待处理的工单列表所以 idx_policy 和 idx_status 这两个索引必须有否则数据量过万之后每次按保单查都做全表扫描页面响应会肉眼可见地变慢。status 字段用 TINYINT 存数字而不是字符串代码里比对方便也省空间但必须在 COMMENT 里写清楚每个数字的含义不然半年后没人看得懂 status3 到底代表什么。另外注意 order_no 和 policy_no 是业务编号客户看得见、要用来对账所以单独设列id 只是给程序内部关联用的。很多毕业设计把业务编号直接当主键一旦要改单号规则就得动主键非常被动。工单与保单是一对多的关系一张保单可以有多条工单反过来不行这个方向不能搞反。2.2 理赔子表状态字段就是理赔流程的进度条理赔是整个售后系统里最重的模块因为涉及金额核定和多角色流转。它的子表设计通常长这样CREATE TABLE claim_info ( id INT PRIMARY KEY AUTO_INCREMENT, claim_no VARCHAR(32) NOT NULL COMMENT 报案号, order_id INT NOT NULL COMMENT 关联工单ID, policy_no VARCHAR(32) NOT NULL COMMENT 保单号, accident_time VARCHAR(32) COMMENT 出险时间, report_time DATETIME COMMENT 报案时间, claim_amount DECIMAL(12,2) COMMENT 申请金额, approved_amount DECIMAL(12,2) COMMENT 核定金额, status TINYINT NOT NULL DEFAULT 1 COMMENT 1已报案 2查勘中 3核赔中 4待支付 5已结案 6已拒赔, adjuster VARCHAR(32) COMMENT 查勘员, UNIQUE KEY uk_claim_no (claim_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT理赔信息表;这里最值得琢磨的是状态字段。理赔状态是一条固定链报案 → 查勘 → 核赔 → 待支付 → 结案拒赔是核赔阶段的分支分支。代码里会按这个数字状态写判断页面上显示查勘中就用状态值对应文案。所以改状态枚举是整个项目里风险最高的事新增状态可以但改旧状态的数字含义会导致历史数据全部乱套——之前归档的报案记录状态含义全变了统计报表也会跟着错。出险时间我用 VARCHAR(32) 而不是 DATETIME这是故意为之。实际业务里出险时间经常是客户口头描述格式五花八门2025年3月5号和2025-03-05都有查勘员录入时不会规规矩矩按日期格式填。字符串反而不会在录入阶段报错展示时原样输出统计时再做格式归一。这个细节是踩过坑才改的初期用 DATETIME前端一传2025/03/05数据库直接报错。金额字段用 DECIMAL(12,2) 而不是 DOUBLE因为保险场景对金额精度有硬要求。DOUBLE 的浮点误差在累计对账时会暴露0.1 加 0.2 算出 0.30000000000000004 这种事在理赔金额统计里没法接受。DECIMAL 是精确类型只是存储上稍微多占几个字节对这套系统来说完全可以忽略。2.3 回访与满意度表让服务过变成服务得好理赔结案之后要回访保单到期之前要回访新产品上线也要回访。回访记录表是统计满意度的数据来源CREATE TABLE visit_record ( id INT PRIMARY KEY AUTO_INCREMENT, order_id INT NOT NULL, policy_no VARCHAR(32) NOT NULL, customer_id INT NOT NULL, visit_type TINYINT COMMENT 1理赔回访 2续保回访 3满意度调查, content VARCHAR(500) COMMENT 回访内容, satisfaction TINYINT COMMENT 1不满 2一般 3满意 4很满意, next_visit_date DATE COMMENT 下次回访日期, operator VARCHAR(32) COMMENT 回访人, create_time DATETIME COMMENT 回访时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT回访记录表;satisfaction 字段是整个售后服务质量评估的量化依据。这个季度客户满意度 96%这类指标SQL 写法就是COUNT(satisfaction 3) / COUNT(*)。没有这个字段售后做得好不好就只能是业务员嘴上的自我评价领导看报表也无从下手。所以这张表的第一个价值不是记录是量化。很多人做这张表会漏掉 operator回访人字段。回访业务的本质是任务分配客服每天打开系统看到今天要回访 15 个客户这 15 个必须能按人过滤。没有 operator 就只能查全量再自己挨个认领分配机制就塌了。这个字段不是可选项是业务能否流转起来的前提。同理 next_visit_date 用于生成明天待回访列表也别删。2.4 续保提醒日期算法是这里唯一的技术门槛续保提醒是售后系统里离钱最近的功能逻辑本身不复杂保单到期前 N 天生成提醒任务。真正要小心的是日期边界。常见的实现是一条 SQL 扫描即将到期的保单SELECT * FROM policy_info WHERE expire_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY) AND renewal_status 0;这里三个坑。第一CURDATE() 依赖数据库服务器时区MySQL 的 time_zone 要统一设成 Asia/Shanghai否则跨时区部署时提醒会提前或延后一天。第二expire_date 如果是 DATETIME 类型查询到期日当天的保单要小心BETWEEN 默认从 00:00:00 开始到期日当天的保单如果存的是带时间的值边界判断会漏数据。第三renewal_status 字段是防重复提醒的开关生成提醒后必须置 1否则第二天任务又跑一遍客户被短信连续轰炸投诉电话直接打到客服主管那里。policy_info 表一般长什么样核心字段不外乎 policy_no、customer_id、product_type、start_date、expire_date、renewal_status。续保提醒的任务就是盯住 expire_date 这一个字段所以这张表上 expire_date 必须建索引定时任务天天扫这张表没有索引就是一场灾难。实际项目里我建议把提前 30 天这个数字从代码里抽出来。业务上很可能下个月就改成提前 45 天写死在 SQL 里每次都要改代码重新部署。怎么改成可配置第 6 章会专门讲。3. 把系统跑起来解压、导库、改配置、启动四步全流程表结构过了一遍这一章落地。跑通这类项目的完整流程可以压缩成一句话解压工程导入 IDE、导入数据库脚本、改数据源配置文件、部署到 Tomcat 启动。每步都有固定的坑按下面顺序来半小时内能见到登录页。3.1 环境组合怎么选JDK 8、Tomcat 8.5、MySQL 5.7 为什么最稳先别急着动手把环境对齐再开始不然后面全是环境报错。这类压缩包大多是近几年的实训项目技术栈以 SSM 为主。这个年代的项目对运行环境非常挑剔不是越新越好。软件推荐版本用新版版本的代价JDK1.8JDK 17 运行旧框架会报 javax/jakarta 包缺失改起来伤筋动骨Tomcat8.5Tomcat 11 要求 Jakarta EE旧项目基本跑不了MySQL5.7MySQL 8 改了认证插件旧版 JDBC 驱动直接连不上IDEIntelliJ IDEA / Eclipse导入方式不同本质都是识别 Maven 或普通 Web 工程这个组合是这类项目性价比最高的选择。JDK 8 是 SSM 框架的舒适区Spring 4.x/5.x、MyBatis 3.x 全是官方支持版本Tomcat 8.5 兼容 JDK 8内嵌 Servlet 3.1正好对上 SpringMVC 的老配置方式MySQL 5.7 与项目自带的 .sql 脚本语法兼容度最高。有的压缩包会附带 README 写明 JDK 版本要求先看那个文件按它的要求来。如果没写就按上面这套组合九成能跑起来。剩下那一成跑不起来的问题大概率不在版本在配置。3.2 导入数据库两种方式与编码陷阱数据库脚本一般叫 db_insurance.sql 或 insurance_db.sql在压缩包根目录或 sql 目录下。先用文本编辑器打开看文件头部判断里面有没有 CREATE DATABASE 语句。有直接导入mysql -uroot -p db_insurance.sql没有的话先建库再导入mysql -uroot -p CREATE DATABASE insurance DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE insurance; SOURCE /path/to/db_insurance.sql;SOURCE 是 mysql 客户端的内置命令后面跟本地绝对路径。Windows 下路径里的反斜杠会被当成转义符要把 C:\projects\db.sql 写成 C:/projects/db.sql。这个细节不处理好会报一个莫名其妙的语法错误很容易让人误以为是 SQL 文件本身有问题。导入完成后立刻验证确认数据真实进库了USE insurance; SHOW TABLES; SELECT COUNT(*) FROM aftersale_order;如果 aftersale_order 这个表名不存在说明脚本里表名不一样用 SHOW TABLES 看一下实际表名再继续。编码坑集中在脚本文件的字符集上。很多脚本是从 Windows 环境导出的文件本身是 GBK 编码库是 UTF-8导入后表注释和字典表数据全成乱码。遇到这种情况把 SQL 文件用编辑器另存为 UTF-8 编码再导一次。或者导入时显式指定字符集mysql -uroot -p --default-character-setutf8mb4 insurance db_insurance.sql提示判断乱码的简单办法是看字典表里中文内容而不是表名表名全是 ASCII乱码不会体现在表名上。3.3 改数据源配置jdbc.properties 里的四个必改项数据库导好之后把工程导入 IDE找到数据源配置文件。SSM 工程里它通常叫 jdbc.properties放在 src/main/resources 下。这个文件决定了 Java 代码能不能连上刚才建好的库至少要改四行jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/insurance?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai jdbc.usernameroot jdbc.passwordyour_password前两行通常模板里写死了要对照你的实际情况核一遍。jdbc.url 里有几个关键参数useUnicodetrue 和 characterEncodingutf8 保证中文正常读写useSSLfalse 省掉本地开发的 SSL 握手开销serverTimezoneAsia/Shanghai 是必须加的旧版 mysql-connector-java 5.1.x 连 MySQL 5.7 不配时区参数会直接抛异常启动就失败。用户名密码改成你本地 MySQL 的实际账号。注意别用 root 空密码去试很多新版 MySQL 默认 root 用 auth_socket 插件命令行能进但 JDBC 连不上。给应用建一个独立账号最省事也方便后续回收权限CREATE USER insurance_applocalhost IDENTIFIED BY YourPass123; GRANT ALL PRIVILEGES ON insurance.* TO insurance_applocalhost; FLUSH PRIVILEGES;改完配置文件后确认 IDE 打包时用的是你改过的这份。用 Maven 管理的工程target/classes 下会残留旧的 .propertiesIDEA 不会每次都帮你清运行前先 mvn clean 一次。不然你改了半天跑的还是旧配置这种问题最容易让人怀疑人生。3.4 部署到 Tomcat 并启动war 包还是 IDE 直接跑配置改完进入启动阶段。两种常见选择IDE 里集成 Tomcat 插件直接跑适合调试打 war 包丢到独立 Tomcat 的 webapps 目录适合模拟线上环境。平时调试用第一种做完功能后用第二种验证一遍。独立 Tomcat 的方式更直观也好排查问题cd /path/to/project mvn clean package -DskipTests cp target/insurance.war /path/to/tomcat/webapps/ cd /path/to/tomcat/bin ./startup.sh tail -f /path/to/tomcat/logs/catalina.outTomcat 启动后会自动解压 war 包到 webapps/insurance/ 目录。看到 catalina.out 里出现 Deployment of web application archive insurance.war has finished 才算部署完成。这份日志是整个启动过程最权威的记录任何启动失败都会在这里留下堆栈别去看控制台控制台的信息经常不完整。浏览器访问 http://localhost:8080/insurance/ 或 README 里写的入口路径看到登录页就通了。这里有个新手最容易误判的地方打开 http://localhost:8080 看到 Tomcat 默认首页就以为部署成功了。那是 ROOT 应用的页面跟你的项目没有关系你的应用要带 /insurance 前缀访问。如果启动后页面 404先别慌看 Tomcat 日志里有没有 Context 初始化失败的提示再确认访问路径。第 5 章专门讲这类问题。4. 上线前必调的参数连接池、定时任务、上传路径与日志本地跑通只是第一步真要让业务员日常用起来必须把教学项目里的默认参数过一遍。默认值是为三个人玩设计的不是为三十个人干活设计的。这一章讲四个最关键的调整点连接池怎么才能不垮、定时任务怎么不漏单、上传怎么不报错、日志怎么留得下来。每一条都是上线后最容易出问题的位置。4.1 连接池参数maxActive 和 validationQuery 决定系统能撑多久旧 SSM 项目大多是 DBCP 或 C3P0 连接池配置在 spring-datasource.xml 里。默认配置往往只有基础四项上线后第一个瓶颈就在这里。bean iddataSource classorg.apache.commons.dbcp.BasicDataSource destroy-methodclose property namedriverClassName valuecom.mysql.jdbc.Driver / property nameurl value${jdbc.url} / property nameusername value${jdbc.username} / property namepassword value${jdbc.password} / property namemaxActive value50 / property namemaxIdle value10 / property namemaxWait value60000 / property nameinitialSize value5 / property namevalidationQuery valueSELECT 1 / property nametestOnBorrow valuetrue / /bean参数含义拆开说。maxActive50 是连接池能同时提供的最大连接数。30 个业务员同时在线操作加上定时任务偶尔占连接50 是稳妥值如果公司网点规模更大按峰值在线人数除以 2估算。maxIdle10 是空闲时保留的最大连接数防止频繁重建连接。maxWait60000 表示排队拿连接最长等 60 秒超时直接抛异常。这里不要设成 -1否则连接耗尽时请求会无限挂起页面卡死看不出原因重启 Tomcat 才好。initialSize5 是启动时预建的连接数应用刚起来就能扛住第一波请求不用等业务来了现场建连。这个参数教学项目里基本没有加上之后启动速度会慢一两秒但值得。最关键的是最后两行validationQuery 和 testOnBorrow。MySQL 服务端的 wait_timeout 默认 8 小时连接闲置超过这个时间会被服务端断开但连接池不知道下次取到这条死连接一执行就报 Communications link failure。testOnBorrowtrue 让每次从池子拿连接前先执行一次 SELECT 1连接是死的就舍弃重建。这是治每天早上第一波操作必卡的后悔药任何跑了一段时间就报连接异常的项目先检查这两行在不在。4.2 续保提醒定时任务cron 表达式与漏单补偿续保提醒是系统的招牌功能但默认实现往往把日期写死任务也没有补偿机制。Spring 的定时任务需要两处配置注解驱动和任务类。!-- 启用 Spring 注解式定时任务 -- task:annotation-driven /任务类里由 Scheduled 驱动Component public class RenewalTask { Scheduled(cron 0 0 9 * * ?) public void doRemind() { ListPolicyInfo list policyMapper.findExpiringWithin(30); for (PolicyInfo p : list) { if (!remindLogMapper.existsByPolicyId(p.getId())) { remindLogMapper.insert(new RemindLog(p.getId(), new Date())); // 此处调用短信服务商接口发送续保提醒 } } } }cron 表达式是秒 分 时 日 月 星期六位0 0 9 * * ? 表示每天 9 点整执行。注意 Spring 的 cron 和 Linux crontab 不一样Spring 从秒开始一共六位Linux 是五位从分开始。把 Linux 的表达式填进来启动会直接报 IllegalStateException。定时任务选在早上 9 点是因为这个时间业务员刚上班客户接电话意愿也高夜里跑纯属浪费短信费。逻辑上的漏单问题如果 9 点整系统正在重启或者数据库恰好锁表这一轮任务就漏了。漏掉的续保提醒意味着客户可能悄悄去别家续保。我一般在任务类里加启动补偿PostConstruct public void compensate() { doRemind(); // 应用启动时补跑一次保证当天不会漏 logger.info(启动补偿执行完成); }PostConstruct 在 Spring 容器初始化完成后执行补跑一次把今天该提醒的单子补上。配合 remindLog 表的去重逻辑重复跑也不会发重复短信。注意补跑和定时任务有并发风险方法上加 synchronized 兜底或者用任务框架的锁。这个细节能避免重复提醒。4.3 文件上传与日志两个最容易被忽略的配置理赔报案要传现场照片上传功能是售后流程里绕不开的环节。Spring MVC 需要 multipart 解析器才能处理文件上传配置在 spring-mvc.xmlbean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver property namemaxUploadSize value52428800 / property namemaxInMemorySize value1048576 / property namedefaultEncoding valueUTF-8 / /beanmaxUploadSize52428800 即 50MB。按现场照片每张 2-3MB、一次传 5-8 张来算50MB 留了余量。maxInMemorySize 表示 1MB 以内的小文件直接放内存超过的落磁盘避免大文件占用堆内存。另外页面的 form 表单必须加 enctypemultipart/form-data 属性漏掉这个接口永远拿不到文件前端还不报错只是后端 MultipartFile 参数一直是 null。上传目录也要改。很多项目把上传路径写死在代码里换台机器就报目录不存在。改成配置项并自动建目录Value(${upload.path}) private String uploadPath; PostConstruct public void init() { File dir new File(uploadPath); if (!dir.exists()) { dir.mkdirs(); } }日志配置同样值得过一遍。这类项目的 log4j.properties 默认输出到控制台上线后没有文件日志出了问题无从查起log4j.rootLoggerINFO, stdout, file log4j.appender.fileorg.apache.log4j.DailyRollingFileAppender log4j.appender.file.File/var/log/insurance/insurance.log log4j.appender.file.DatePattern.yyyy-MM-dd log4j.appender.file.layoutorg.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern%d{yyyy-MM-dd HH:mm:ss} %p %c:%L - %m%n log4j.logger.com.insurance.mapperDEBUGDailyRollingFileAppender 按天滚动日志不会无限变大。pattern 里的 %c:%L 输出类名和行号排查问题直接定位到代码位置。com.insurance.mapper 包打 DEBUG 级别MyBatis 会打印每条 SQL 语句和参数这是排查数据问题时最趁手的工具上线稳定后把这行改成 INFO否则查询量大时日志文件刷得飞快。注意日志目录 /var/log/insurance/ 要提前创建并确认 Tomcat 进程有写权限否则启动时报错但进程不退出很容易被忽略。5. 运行中的常见问题排查五条真实踩坑记录这一章直接给结论。跑起来之后遇到的各种报错里以下五类占了这类项目九成的问题。每一条都是实际踩过的按现象、原因、解决的顺序写拿过来对照处理就行。5.1 启动报 ClassNotFoundExceptionlib 目录没把依赖带进来现象Tomcat 启动成功但一访问页面就报 java.lang.ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet或者 NoClassDefFoundError。原因SSM 项目的依赖 jar 没有进入 WEB-INF/lib。用 IDEA 跑的时候是 IDE 自己提供了 classpath打包部署后没人管依赖了。常见根源是 IDEA 的 Artifact 配置里没把库文件放进 war 包或 pom.xml 里依赖的 scope 写成了 provided编译时有部署时被排除。解决IDEA 里打开 Project Structure → Artifacts选中项目在 Available Elements 里找到所有 Library右键选择 Put into /WEB-INF/lib重新 Build 后确认 war 解压目录下 WEB-INF/lib 里有 spring-webmvc.jar。Maven 项目则检查 pom.xml把依赖的 scope 改成 compile 或直接删掉 provided。改完重建再部署。这类问题排查起来最费时间的就是定位方向先看 lib 目录而不是改代码。5.2 页面中文乱码三处字符集必须一致现象登录进去客户姓名、保单类型等中文内容显示成问号或乱码符号。原因请求、页面、数据库三处字符集不一致。典型组合是 JSP 页面用 UTF-8数据库表是 latin1Tomcat 接收请求用 ISO-8859-1任何一处没对齐中文就废。解决按顺序统一。第一步JSP 页面顶部加% page languagejava contentTypetext/html; charsetUTF-8 pageEncodingUTF-8 %第二步数据库表统一改 utf8mb4ALTER TABLE aftersale_order CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;第三步Tomcat 的 conf/server.xml 里给 HTTP Connector 加 URIEncodingUTF-8。改完重启 Tomcat乱码能解决九成。还有一成在数据库连接串上jdbc.url 里 characterEncodingutf8 必须带这个前面第 3 章已经讲过。三处全对齐还乱码就查页面表单提交时有没有指定 accept-charset以及 MySQL 连接器版本是否过旧。5.3 登录页 404Tomcat 部署路径缺了一个斜杠现象应用能启动访问 http://localhost:8080/insurance 报 404但访问 http://localhost:8080/insurance/ 就正常。原因Tomcat 对不带斜杠的路径会尝试找默认欢迎页。这类项目通常没有 index.jsp目录列表又被关闭所以根路径就 404 了。这不是部署失败是缺一个斜杠。解决两个方向任选。要么在 web.xml 里配欢迎页把登录页加进去welcome-file-list welcome-filelogin.jsp/welcome-file /welcome-file-list要么推广统一入口让业务员收藏完整路径 http://localhost:8080/insurance/login.jsp。这个问题的迷惑性在于让人误以为部署失败反复重新部署浪费时间。先确认带斜杠的路径能不能通能通就只是路径问题不是部署问题。5.4 跑了一周后连不上数据库MySQL 8 小时断连现象系统刚上线头几天正常一周后业务员反馈早上操作很慢或者直接报 Connection is not available, request timed out。重启 Tomcat 又好了第二天又犯。原因经典的 MySQL wait_timeout 断连。MySQL 默认把空闲超过 8 小时的连接断掉连接池不知道继续把失效连接分给应用。连接池变成黑匣子导致的必踩坑不是代码逻辑问题。解决三管齐下。第一MySQL 端调大 wait_timeoutSET GLOBAL wait_timeout28800重启 MySQL 后要写进 my.cnf 的 [mysqld] 段才持久化。第二连接池配置加 validationQuerySELECT 1 和 testOnBorrowtrue这是根治手段拿连接前先探活。第三DBCP 连接池还可以加 minEvictableIdleTimeMillis60000让空闲连接每分钟被回收重建。前两步做掉这个故障不会再出。这个问题的隐蔽性在于启动后一切正常问题的触发条件是时间不是操作所以很难在测试阶段暴露。5.5 端口被占用8080 被别的程序抢了现象Tomcat 启动日志报 Address already in use: JVM_Bind 或 Failed to initialize end point associated with ProtocolHandler http-bio-8080。原因8080 端口被占用。可能是另一个 Tomcat 实例、Nginx、某个开发工具的本地服务或者上次 Tomcat 没有完全退出。Windows 下最常见的是 Oracle 和 WebLogic 也爱用 8080。解决先查谁占了端口# Linux / macOS lsof -i :8080 # Windows netstat -ano | findstr 8080拿到占用进程的 PID确认是无关服务就杀掉。如果端口被公司其他系统占用不能动就改 Tomcat 端口在 conf/server.xml 里Connector port8081 protocolHTTP/1.1 connectionTimeout20000 redirectPort8443 /改成 8081 后记得同步检查项目代码里有没有硬编码的 8080 地址。有些项目把回调地址写死在配置里页面能打开但接口请求全打到旧端口表现为页面加载一半就报错。全局搜一遍 8080 字符串把所有硬编码一起改掉。6. 二次开发的两个实用技巧让通用项目变成能用的系统跑通、调完参数系统已经能接真实业务了。但还有两个值得动手的小改造能把通用模板变成贴合自己业务流程的系统。6.1 用 Spring AOP 给售后操作加操作日志售后流程最怕扯皮客户说我上周就提交了报案业务员说没收到系统里查不到记录。与其指望每个人自觉点日志按钮不如在架构层面统一记录。用 Spring AOP 做一个切面在写操作的方法上自动落日志Aspect Component public class OperationLogAspect { Around(annotation(operationLog)) public Object record(ProceedingJoinPoint pjp, OperationLog operationLog) throws Throwable { Object result pjp.proceed(); OperationLogEntity log new OperationLogEntity(); log.setAction(operationLog.value()); log.setOperator(SecurityUtils.getCurrentUser()); log.setOperateTime(new Date()); log.setDetail(pjp.getSignature().toShortString()); operationLogMapper.insert(log); return result; } }这里只拦截标了 OperationLog 注解的方法不影响正常读操作的性能。理赔状态变更、工单转派、续保提醒生成这几类核心写操作各标一个注解就能自动留痕。配合一个简单的查询页面所有操作事后可回溯。这个改造的成本非常低但对售后管理的价值很高出了纠纷直接查日志表。6.2 把续保提醒提前天数改成配置项第 2 章提过续保提醒的提前 30 天如果写死在 SQL 里每次调整都要动代码。改成配置化很简单建一张 reminder_config 表把提前天数、提醒文案、是否启用放进去定时任务每次执行前先读配置再按配置值扫描保单。业务上要改成 45 天直接在配置页改数字不用再找开发。这类业务上会变的数字统一放进配置是这类项目里性价比最高的改造。改造完成后的验证方法很关键手动把一条保单的到期日改成今天加提前天数减一天的范围然后手动触发一次任务看提醒记录表有没有生成记录短信接口有没有收到调用。验证通过再放开定时任务避免上线即翻车。我以前做过一个项目没做这个验证直接上定时任务结果 cron 表达式因为写成了五位没生效续保提醒静默失败了一个月等发现时这个月的续保数据已经没法追回了。从那以后任何定时任务上线之前我都先手动触发一次并检查日志。这个习惯帮你挽回的损失可能远不止一个月。希望这个系统能真正跑在你的业务里也希望你少走我当年走过的弯路。希望帮到你。本文还有配套的精品资源点击获取
返回列表