新闻详情

新闻详情

首页 / 资讯中心 / 详情

SSM框架考勤管理系统实战:从环境配置到权限控制

发布时间:2026/9/12 17:06:47来源:尧图网络
SSM框架考勤管理系统实战:从环境配置到权限控制
简介一款基于SSMSpringSpringMVCMyBatis与JSP技术的员工信息管理系统毕业设计源码主要面向Java方向的毕业设计者和课程设计学员。系统完整覆盖员工、部门、职位、薪资、培训与考勤六大管理模块可实现员工信息维护、部门职位调整、薪资单增删改查、上下班打卡及培训管理等功能贴合企业人事管理常见业务。压缩包共含891个文件包括104个Java后台类、49个JSP页面、219个JS脚本、119个CSS样式、160张PNG图片及2个SQL数据库脚本并配有说明文档与前端字体图标等资源整体大小10.47MB。项目采用JDK1.8、MySQL5.7、Tomcat7环境通过Eclipse/IDEA和Maven即可部署运行。目前已有63人学习使用内置完整源码和数据库初始化脚本便于快速搭建、二次扩展也能作为毕业设计答辩的实用参考。1. 这套 SSM 考勤模块最容易被低估的是它的权限边界一个只有六个功能模块的员工信息管理系统在简历里写出来平平无奇真正拆开看才发现坑都在细节里。考勤打卡的“一天只能打两次卡”限制、薪资条按员工 ID 关联时的空指针、多条件查询时 SQL 的动态拼接——这些才是让许多人在答辩时被问住的地方。这套基于 SSMSpring SpringMVC MyBatis JSP MySQL 5.7 的项目功能上覆盖员工、部门、职位、薪资、培训、考勤六大模块前端用 Bootstrap JSP 做页面渲染后端三层架构分离得很干净。它适合两类人一是需要快速完成课程设计或毕业设计的学生二是想把 SSM 整合过程重新捋一遍的 Java 开发。后者会在这里看到传统 SSM 项目最常见的组织方式和隐藏问题。2. 环境适配与工程结构为什么 JDK 1.8 搭配 Tomcat 7 至今没淘汰SSM 这套组合在 2024 年看似乎有些年头但大量存量系统和教学项目仍在用它。选 JDK 1.8 Tomcat 7 Maven 3.3 不是随意搭配背后有兼容性逻辑Spring 4.x 与 MyBatis 3.x 在 JDK 8 上运行最稳定Tomcat 7 支持 Servlet 3.0 规范与 SpringMVC 的注解驱动开发完全匹配。而 MySQL 5.7 在事务隔离级别和索引实现上与 MyBatis 的 JDBC 驱动兼容性也经过了大量生产验证。2.1 环境版本匹配的取舍逻辑组件版本选择理由JDK1.8Spring 4.x 官方支持的最高稳定版本分支lambda 可用但不过度依赖Tomcat7.xServlet 3.0 与 JSP 2.2 规范与 SpringMVC 4.x 兼容无冲突MySQL5.7InnoDB 默认引擎成熟稳定支持 JSON 函数但项目用不到Maven3.3.x与 JDK 8 兼容良好依赖解析速度可接受Navicat11主要用于导入 SQL 脚本和可视化查看表结构properties spring.version4.3.18.RELEASE/spring.version mybatis.version3.4.6/mybatis.version mysql.connector.version5.1.47/mysql.connector.version /properties这里直接锁死 Spring 4.3.18 和 MyBatis 3.4.6 是稳妥做法。如果盲目升级 Spring 到 5.xSpringMVC 的注解扫描和 JSP 视图解析会出现兼容性问题Tomcat 7 对 Spring 5 的 Servlet 4.0 支持也会报警。MySQL 驱动用 5.1.47 而不是 8.x避免因驱动版本导致的时区serverTimezone和 SSL 连接报错。Maven 3.3 够用没必要上 3.6因为该项目的依赖树简单不需要复杂的分模块构建。2.2 标准 SSM 工程的 Maven 目录与分层src/main/java ├── com.longteng.controller # SpringMVC 控制器 ├── com.longteng.service # 业务逻辑接口 ├── com.longteng.service.impl # 业务实现类 ├── com.longteng.dao # MyBatis Mapper 接口 ├── com.longteng.pojo # 实体类对应数据库表 ├── com.longteng.utils # 工具类日期处理、分页 src/main/resources ├── jdbc.properties # 数据库连接配置 ├── spring-mybatis.xml # Spring MyBatis 整合 ├── spring-mvc.xml # SpringMVC 配置 ├── mapper # 各表的 Mapper.xml 文件 src/main/webapp ├── WEB-INF │ ├── jsp # 视图层 JSP 页面 │ └── web.xml # Web 应用部署描述符这个结构的核心是 Controller 不直接操作 DAO 层所有业务流转必须经过 Service 接口。实际开发中我会额外加一个exception包放全局异常处理器但这个项目没有问题不大——因为 JSP 页面本身做了大量 try-catch 和空值判断。jdbc.properties中需要特别注意两点。一是useSSLfalse必须显式声明否则 MySQL 5.7 默认开启 SSL 检查会报警告日志。二是数据库连接串要加characterEncodingutf-8否则 JSP 页面传入的中文姓名和部门名称会在入库后变成乱码。jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/longteng_db?useUnicodetruecharacterEncodingutf-8useSSLfalse jdbc.usernameroot jdbc.password123456提示Navicat 11 在导入 SQL 脚本时如果源文件是 utf-8 编码但表结构注释是中文会出现注释乱码请在导入前确认 SQL 文件的编码格式。2.3 web.xml 与 Spring 容器启动顺序servlet servlet-namespringmvc/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet这一步是 SSM 整合中新手最容易搞错的点。spring-mvc.xml只管 Controller 层的组件扫描和视图解析器spring-mybatis.xml负责 Service、DAO 和数据源的装配。两者不能合并到同一个 contextConfigLocation 中否则 SpringMVC 会尝试扫描 Service 并创建重复 Bean导致事务失效。Tomcat 启动时web.xml 会先加载 Spring 根容器listener 方式再加载 SpringMVC 子容器子容器可以访问父容器的 Bean反向不行。所以配置里必须让 Controller 能注入 Service而 Service 注入 Mapper 是由父容器完成的。3. 数据库设计与 MyBatis 映射六张业务表的字段约束和关系六大功能模块最终落到数据库就六张核心表员工表employee、部门表department、职位表position、薪资表salary、培训表training、考勤表attendance。它们之间的外键关系不复杂员工属于一个部门、一个职位薪资记录通过员工 ID 关联考勤记录同样关联员工 ID。难点不在表设计而在 MyBatis 的关联查询和动态 SQL 拼接。3.1 员工表字段与索引设计思路CREATE TABLE employee ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT 员工ID, emp_no VARCHAR(20) NOT NULL UNIQUE COMMENT 工号, emp_name VARCHAR(30) NOT NULL COMMENT 姓名, gender TINYINT DEFAULT 1 COMMENT 1男 0女, birth_date DATE COMMENT 出生日期, dept_id INT COMMENT 部门ID, position_id INT COMMENT 职位ID, phone VARCHAR(20) COMMENT 手机号, hire_date DATE COMMENT 入职日期, status TINYINT DEFAULT 1 COMMENT 1在职 0离职, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_dept (dept_id), KEY idx_position (position_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;设计时给dept_id和position_id加了普通索引而不是外键约束。理由很实际如果建立物理外键 FK员工删除时部门删除会被 MySQL 阻断管理系统的便捷操作会受影响。业务上部门删除前应该检查该部门下是否有在职员工这个逻辑放在 Service 层用代码控制更灵活而不是交给数据库约束。工号emp_no加唯一索引是必须的员工卡片上如果出现重复工号后续关联薪资和考勤会产生脏数据。3.2 Mapper XML 中 resultMap 与动态 SQL 的配合SSM 项目里实体类的属性命名是驼峰风格数据库字段是下划线风格例如createTime对应create_time。如果在spring-mybatis.xml里开启了驼峰映射那么不需要每个表都写 resultMap。但实际开发中多表联查的结果集往往不是单表实体类能直接映射的这时候 resultMap 的价值就体现出来了。resultMap idEmployeeDeptResult typecom.longteng.pojo.Employee id columnid propertyid/ result columnemp_no propertyempNo/ result columnemp_name propertyempName/ association propertydepartment javaTypecom.longteng.pojo.Department id columndept_id propertyid/ result columndept_name propertydeptName/ /association /resultMap这是员工模块列表页的典型写法。页面需要同时展示员工所属部门名称而不是显示 dept_id 数字。用association标签嵌套关联对象比分开两次查询更省事MyBatis 会自动处理 N1 问题——只要 SQL 用的是 JOIN 而不是子查询。动态 SQL 是员工管理模块查询功能的重点。管理人员经常需要按姓名、部门、状态、入职时间段组合筛选员工如果每个组合都写一个 Mapper 方法会爆炸。where标签能自动去掉第一个多余的 ANDif标签做非空判断这是 SSM 项目里查询条件组合的唯一正解。select idselectEmployeeByCondition resultMapEmployeeDeptResult SELECT e.*, d.dept_name FROM employee e LEFT JOIN department d ON e.dept_id d.id where if testempName ! null and empName ! AND e.emp_name LIKE CONCAT(%, #{empName}, %) /if if testdeptId ! null AND e.dept_id #{deptId} /if if teststatus ! null AND e.status #{status} /if /where ORDER BY e.id DESC /selectLIKE CONCAT(%, #{empName}, %)这样写是为了防止 SQL 注入。直接字符串拼接%${empName}%虽然能用但#{}走的是 PreparedStatement 预编译${}是字符串替换用户在搜索框里输入 OR 11 --就能拖出全表数据。这一点在答辩时被问到概率极高。提示如果查询超过两个表的关联建议拆成两个 Mapper 方法分别执行避免 MySQL 优化器在大数据量下的 JOIN 性能退化。3.3 薪资表和考勤表的定时数据特征薪资模块的设计要点是“按月生成不可覆盖”。薪资记录表结构上至少要有salary_month字段格式 2024-05和base_salary、bonus、deduction、final_salary四个金额字段。录入薪资条时Service 层必须校验同一员工同一月份只能存在一条记录。这里用一个联合唯一索引就能兜底ALTER TABLE salary ADD UNIQUE KEY uk_emp_month (emp_id, salary_month);考勤表则不同它的数据特征是高频追加。每天上下班各一条记录字段最少包含emp_id、work_date、check_in_time、check_out_time。项目需求中“上下班打卡查看考勤记录”这个描述看起来简单但实现时要注意一个边界check_out_time在当天第一次打卡时是 NULL必须在 Service 层判断该员工当天是否已有打卡记录第二次打卡才更新check_out_time而不是插入新记录。4. Controller-Service-Mapper 分层实现以员工模块和考勤打卡为例SSM 项目的代码组织讲究“薄 Controller、厚 Service”。Controller 只接收请求参数、调用 Service 并返回页面跳转或 JSON 数据所有业务规则唯一性校验、状态流转、数据组装都写在 Service 实现类里。这种分层的好处是如果以后要把 JSP 换成 Vue 接口Controller 甚至不用大改只改返回类型即可。4.1 Controller 层注解驱动与参数绑定Controller RequestMapping(/employee) public class EmployeeController { Autowired private EmployeeService employeeService; RequestMapping(/list) public String list(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, String empName, Integer deptId, Model model) { PageInfoEmployee pageInfo employeeService.findByCondition(pageNum, pageSize, empName, deptId); model.addAttribute(pageInfo, pageInfo); return employee/list; } RequestMapping(/delete) public String delete(RequestParam(id) Integer id) { employeeService.deleteEmployeeWithCheck(id); return redirect:/employee/list; } }Model是 SpringMVC 的数据载体把 Service 返回的分页对象放入 Model 后JSP 页面通过EL 表达式 JSTL就能直接渲染。delete方法返回redirect:前缀避免用户按 F5 刷新时重复提交删除请求——这是传统 JSP 系统中防止表单重复提交最简单有效的方案。RequestParam(defaultValue 1)的作用是当前端未传pageNum参数时默认取第一页同时把pageSize默认设为 10。列表页的分页条用 Bootstrap 的样式配合 JSTL 的c:forEach循环渲染页码按钮。4.2 Service 层事务控制与业务规则落地员工删除操作不能简单执行DELETE FROM employee WHERE id ?。一个在职员工名下可能关联薪资记录、考勤记录、培训记录直接删员工会让这些关联数据变成孤儿数据。在 Service 层做逻辑判断Service public class EmployeeServiceImpl implements EmployeeService { Autowired private EmployeeMapper employeeMapper; Autowired private SalaryMapper salaryMapper; Autowired private AttendanceMapper attendanceMapper; Override Transactional(rollbackFor Exception.class) public void deleteEmployeeWithCheck(Integer id) { Employee employee employeeMapper.selectByPrimaryKey(id); if (employee null) { throw new BusinessException(员工不存在); } if (employee.getStatus() 1) { throw new BusinessException(在职员工不允许删除请先办理离职); } int salaryCount salaryMapper.countByEmpId(id); if (salaryCount 0) { throw new BusinessException(该员工存在薪资记录确认清除薪资数据后再操作); } employeeMapper.deleteByPrimaryKey(id); } }Transactional(rollbackFor Exception.class)是 SSM 事务配置的核心。默认情况下 Spring 事务只对 RuntimeException 回滚受检异常如 IOException不会触发回滚。这里显式声明对所有异常回滚避免删除员工成功后清理关联数据时发生异常导致数据不一致。这类“物理删除受限”的做法实际开发中比硬删更安全也是在答辩中能展现工程经验的地方。考勤打卡的 Service 实现是另一个值得注意的业务规则。打卡接口接收员工 ID 和打卡方向1 上班 / 2 下班核心逻辑是判定当天记录是否存在public String punchCard(Integer empId, Integer direction) { String today LocalDate.now().toString(); Attendance record attendanceMapper.selectByEmpIdAndDate(empId, today); if (direction 1) { if (record ! null record.getCheckInTime() ! null) { return 今天已经打过上班卡; } if (record null) { attendanceMapper.insert(new Attendance(empId, today, LocalTime.now(), null)); } else { record.setCheckInTime(LocalTime.now()); attendanceMapper.updateByPrimaryKey(record); } } else if (direction 2) { if (record null || record.getCheckInTime() null) { return 未打上班卡不能打下班卡; } if (record.getCheckOutTime() ! null) { return 今天已经打过下班卡; } record.setCheckOutTime(LocalTime.now()); attendanceMapper.updateByPrimaryKey(record); } return 打卡成功; }这里用LocalDate.now()和LocalTime.now()替代了老项目的new Date()加SimpleDateFormat格式化JDK 8 的时间 API 在可读性和线程安全性上完胜。注意 MySQL 中DATE类型字段与LocalDate的映射无需额外转换MyBatis 3.4.6 已经支持 JSR-310 时间类型。但如果用的 MySQL 驱动是 5.1.47 之前的版本可能会报No value specified for parameter 1需要升级驱动或在 JDBC URL 上加useJDBCCompliantTimezoneShifttrue。4.3 Mapper 接口与 XML 映射的绑定规则MyBatis 的 Mapper 接口和 XML 文件通过命名空间绑定。接口方法名必须与 XML 中select、insert等标签的id完全一致参数类型和返回类型也要对应。例如public interface AttendanceMapper { Attendance selectByEmpIdAndDate(Param(empId) Integer empId, Param(workDate) String workDate); int insert(Attendance record); int updateByPrimaryKey(Attendance record); }XML 中select idselectByEmpIdAndDate resultTypecom.longteng.pojo.Attendance SELECT * FROM attendance WHERE emp_id #{empId} AND work_date #{workDate} LIMIT 1 /select方法参数有两个以上时必须用Param注解指定参数名否则 MyBatis 会提示BindingException。这个坑非常经典——单参数时可以不写Param但多参数时漏掉它运行期直接报错。在 Spring 容器中Mapper 接口的实现类是 MyBatis 通过动态代理生成的不需要写实现类。但要注意 XML 文件的路径必须在spring-mybatis.xml中用mapperLocations配置指到bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.longteng.dao/ property namesqlSessionFactoryBeanName valuesqlSessionFactory/ /bean扫描器会把com.longteng.dao包下所有接口自动注册成 Bean然后 Service 中直接Autowired注入即可。如果 XML 和接口不在同一个包路径下扫描器找不到对应 SQL也会在启动时报Invalid bound statement。5. JSP 视图与 JavaScript 交互Bootstrap 表格渲染和 JSON 数据接口传统 SSM 项目的前端是 JSP JSTL Bootstrap。这套组合没有前后端分离那么现代但胜在页面导航刷新模型简单数据回显直接。列表页用c:forEach循环生成表格行操作列放三个按钮修改、删除、详情。按钮绑定的事件里删除操作一般用 JavaScript 弹确认框。5.1 列表页 JSTL 渲染与分页条实现table classtable table-bordered table-hover thead tr th工号/th th姓名/th th部门/th th职位/th th入职日期/th th状态/th th操作/th /tr /thead tbody c:forEach items${pageInfo.list} varemp tr td${emp.empNo}/td td${emp.empName}/td td${emp.department.deptName}/td td${emp.position.positionName}/td td${emp.hireDate}/td td c:choose c:when test${emp.status 1} span classlabel label-success在职/span /c:when c:otherwise span classlabel label-default离职/span /c:otherwise /c:choose /td td a href${pageContext.request.contextPath}/employee/edit?id${emp.id} classbtn btn-primary btn-xs修改/a button onclickdeleteEmp(${emp.id}, ${emp.empName}) classbtn btn-danger btn-xs删除/button /td /tr /c:forEach /tbody /table${emp.department.deptName}这种链式属性访问依赖 Employee 实体类中的department属性非空。如果数据库中有员工dept_id为 NULL返回的department就是 null页面会直接报 500。所以查询 SQL 中要保证关联结果一定返回或者在 Service 中兜底设置空对象。${emp.hireDate}如果数据库字段是DATE类型在 EL 表达式中会默认输出yyyy-MM-dd格式但如果字段类型带时间部分页面会出现2024-05-12 00:00:00这样不友好的展示需要在实体类中对该属性加JsonFormat或页面格式化标签。分页条的原理是基于PageInfo对象MyBatis 分页插件 PageHelper 的产物的属性。pageInfo.pageNum是当前页码pageInfo.pages是总页数。点击页码时构造带查询条件的 URL把pageNum参数传给后台重新查询。这里要保留empName和deptId作为查询条件的隐藏参数否则点第二页时查询条件会丢失。5.2 考勤打卡页的 Ajax 与 JSON 交互写法考勤打卡的交互场景比较特殊员工点击按钮打上班卡或下班卡后台返回成功或失败消息但不能刷新整页否则刚打上的卡看不到反馈。所以这里用 jQuery 的$.post发送异步请求处理响应的 JSON 数据。function punchCard(direction) { var empId $(#employeeId).val(); if (!empId) { alert(请先选择员工); return; } $.post(contextPath /attendance/punch, { empId: empId, direction: direction }, function (data) { if (data.success) { $(#msg).text(data.message).css(color, green); loadingTodayRecord(empId); } else { $(#msg).text(data.message).css(color, red); } }, json); }这里对应的 Controller 返回类型是ResponseBody MapString, Object。Spring 容器中要配置MappingJackson2HttpMessageConverter才能把 Map 序列化成 JSON 字符串但 SpringMVC 4.x 的注解驱动配置会自动注册这个转换器。前提是 pom.xml 中引入了 Jackson 的依赖包。如果项目用的 JSON 工具是 fastjson 或 Gson需要在spring-mvc.xml中手动配置消息转换器否则前端接收到的可能是一个字符串而非 JSON 对象。提示考勤打卡接口如果用了ResponseBody返回值不能是字符串。统一封装成{ success: true, message: 打卡成功 }这种结构前端判断data.success后再做 DOM 操作。老项目里直接返回提示文本导致前端只能alert(data)体验很差。项目自带的 JS 方法里queryAttendance函数会把当天考勤记录以表格形式展示传入参数是员工 ID 和日期范围。5.3 培训管理与部门管理的页面数据回显技巧培训管理模块的增删改查相对独立但有一个页面回显的细节值得记录编辑培训时页面需要展示培训开始时间和结束时间。实体类中如果是Date类型JSP 的input typedate控件不能直接绑定需要先在 Controller 中转成字符串格式再放入 ModelGetMapping(/edit) public String edit(RequestParam(id) Integer id, Model model) { Training training trainingService.getById(id); SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); model.addAttribute(startDateStr, sdf.format(training.getStartDate())); model.addAttribute(endDateStr, sdf.format(training.getEndDate())); model.addAttribute(training, training); return training/edit; }这样在 JSP 里input value${startDateStr}就能正常回显。部门管理模块则更简单一个department表只有id、dept_name、description三个字段它的增删改查可以作为上手练手的第一个模块把 Controller、Service、Mapper 三层各写一遍再扩展到其他模块。6. 登录拦截、权限控制与部署到 Tomcat 的避坑清单这套系统的登录拦截逻辑在spring-mvc.xml中配置用 SpringMVC 的HandlerInterceptor手动实现。它的作用是用户访问任何非登录页面时先经过拦截器判断 session 中是否存在登录用户不存在则重定向到登录页。这种方式在传统 JSP 项目中被广泛使用后续如果要替换成 Spring Security 或 Shiro也只需把这个拦截器替换掉。6.1 拦截器配置与静态资源放行public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user request.getSession().getAttribute(loginUser); if (user null) { String requestURI request.getRequestURI(); if (requestURI.contains(/login) || requestURI.contains(/css) || requestURI.contains(/js) || requestURI.contains(/images)) { return true; } response.sendRedirect(request.getContextPath() /login); return false; } return true; } }注意拦截器里对/css、/js的放行是必要的。Bootstrap 的 CSS 和 jQuery 文件如果被拦截页面样式会全部丢失以及图片和字体文件也会 404。更优雅的做法是在spring-mvc.xml中单独配置mvc:resources mapping/static/** location/static/把所有静态资源放在webapp/static目录下。登录验证的逻辑要放在 Controller 层Session 中存的loginUser是一个实体对象而非用户名字符串。相较只存昵称存对象的好处是后续任何页面要显示当前登录人的部门或角色时直接sessionScope.loginUser.deptName即可。登录密码一般用 MD5 加盐存储虽然从安全角度看强度不够但这个项目没有引入 shiro 等权限框架Unsalted MD5在毕业设计中作为教学展示是合理的。6.2 部署到 Tomcat 前必查的 5 个配置点mvn clean package -DskipTests打包之前需要逐项检查以下内容防止启动失败或页面 404检查项具体内容错误表现jdbc.properties数据库账号密码确认与本地 MySQL 一致Access denied for userMySQL 是否创建数据库和导入脚本Navicat 执行longteng_db.sqlUnknown databaseweb.xml中的启动顺序Spring 根容器先于 SpringMVC 加载启动报No bean namedTomcat 7 的 JDK 版本必须是 JDK 8UnsupportedClassVersionError项目编码格式IDEA 中统一 UTF-8页面中文乱码如果 Tomcat 启动后访问页面报 404优先检查WEB-INF下 JSP 文件路径与spring-mvc.xml视图解析器的prefix是否匹配。例如视图解析器配置了/WEB-INF/jsp/Controller 返回employee/list实际寻找的是/WEB-INF/jsp/employee/list.jsp文件放错位置就会 404。6.3 一个常见问题静态资源 JS 文件不给浏览器缓存怎么办JSP 页面引用的 JS 和 CSS 文件在 Tomcat 7 下如果没有设置 Expires 头每次刷新都会重新发送 HTTP 请求。开发期无感知但部署到演示环境后首屏会很慢。可以在 web.xml 中配置一个 filter 设置缓存头filter filter-namecacheFilter/filter-name filter-classcom.longteng.utils.CacheFilter/filter-class init-param param-namecacheTime/param-name param-value3600/param-value /init-param /filter对应的CacheFilter类需要实现javax.servlet.Filter在doFilter中判断请求路径后缀如果是.css、.js、.jpg等文件类型则设置response.setHeader(Cache-Control, max-age cacheTime)否则不设置直接放行。这个项目在启动时还会打印一条log4j:WARN No appenders could be found for logger的警告它不是错误但会在log4j.properties中补上 rootLogger 配置把输出的日志级别设为INFO并指定控制台和文件输出这样后续排错时能查到关键业务日志。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

