Java SSM + Flask 混合架构:工作日志办公自动化系统实战
说实话很多公司的工作日志就是这么写出来的——先做一小时表格再找一个同事互相催等到月底盘点的时候领导翻遍十页记录也说不清这周到底干了啥。我自己在企业里做过几版办公信息化的东西对这种场景太熟悉了。日志不是不好是工具不行大家要么在微信群里贴一段话要么用Excel填完就没人看数据没办法汇总也谈不上什么协同。所以这次我决定自己动手做一个真正用得上、也愿意被人每天打开的工作日志办公系统。这个项目尝试用一套很务实的混合技术路线主体用Java和SSM搭起来负责用户管理、日志流转、审核流程这部分核心业务穿插一个Flask服务专门做统计汇总、定时提醒、报表导出这类独立的辅助能力。整套下来不追求花哨核心目标就是把员工日常记录、办公自动化、协同办公、工作流程管理这些场景串成一条顺畅的线让团队成员和主管都能从里面真正省时间。下面这篇文章是完整的项目复盘。我不光说功能也会把数据库怎么设计、SSM和Flask怎么分工、调试时我踩过哪些坑还有部署上线的细节都拆开讲。如果你正在做类似的办公系统、毕业设计或者想在企业里改进团队日志管理这篇内容可以直接当参考。1. 项目思路拆解工作日志系统到底该管些什么1.1 先盘一下日常办公里那些让人心累的日志问题我以前去一家制造业企业调研的时候他们当时的日志管理方式是“部门群打卡”。员工在群里发一段文字部门主管每周五去翻聊天记录谁发了谁没发只能人工数。到了月底行政要把这些零散内容整理成汇报给老板看的周报月报那叫一个痛苦复制粘贴、格式错乱、内容缺页最后还得靠同事主动“帮忙回忆”。更离谱的是因为文字都在群里换个人根本没法检索以前干了什么想复盘项目等于把群消息翻一遍这效率基本为零。我对这类需求的总结很简单企业要的不光大屏幕展示四个点必须得稳——每日填写要方便审核流转要清晰谁提交没提交要一眼能看到月底统计要自动化。如果这四件事都要靠人肉处理那开发软件意义就不大。所以我做这套系统的定位很明确它就是一个以工作日志为中心、附带办公自动化管理流程的轻量级协同工具。员工进入系统后最常用的是“写日志”和“看我的记录”主管看到的是“团队日志列表、审核与评论”管理员负责“账号分配、部门组织、日志抽查”老板或者高层最后只需要打开“汇总看板”一目了然团队运转情况。一句话概括这套系统的核心价值不是让员工被动地去记流水账而是把日志变成管理者可以依托的决策数据。这也是为什么我在设计表结构和状态机的时候特意留了一块给“审核意见”和“日志评分”的字段——日志最终要进入管理闭环。1.2 角色划分和业务流程从填写到归档的一条完整链路系统里我规划了三种基础角色普通员工、部门主管、系统管理员。实际使用的时候主管可以继续往上叠层级比如大主管能看到多个部门的日志但最小闭环还是这三角色。它们之间组成一条比较经典的流程员工登录后选择日期、填写今日工作内容、明日计划、遇到的问题、加班时长等先存草稿再正式提交。主管在每个工作日快结束时查看未审核列表逐条审核给通过或退回的结论退回时要填写意见员工能及时收到提醒并修改重新提交。管理员不定期抽查各团队的提交情况通过统计看板判断某部门是否存在大量未提交、未审核积压等问题。状态流转这块我只设置四个枚举值0草稿、1待审核、2已通过、3已退回。前期不搞太复杂像什么“已转发”“已归档”的过渡态在真实使用中反而会让员工困惑。每个日志有任何一次状态变化我都会在日志历史表里留一条痕迹做后期数据追溯审计。有人问我日志系统要不要做成类似“工作流”那种能自定义审批链根据实际经验员工日报、周报的审批链路并不适合搞太深。日常办公系统讲究的是快速闭环一般一到两级审批就够。我在系统里虽然留了部门-子部门的层级关系但日志审批默认就一级主管退回即可让员工重新处理。如果你以后想扩成“部门主管部门总监总经理”三层审批把审批表单独抽出来加一个level字段即可。1.3 技术选型怎么想为什么跨了Java和Python两套生态我确定技术方案没花太多时间。主后端用Java的SSM框架组合也就是Spring、SpringMVC、MyBatis这不是为了追冷门而是这套组合做企业管理系统特别合适Spring负责把对象关系管得明明白白SpringMVC处理HTTP请求的分发MyBatis写SQL特别灵活适合处理工作日志这种查询条件经常变化的业务。Java生态本身的稳定性和团队接手成本让我可以放心把最核心、最不能出错的业务流程放在上面。比如用户登录、权限拦截、日志CRUD、审核这几个操作都必须在强事务和可靠状态管理下运行SSM天然擅长这类场景。而Flask的出场是解决掉那些跟主业务“没那么强耦合”、但实际又很烦人的事情。我做系统的时候很烦一件事日志数据的统计报表写起来不复杂但在Java里面要导Excel、配定时任务、再做图表接口代码量不小。其实用Python的Flask处理这类“辅助计算”非常轻巧接口开发速度快代码可维护性好配合pandas处理数据也很顺手。于是最后的架构是这样的Java SSM跑在Tomcat上提供全部核心业务接口和页面Flask部署成独立服务只负责接收由Java转发过来的统计查询请求然后执行汇总计算返回JSON数据Java再把数据整合到Web页面上展示。定时提醒方面我也交给Flask用APScheduler每天定时扫描当天日志提交情况直接调用企业内部通讯工具或邮件接口发送提醒。这种混合架构不稀奇但现在写代码讲求实用哪块顺手就用哪块。Java管业务管事务Flask管数据和任务两台服务各自独立挂了还能互不影响部署上也更灵活。需要注意的是两个服务之间的接口报文要约定清晰比如统一返回格式里必须有code、message、data三段避免两边对接的时候对不上字段名。2. 系统设计与数据库表结构先把地基打结实2.1 分层架构与模块划分我的代码组织是经典的SSM三层加上一个独立的Python服务层。在Java端Controller层只做参数校验和视图转发不写任何业务SQLService层处理业务逻辑事务边界基本都放在这里Mapper层保持接口清爽SQL统一写在XML文件里方便后期调优。模块划分按功能拆成这样的包结构user用户、department部门、worklog日志、approval审核、statistics汇总、common通用工具类。每个模块独立成包互相之间通过Service接口调用没有跨模块的零散引用。Flask端就简单很多我不建复杂的项目模型直接按文件划分app.py负责接口路由和启动stats_service.py里面是各类汇总计算函数reminder.py放定时任务database.py里面抽象统一的数据库连接方法。为什么不在Flask里再用一套ORM在这种场景下没有意义。统计查询本身以读多写少为主直接封装SQL游标操作比使用ORM性能更好而且写出来的代码所有人都能看懂。总体分层和数据流向是这样的前端页面JSP或者Bootstrap页面请求Java Controllers。Java Service层处理核心业务如果涉及统计分析就调用RestTemplate向Flask服务发起HTTP请求。Flask访问同一套MySQL数据库执行聚合查询返回统计结果。Java再把统计结果返回给页面渲染。这里有个关键点Flask和Java共享同一套MySQL数据库但两边读写权限又做了区分。比如日志状态表只有Java端可以写Flask只做聚合查询不直接去改业务表的记录。这个约定避免两边同时维护状态导致数据不一致。2.2 核心表结构日志、用户、审批、通知各自精心设计数据库我用的是MySQL 5.7字符集统一utf8mb4存储引擎InnoDB。表不多但每张表字段都经过仔细考虑。最核心的几张表列出来给大家参考一张是用户表user_info字段我为id、username、password、real_name、role_type、department_id、status、create_time。密码存储用的是加盐MD5虽然现在已经有很多更高级的加密方式但对于内部办公项目加盐后复杂度已经能扛住常规风险。加盐的逻辑是取用户名加固定盐串拼接后再MD5保证就算未来数据库泄露攻击者想逆推原始密码难度也变大。一张是部门表department我没有设计成多叉树结构就只做了两级parent_id表示上级部门。为什么不用经典递归树对中小型企业办公系统来说两级部门基本够用再深的层级管理成本高收益不明显。如果你非要上级审批多层级那department表需要自关联多级同时审批逻辑要改成递归查询上级再往上传递。日志表work_log是整个业务的核心。字段要重点说date字段是记录日期work_content是今日完成内容plan_content是明日计划problem字段记录遇到的问题或者风险work_hours记录当天工作量估计status是状态submit_time是员工点击提交的时间audit_time是主管审核时间audit_user_id是审核人ID。这里有潜在一坑名字千万别用date或者desc之类的保留字我在建表初期就是因为表名和字段名都叫log结果跑SQL报了一堆错后来统一改成work_log避开。审批表approval_record单独拎出来记录work_log_id、operator_id、action_type、comment、create_time用于留存完整的审批痕迹。我当时坚持这张表必须独立因为后续做审计查询的时候非常有用你可以清晰知道一条日志从草稿到通过经历了哪些人、看了几次。通知消息表notice_message负责在日志被退回或者月底未提交提醒时给用户发站内消息。字段包括user_id、content、is_read、create_time。Flask定时提醒任务写入的就是这张表Java端在用户登录后查询未读消息数展示。这里有一个体验优化点阅读状态最好用数字0/1别用字符串后续统计未读率这类指标的时候方便直接用SQL聚合。2.3 状态机和关键约束怎么设计我在设计初期就把日志状态定义清楚并且在后端写了一个校验类统一控制状态修改的合法范围不让业务层到处写if判断。允许的变迁只有四条路草稿到待审核、待审核到已通过、待审核到已退回、已退回到待审核。这条规则在Java端和Flask端都要校验。虽然是重复劳动但防止两位服务各按各的理解开放错误接口造成数据错乱。索引设计方面work_log表我建立了两组索引work_log_user_date_index(user_id, log_date)因为员工查自己某天的日志很频繁work_log_status_time_index(status, submit_time)主管查某状态下待审核日志的时候会走到这组索引。很多新人做日志系统最容易忽略的就是提交时间这个字段等到数据量上来后台列表页每一页都要等好几秒这时候加索引就晚了。还有审批表必须对work_log_id建索引。约束上比较关键的一点是一个人一天只能有一条工作日志提交给系统不然同一个日期多条记录主管审核起来完全没法弄。这个唯一索引我直接建在user_id和log_date上。业务还会遇到员工忘了提交昨天的日志想补提交怎么办我在前端也做了控制默认只开放最近三天内可补录超过三天要走主管开放的特殊权限这是为了降低数据造假的可能。3. 核心功能实现SSM业务处理和界面衔接3.1 登录鉴权和权限控制登录这块我用SpringMVC拦截器实现会话管理。登录成功后把用户ID和姓名放进session同时存了角色类型。拦截器里有两个核心逻辑一是判断当前session是否有效二是判断当前请求路径的权限要求是否匹配用户角色。以前我偷懒用注解加AOP做权限控制后来发现有些请求路径没被扫描到还是会出现权限漏洞。这次直接在拦截器里维护一个URL权限映射表普通员工只能访问以/user/开头的路径主管额外能访问/audit/管理员能访问/admin/兜底规则是不允许访问不属于自己角色的路径。密码安全我现在也做加强了一遍。除了登录时MD5加盐比较还对连续登录失败次数做了处理。登录失败超过5次账号锁定15分钟防止工作上有人恶意尝试别人账号。另外一个细节是改密码的时候新密码不能和旧密码相同这个用history表记录最近三次密码哈希值。前端我并没有赶时髦做前后端分离采用的还是JSP加Bootstrap的组合。为什么因为办公系统追求的是内部员工能快速上手JSP渲染加上Java端控制视图彻底免掉跨域、Token刷新这一堆破事整体链路最简单。不过新开发的项目已经开始用Vue这种老的JSP方式可能在团队交流中显得落后我只是自己找平衡点。如果你想用前后端分离做可以只保留Java端的REST接口模板替换成前端工程即可。3.2 工作日志的填报表单与保存逻辑日志填报页面是每员工天天要面对的东西我花了不少心思做简单明了。表单字段就是日期、今日内容、明日计划、遇到的问题、预估工时这五项。最初版本还加了加班小时、出差地点、参与项目编号结果是员工填写的平均时长翻了倍后来一刀砍掉只留核心。有些信息确实有价值但不是所有团队都需要所以我把这些字段做成可配置项启用配置项后表单才显示默认关闭。保存逻辑分两种存草稿和正式提交。存草稿是把字段内容先写库状态置0员工下班前随时可以继续改。正式提交则要校验内容长度和填写完整性至少大于20个字才能提交同时明日计划也不能为空避免员工纯粹在应付。这里我特别说一下提交后能否反悔的事。员工正式提交后如果发现写错了想撤回来改系统一般不会立刻开放这个权限得走流程。我的实现方式是员工可以“撤回申请”把日志状态从待审核打回草稿但要求当天撤回次数不超过两次并且撤回行为会记录在审批表中。这个逻辑一开始没有结果有员工提交后进行多次撤回修改给主管的审核任务里积累一大堆重复的待审核日志所以加了次数限制后续体验稳定很多。3.3 主管审核页面和批量处理主管登录后首页显示的就是待审核的工作日志列表。我按照提交时间倒序排优先显示快到截止时间那些。每一条日志卡片除了显示内容还要显示提交时长和超时标记。如果日志是昨晚提交的今天还没有审核那它就要在列表顶部标成黄色待办颜色别用红色红色留给已超时48小时的。审核操作分通过、退回两个动作。通过只要点一下即可退回必须填写意见没有意见就不能退这个校验卡得很死。我当时遇到过一个痛点主管批量审核的时候退出后忘了填原因员工不知道自己哪里需要改然后又原样提交一次循环了好几次主管反而更累。加了必填意见之后这类退改循环大幅减少。批量审核是提升主管效率的关键。页面上提供一个勾选框主管可以一次勾选最多20条日志批量通过。但我特意不做批量退回因为退回必须逐条写针对性意见否则失去意义。如果某个员工长期未提交或者内容质量差主管可以在员工列表里给他打一个“重点关注”标注后续他的日志会在主管视图里优先展示。这算是一个从工作日志系统延伸到团队管理的实用功能。3.4 统计看板和通知提醒如何实现统计看板不是单靠Java就能好看的。我在Java端提供一个/dashboard接口它在内部请求Flask服务的/stats/summary接口这是整套系统里最有技术价值的一段联动。Flask在这个环节干的事情是连接MySQL日志表按部门、按状态、按日期这三个维度做聚合。返回的数据结构类似这样{ code: 0, data: { total: 2350, department: [ {dept_name: 研发部, submit_count: 420, unsubmit_count: 12, pass_rate: 0.93} ], trend: [ {date: 2025-01-10, count: 120} ] } }Java拿到这份JSON后把它拆成图表组件需要的数据格式渲染到页面。我前端的图表用ECharts实现不需要重新发明轮子。首页上会展示团队近7天提交趋势、未提交部门排行榜、审核通过率。主管点开排行榜能看到自己部门哪些员工连续3天以上没提交日志这对团队管理来说是很有用的中远期参考。提醒通知这块还是Flask的APScheduler负责。每天早上10点自动扫描前一天的日志提交情况如果某员工有未提交标记就通过插入notice_message表实现站内信提醒。因为我本身不想让Flask过度依赖企业内部邮箱发送规则所以提醒就是“站内信对接企业群里机器人推送”两种方式。实际用下来站内信确实有用但很多人不会主动看系统消息所以更好的办法是在员工邮箱侧做转发这个留给你们根据公司条件扩展。3.5 Flask服务的具体实现要点Flask服务整个工程很精简我贴一下骨架和核心接口的实现思路from flask import Flask, jsonify, request import pymysql app Flask(__name__) DB_CONFIG { host: 127.0.0.1, user: worklog_user, password: ******, database: worklog_db, charset: utf8mb4 } app.route(/stats/summary, methods[GET]) def stats_summary(): dept_id request.args.get(dept_id, 0, typeint) date_from request.args.get(date_from, ) date_to request.args.get(date_to, ) data aggregate_stats(dept_id, date_from, date_to) return jsonify({code: 0, message: ok, data: data})aggregate_stats负责根据传入参数执行几条SQL。先取部门列表然后按部门和状态分组统计提交数未提交数再查近期每日提交量。我做了一个比较重要的微调如果查询区间超过31天直接限制最大31天避免一次查一年数据拖垮MySQL。统计页面提供“近7天”“近30天”“自定义区间”三个快捷按钮对绝大多数管理场景够用了。定时提醒的代码也不复杂就是一个while周期函数每分钟检查当前时刻是否到达预设提醒批次。不过我用APScheduler更标准直接配置cron触发器即可。Flask服务里不直接写业务逻辑只做数据读取和汇总这既是安全考虑也是避免两个服务通过不同的代码路径去写数据库导致锁竞争。4. 调试文档与部署上线从本地跑起来到服务器稳定运行4.1 开发环境准备和参数配置这个系统常规开发环境我建议是JDK 1.8、Tomcat 9、Maven 3.6、MySQL 5.7或8.0、Python 3.8以上。这些版本组合我已经跑了很久兼容性没有踩到特别离谱的坑。JDK版本别贪新办公系统追求稳JDK8已经能支持绝大多数开源库新出的一些框架特性在这个场景没有必须性。Java端需要注意的三个配置文件分别处理数据库连接、Spring、SpringMVC第一个是jdbc.properties设置数据库连接参数关键是要加上useUnicodetrue和characterEncodingutf8否则中文写入很可能乱码这是最容易犯的错。数据源我用的是Druid连接池不是HikariCP主要考虑Druid自带监控页面方便我远程查看SQL执行峰值。第二个是spring-mybatis.xml里面配置SqlSessionFactory和MapperScannerConfigurer要指定mapper-locations指向XML目录这样接口和SQL映射才绑定得上。事务管理我开启annotation方式Service层注上Transactional就自动有事务。第三个是spring-mvc.xml开启注解驱动和组件扫描。视图解析器指向/WEB-INF/views/静态资源放/resources/下。编码过滤器设为UTF-8这个东西不配会严重影响表单提交时的中文数据。Flask端的环境配置我用虚拟环境隔离requirements.txt里固定Flask版本2.2.5pymysql版本1.0.2APScheduler版本3.10.4。为什么锁版本这两个库版本升级后API变化挺大以前我遇到过一次升级APScheduler之后定时任务全部不执行排查到一晚上最后还是降版本解决。所以依赖版本锁死越稳越好。4.2 本地联调过程要做什么本地跑起来后第一件事不是点页面而是先把接口调通。我通常用Postman构建请求集合按模块一个一个测。顺序是登录接口、部门列表接口、日志提交接口、审核接口、统计接口。每个接口先测正常参数再测边界参数比如日志内容传空字符串、日志日期传非法格式、未登录直接访问受保护接口这些边界场景都要覆盖到。调试日志我是认真写的。Java端用Logback把输出分成三个级别和三个文件debug.log记录SQL和执行参数info.log记录Controller层的请求信息和业务操作error.log只记录异常。这样排查问题的时候直接看对应文件不用去服务器上翻一大坨控制台。Flask端我也配置了logging把请求日志单独输出到flask_app.log。调试日志这件事很多开发初期会嫌麻烦但联调期全靠它救人。我曾经遇到过一次登录后页面直接404查了很久发现是权限拦截器把未登录请求重定向到登录页结果登录页路径本身又需要登录权限形成一个循环重定向。当时如果没有debug日志里的请求路径输出这种问题很难快速定位后来我做权限拦截器时总会额外加一个白名单列表把登录页、静态资源、验证码接口全部排除在外。4.3 服务器部署流程和进程守护生产环境我的部署方式比较朴素一台服务器上跑两个服务。Java端打成war包部署到Tomcat的webapps目录Flask用nohup启动通过Nginx反向代理统一端口入口把外部80端口的请求路径转到Tomcat或Flask。这里给出Flask部署用到的命令cd /opt/worklog/flask-service source venv/bin/activate nohup python app.py --host0.0.0.0 --port5001 flask.log 21 Java端的Tomcat不在8080端口我用默认8080然后Nginx配置里对/api/stats/路径proxy_pass到127.0.0.1:5001其他路径全部proxy_pass到127.0.0.1:8080。这样外部只需要开放80端口内部服务通过主机内部IP通信减少了暴露的端口面。进程守护方面我用systemd管理Flask服务。因为nohup启动如果服务器重启服务就丢了还要人肉重启这不行。写一个worklog-flask.service单元文件RestartalwaysRestartSec5万一服务意外退出systemd会拉回来。Java端因为跑在Tomcat里面我把Tomcat也注册成systemd服务统一开机自启。Flask服务单线程跑统计还好但如果并发上来也不行。我建议用waitress这种纯Python的WSGI服务器替代内置的dev server性能比flask自带的开发服务器靠谱很多。部署时把app.py改造成让waitress servefrom waitress import serve app create_app() serve(app, host0.0.0.0, port5001, threads8)threads设成8对于这种内部办公系统足够用了。如果未来访问量暴涨Flask端可以考虑用gunicorn或者加一层负载均衡但现阶段没必要。4.4 联调时常见的跨服务问题怎么排查Java端调用Flask服务用的是RestTemplateI was initializing it without custom timeout结果某一次Flask服务繁忙Java端线程阻塞好几秒直接拖慢主页面。后来在RestTemplate上显式设置了connectTimeout和readTimeout分别5秒和8秒。这里有一个设计思路要分享主业务流程不能因为辅助服务故障而卡死。所以Java调用Flask统计接口时我会捕获超时异常降级返回缓存中最近一次统计数据或者空的占位图而不是整个页面报错。辅助服务挂了不影响主流程这是混合架构的一个天然优势。跨服务字段对应也是个坑。Java端实体类里字段叫createTimeFlask端SQL查出来字段是create_time两边直接转换的时候就很别扭。我后来统一约定对外接口字段一律下划线风格Java端用JsonProperty注解映射这样彻底解决了两边的命名争议。现在回想起来这种接口约定应该在写代码之前就定好完全属于先期设计考虑不周。再有一个就是编码问题。两台服务如果连接数据库设置不一致Flask返回的中文可能在接收端直接乱码。MySQL连接参数里characterEncodingutf8加上服务端保持utf8mb4其他环节都保持UTF-8很少再遇到乱码。如果还乱就检查Tomcat的server.xml里URIEncoding是不是设置成了UTF-8。5. 实操过程中的高频坑和排查经验5.1 时间字段那件事本地时间、服务器时间、数据库时间总会打架日志系统对时间很敏感。员工填A天日志应该是基于他自己本地时间但服务器可能部署在另一个时区数据库默认时间也有偏差。我在设计上做了一个强制约定所有前端提交的日期时间参数都统一传字符串后端解析后使用DateUtils工具类转成当前系统时区时间数据库连接参数serverTimezone设置为Asia/Shanghai。这样最大程度避免时区不同产生的八小时偏差。另一个经验是统计看板的日维度统计不要用NOW()函数而是用当天的00:00:00作为区间左边界。具体SQL写法就是WHERE submit_time 2025-01-10 00:00:00 AND submit_time 2025-01-11 00:00:00而不是用DATE()函数包住字段去比较。原因很简单DATE()包住字段之后MySQL这个字段上的索引就失效了数据量大了查询会变慢。日期的查询区间要这样写不然索引优化等于白做。5.2 MyBatis动态SQL和分页优化日志查询条件本来就多按部门、按员工、按日期、按状态、按关键字如果我把每种组合都写一条SQL那Mapper文件会爆炸。我利用MyBatis的动态SQL通过if标签拼接条件让一条查询方法适用所有组合select idselectLogList resultTypeWorkLogVO SELECT wl.*, ui.real_name, dept.dept_name FROM work_log wl JOIN user_info ui ON wl.user_id ui.id LEFT JOIN department dept ON ui.department_id dept.id where if testdeptId ! null and deptId ! 0 AND dept.id #{deptId} /if if teststatus ! null AND wl.status #{status} /if if testkeyword ! null and keyword ! AND (wl.work_content LIKE CONCAT(%, #{keyword}, %) OR wl.problem LIKE CONCAT(%, #{keyword}, %)) /if /where ORDER BY wl.submit_time DESC /select分页这块我用的PageHelper插件但有个巨坑PageHelper在使用的时候分页参数必须紧跟第一条SQL语句如果中间插了别的东西分页会失效。我印象里有一次在Service里先查了员工总数再查日志列表分页突然怎么都不生效最后排查发现是PageHelper的PageMethod在多个查询前无法正确识别目标语句。解决办法是尽量在一个Mapper方法内完成查询与分页不让Service层做跨查询的分页。5.3 跨域问题前后端分离页面和Flask接口怎么配合因为我的系统本质上不是完全前后端分离跨域问题少很多。但如果你要用Vue工程做前端页面请求JAVA接口而JAVA又去请求Flask接口那跨域可能就会出现。我的经验是JAVA作为服务端请求服务端根本不存在跨域跨域只发生在浏览器直接向Flask发请求时。所以要么Nginx统一转发同一域名的请求要么在Flask端加上CORS配置。CORS配置别滥用。如果只允许办公系统后台域访问统计接口那么在Flask端用flask-cors库指定origins白名单。我见过有同学图省事直接CORS全开放这相当于约等于允许任何站点脚本读取统计接口数据内部数据安全就会出问题。5.4 权限控制要精细到什么程度整个系统权限控制我迭代过好几个版本。最开始只做了登录和角色判断后面发现一些低级别的权限漏洞。比如普通员工直接拼URL访问/audit/list接口他是否能拉到整个公司的日志答案在旧版本里是“能”因为拦截器只检查了登录状态没有检查角色。后来我改造为URL前缀和角色绑定并且在Service层再校验一遍当前登录用户是否有权访问目标部门的数据。这就是所谓“后台权限二次校验”虽然代码冗余一点但站在管理系统的角度权限校验永远不能只靠前端跳转隐藏在页面上。还有一处容易漏的是数据范围权限。普通主管默认只能看到自己部门的日志。但如果某个员工调岗了他的历史日志归属部门怎么算我采用了一个比较省事但有效的办法日志归属不按员工当前部门动态查找而是在员工入部门时把部门快照写进日志记录中也就是在work_log表里冗余一个department_id字段。这样无论员工调动去哪个部门他过去的日志还留在原部门的统计数据里。这个设计可能跟业务期望不符如果你希望调动后日志归属新部门那删除冗余字段动态查询即可按公司管理制度来定就行。5.5 定时任务漏跑和重复通知的控制Flask端定时任务有一个很典型的问题如果服务在触发时间点因为重启等原因错过了任务APScheduler默认策略就是在重启后立即补跑漏掉的任务这可能造成重复通知。我这里的处理方案是加一个执行记录表task_exec_log每次任务执行前先查询该任务在目标日期是否已经执行过执行过则跳过。这个表就是一专多能还能顺便做数据统计看看每月的提醒发送成功了多少条。另外定时任务要记得处理员工请假和周末休息的情况。我的默认实现是周一至周五才提醒周末和工作日之外的法定假日不提醒。但公司不同所以我留了一个holiday配置表管理员可以在后台勾选特殊日期或者一键标记为“非工作日”。这个小功能后来被广泛使用不然法定节假日那天员工收到日志提醒会很烦。6. 这个项目做到现在我最想跟你分享的三句话让我用经验来收尾好了。第一办公系统最大的技术难点从来不在代码复杂程度上而在对人的使用习惯的尊重。日志页面默认展示当日日期、把表单字段减到最少、审核页面批量操作顺滑这些体验细节比任何炫酷框架都更能决定员工愿不愿意每天用。第二把Java和Flask放一起用看着累赘实际上分工明确就是最高效。Java负责把业务逻辑焊死Flask用它的轻和快专门处理统计和任务调度两套代码互不干扰。以后你想换掉任何一边接口不动整个系统依然能跑。第三调试文档一定要在开发过程中同步写别等项目快交付才开始补。我这次的调试文档是按照功能模块和常见问题两部分组织的排查问题时直接搜关键词节省的时间远超写它用的时间。真到出问题的时候最便宜的工具就是一份你随时看得懂的日志和一张清晰的表结构说明。如果看完这篇内容你也准备整一套类似的工作日志办公系统我最后提醒你一句先到业务部门蹲半天看看他们是怎么填今天的工作内容的再回来设计表单和流程。这一步比我讲的所有技术点都重要。