百点POE温湿度变送器并发卡顿?从串行轮询到异步并发的全链路优化实践 2026/9/12 18:21:57

百点POE温湿度变送器并发卡顿?从串行轮询到异步并发的全链路优化实践

1. 问题场景:百点POE温湿度变送器并发为何一到高峰就卡成PPT先说结论:这不是一次简单的调参,而是把整套上报链路重新梳理了一遍。项目是某个厂区环境监测系统,现场部署了100个POE温湿度变送器,全部走以太网供电和Modbu…

阅读更多 →
基于QT的地图导航系统与Dijkstra最短路径算法实战 2026/9/12 18:21:57

基于QT的地图导航系统与Dijkstra最短路径算法实战

简介:基于QT实现的地图导航系统是一份面向C/QT初中级学习者的完整项目源码,以Dijkstra算法为核心实现最短路径规划。项目包含登录窗口、地图展示、路径搜索与结果显示等完整交互流程,覆盖了QT信号槽机制、QGraphicsView场景绘制、邻接表地图建…

阅读更多 →
千笔学术智能体:中文AI论文写作与文献分析工具 2026/9/12 18:21:57

千笔学术智能体:中文AI论文写作与文献分析工具

1. 项目概述:千笔专业学术智能体的核心价值 作为一名在学术工具领域深耕多年的从业者,我见证过太多打着"AI辅助"旗号却让普通用户望而却步的论文工具。直到遇到千笔这个产品,才真正理解什么叫"技术民主化"——它用三个突…

阅读更多 →
低功耗开发实战:从芯片手册到实测电流的硬核路径 2026/9/12 18:21:57

低功耗开发实战:从芯片手册到实测电流的硬核路径

1. 这不是“省电小技巧”,而是设备工程师的生存基本功 低功耗开发,四个字听着像手机设置里调个深色模式那么简单——但如果你真这么想,刚入职第一天就可能被硬件主管叫去会议室“喝茶”。我带过的三届应届生里,八成以上在第一次功…

阅读更多 →
大模型技术在企业数字化转型中的战略应用与实践 2026/9/12 18:21:57

大模型技术在企业数字化转型中的战略应用与实践

1. 大模型技术在企业中的战略定位大模型技术正在重塑企业数字化转型的版图。作为人工智能领域最具颠覆性的技术突破,大模型通过其强大的自然语言理解、生成和推理能力,正在改变企业获取、处理和利用知识的方式。不同于传统的AI解决方案,大模型…

阅读更多 →
OptiSystem光通信仿真入门与实践指南 2026/9/12 18:18:57

OptiSystem光通信仿真入门与实践指南

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