相关新闻

RAG进阶实战:从检索优化到Agentic架构的专栏设计

RAG进阶实战:从检索优化到Agentic架构的专栏设计

1. 为什么我要做这个RAG进阶专栏过去大半年,我几乎把市面上能跑通的RAG方案都折腾了一遍。从最朴素的“文档切块向量检索拼Prompt”三件套,到后来引入重排序、混合检索、知识图谱增强,再到把Agent和RAG揉在一起做多轮工具调用,踩过…

2026/10/5 8:47:19 阅读更多 →
基于Simulink的四自由度半车悬架模型建模与仿真全流程

基于Simulink的四自由度半车悬架模型建模与仿真全流程

做“二分之一车辆悬架半车模型研究”这个题目,听起来像教科书的课后作业,但真正想用Simulink把它跑出稳定、准确的仿真结果,比想象中要费功夫。半车模型不是把车从中间切成两半的直觉理解,而是把整车压缩到纵向竖直平面里的四自由…

2026/10/5 8:47:19 阅读更多 →
Hindsight一周涨星破万:多Agent协作与编排框架的技术拆解

Hindsight一周涨星破万:多Agent协作与编排框架的技术拆解

1. 一周涨星破万背后,Hindsight 到底踩中了什么先把时间拨回 2026 年 9 月 21 日到 9 月 28 日这一周。GitHub Trending 榜单上出现了一个让很多人措手不及的名字——Hindsight,单周新增 star 数 11,089,直接登顶。这个数字放在整个开源社区的…

2026/10/5 8:46:18 阅读更多 →

最新新闻

STM32H743从25MHz晶振到480MHz主频的完整时钟树配置指南

STM32H743从25MHz晶振到480MHz主频的完整时钟树配置指南

一块板子,外部只有一颗25MHz晶振,要求把STM32H743的主频稳定跑到480MHz。这个需求听起来很基础,但实际操作起来,很多人在CubeMX时钟树这一关就卡住了:要么是PLL参数不对,要么是生成代码后系统跑不到指定频率…

2026/10/5 10:52:44 阅读更多 →
Nmap核心功能与实战:从安装到扫描原理全解析

Nmap核心功能与实战:从安装到扫描原理全解析

搞网络安全和系统运维的朋友,几乎没有不知道Nmap的。它全称Network Mapper,是一款开源免费、功能极其强大的网络扫描与安全审计工具,在“网络扫描”这个场景里,它就是事实上的标准。不管是做资产盘点、端口探测、服务识别&#xf…

2026/10/5 10:52:44 阅读更多 →
FPGA HDMI设计必读:Video PHY Controller IP原理与调试指南

FPGA HDMI设计必读:Video PHY Controller IP原理与调试指南

做HDMI设计,特别是FPGA方案时,很多人会卡在一个地方:明明协议层、像素数据处理都写完了,结果上板之后,屏幕不是雪花就是黑屏。最后查来查去,问题多半出在物理层——也就是Video PHY这一块。这篇我就围绕Vid…

2026/10/5 10:52:44 阅读更多 →
极限计算核心逻辑:直接代入、重要极限与等价无穷小全解析

极限计算核心逻辑:直接代入、重要极限与等价无穷小全解析

“老师,这个极限到底能不能直接带?”我在带高数和考研数学这些年,几乎每周都会收到好几次这样的问题。很多人学到极限这一章,被“两个重要极限”“等价无穷小”“未定式”这几个词绕得晕头转向,做题全靠猜,…

2026/10/5 10:52:44 阅读更多 →
深度学习AMP训练必备:梯度缩放器GradScaler原理与实战排查

深度学习AMP训练必备:梯度缩放器GradScaler原理与实战排查

做深度学习训练的朋友,尤其是跑过大模型、大batch、还嫌显存不够用的人,应该都绕不过一个名词:自动混合精度(AMP)。我第一次接触AMP是在开源检测项目里,打开一行配置训练速度直接上了一个台阶,但…

2026/10/5 10:52:44 阅读更多 →
Vision Transformer图像去雾实战:Patch尺寸与Decoder设计关键

Vision Transformer图像去雾实战:Patch尺寸与Decoder设计关键

简介:本资源是一套基于Vision Transformer(ViT)的图像去雾算法完整实现方案,面向计算机视觉方向的研究生、算法工程师及深度学习实践者,聚焦于恶劣天气下图像质量退化问题的端到端建模与复现。压缩包共340个文件&#…

2026/10/5 10:51:44 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

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

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

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

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/4 20:14:29 阅读更多 →