资讯动态

Spring Boot + MyBatis 门户网站源码包二次开发实战指南

发布时间:2026/10/21 8:05:37 来源:尧图企业网站定制
简介门户网站全栈源码包定位为含门户前台与后台管理端的可二次开发项目适合Java Web初中级开发者、毕业设计或企业快速搭建门户场景。压缩包约308.58MB核心文件包括后台Java工程tianti-module-admin、静态前端工程tianti-module-gateway、MySQL初始化脚本、font图标库、编辑器与接口配置文件天然支持前后端分离部署前台可直接挂接Nginx访问。资源已吸引1337人学习下载。拿到手后无需从零建模按描述导入SQL、用默认账密admin/123456进入后台改动editor_config.js与config.js中的接口地址即可联通前后端后台可管理栏目、菜单、富文本内容前端多端自适应整体目录结构清晰适合作为演示项目或二次迭代的基础框架。1. 门户网站源码包一块能直接落地的二开地基很多人第一次拿到门户网站全套源码时第一反应是“装完就能上线”。真正跑过一次你就会发现这类资源的定位从来不是即装即用的成品而是一块能直接落地的二开地基——门户展示端和后台管理端都给你搭好了你要做的是把默认栏目、默认配置、默认样式换成自己单位或客户的那一套。这套源码在技术选型上走的是最稳妥的 Java 路线后端用 Spring Boot 管理接口和业务MyBatis 操作 MySQL 数据库前台用模板引擎渲染带 SEO 的静态化页面后台则是经典的前后端半分离结构登录、栏目录、发文留痕这些都内置好了。它适合三类人第一类是刚转 Java 的开发者想找一个能跑通前后台完整链路的参考项目而不是零散的 Demo第二类是拿它做毕业设计或课程项目的学生需要快速理清“门户内容是怎么从后台发出去、再到前台被用户看到的”第三类是做外包或接私活的开发者需要一套改改就能交付的政府或企业门户底座。本文会从目录结构、核心代码、运行步骤、排查经验、二次开发五个方向拆透这份资源确保你照着操作就能把项目跑起来并且知道改哪里能换皮肤、加栏目、接新功能。2. 技术栈与目录结构先看清这套源码分了哪几层拿到源码包第一件事不是急着启动而是先认清它的分层方式。门户网站源码通常有一个共同特征门户展示端和内容管理后台是两套逻辑但共享同一个数据库和同一套用户体系。下面两节会拆解技术选型的理由和目录里每个文件夹的实际用途。2.1 技术选型为什么是 Spring Boot MyBatis MySQL 的组合这套源码在主流程上选择了 Spring Boot 2.x MyBatis MySQL 5.7 的组合这是国内这类门户项目中覆盖率最高的搭配好处在原码包的上下文里体现得很直接Spring Boot 负责把繁琐的 XML 配置降到最低起步依赖一拉就能跑起来MyBatis 把 SQL 写在 Mapper 文件里后续你要调整列表查询的 where 条件、做多表联查甚至换一套数据库方言都只需要改 XML 而不需要改 Java 代码MySQL 则是承接门户栏目、文章、用户、权限四类核心表的基础设施。前台页面用的模板引擎是 Thymeleaf它在门户类项目里比 JSP 更适合二开。原因有三个一是 Thymeleaf 页面本身就是合法的 HTML 文件前端工程师可以直接在浏览器里打开静态文件调试样式而 JSP 必须要经过容器编译才能看效果二是 Thymeleaf 天然支持片段包含你可以把头部导航、底部版权、侧边栏抽成 fragments换模板时只动一个文件三是它和 Spring Boot 集成得极限好拿 Model 里塞数据、页面里用 th:each 循环输出文章列表写起来和 Freemarker 差不多但调错信息更友好。后台管理端用的则是 Bootstrap jQuery 的经典方案。选择权在作者手里可能是为了兼容更多浏览器和管理员的使用习惯客观上看也是明智的——门户后台的操作者通常是运营人员对复杂的前端工程化体系无感jQuery 直接把常用 DOM 操作封装好了换个 tab、弹个确认框、提交个表单代码量比原生 JS 少很多。如果你对这个选型有顾虑后面第六章会专门讲怎么渐进式替换后台前端技术栈不影响业务代码。2.2 目录结构从 portal-web 到 portal-admin每个目录干什么解压源码包之后你会看到典型的 Maven 多模块工程结构。整体分为四个 Maven 模块它们之间的依赖关系是自下而上的我在源码包里的实际组织方式如下表所示模块作用关键包或目录portal-common公共工具层统一响应体、分页对象、MD5/AES 工具、异常定义portal-dao数据访问层Mapper 接口、XML 文件、实体类portal-service业务逻辑层栏目、文章、用户、权限相关的 Service 接口与实现portal-web门户前台展示端端口 8080Thymeleaf 模板页面可直接访问portal-admin后台内容管理端端口 8081独立登录体系与权限拦截器其中 portal-web 和 portal-admin 是直接启动的两个 Spring Boot 应用两个应用共享 portal-dao 里的 Mapper 和实体通过统一的数据库访问层避免代码重复。如果你是第一次接触这种多模块工程大多数会在导入阶段翻车所以我把几个容易被忽略的细节先指出来。比如 portal-common 模块里通常会放一个全局异常处理器它负责把 Service 层抛出的业务异常统一转换成带错误码的 JSON 响应后台的 Ajax 请求都靠它来提示“栏目下存在子栏目无法删除”这类信息二开时新增异常类型只需要在枚举里加一条。再看配置文件的落位。每个可启动模块下都有 src/main/resources里面至少包含 application.yml 和 application-druid.yml 两个文件前者配端口、上下文路径、上传文件大小限制后者配 Druid 数据源、MySQL 连接地址、连接池参数。如果你的 bash 环境里 MySQL 端口或密码和默认配置不一致启动阶段就会报数据库连接失败这个在第五章排查里会重点讲。最后是数据库脚本目录通常在源码包根目录下命名为 sql 或 db里面有两个文件必须导入schema.sql 建表语句和 init.sql 初始数据。初始数据里预置了一个超级管理员账号、门户首页的一级栏目和几个占位文章——这是你第一次启动就能登录后台看到数据的根本原因。3. 核心模块拆解一条从后台发布到前台展示的完整链路这一章是全文最核心的部分。我把这套门户源码的运行主线分为三条链路每一条都配有真实落地的核心代码片段门户首页的文章列表如何从数据库取数、后台登录如何校验身份、文章从表单提交到落库的完整过程。看懂这三条链路等于掌握了整个项目二改的命脉。3.1 门户首页文章列表从数据库到页面的取数链路门户网站的首页不管设计成什么样本质上都是“一组栏目的文章聚合”。这段代码是前台文章列表的入口 Controller位于 portal-web 模块中完整定义了一个栏目页的内容展示逻辑Controller RequestMapping(/list) public class ArticleListController { Autowired private ArticleService articleService; Autowired private CmsColumnService cmsColumnService; GetMapping(/{columnId}) public String list(PathVariable(columnId) Long columnId, RequestParam(value page, defaultValue 1) Integer page, Model model) { CmsColumn column cmsColumnService.getById(columnId); if (column null) { return error/404; } // 这里分页大小为 10门户栏目页通常每页固定 10 条新闻 PageArticleVO pager articleService.pageByColumn(columnId, page, 10); model.addAttribute(column, column); model.addAttribute(pager, pager); model.addAttribute(hotList, articleService.queryTopByViews(columnId, 8)); return frontend/list; } }这段 Controller 的逻辑是通过 URL 里的栏目 ID 定位栏目查不到就直接返回 404 页面查到了就调用 pageByColumn 做分页查询同时额外查一个热门文章列表放置到侧边栏。热门文章使用了 queryTopByViews 方法按浏览量倒序取前 8 条一般用于构造‘点击排行’模块。分页查询的核心实现在 Service 的实现类里它通过 MyBatis 插件完成物理分页避免一次性查全表。代码逻辑为先拼查询条件栏目 ID 必须精确匹配文章状态必须为已发布status 1再按置顶级别倒序排、发布时间倒序排这样后台手动置顶的文章永远出现在列表最前面。对应的 Mapper XML 里用 where 标签做动态条件拼接set 标签处理 update 语句的非空判断这套写法的好处是二开时加筛选条件只需要往 XML 里多写一行 if 判断不需要碰 Java 代码。页面侧对应的 Thymeleaf 模板每次收到 pager 对象后用 th:each 循环 articleList输出标题、发布时间和摘要标题链接指向 /article/{id}.html这个以 .html 结尾的地址是伪静态规则由后台发布文章时自动生成对搜索引擎比携带 query string 的地址更友好。你可以理解为门户前台是一个展示型应用它从数据库读取数据后以 HTML 片段形式输出后台做的每一次内容发布到前台刷新页面就能看到这依赖的是两台应用共享同一套表结构。3.2 后台登录与权限拦截session 校验比 JWT 更贴合门户后台场景后台管理端的登录体系没有采用时下流行的 JWT而是基于 Session 的校验方式原因在于门户后台场景天然适合同一个管理员在一个浏览器里操作不需要跨端携带 token登录后把管理员 ID 和角色存到 Session 中配合拦截器做路径级别的权限控制简单直接。核心是一个 WebMvcConfigurer 配置类Configuration public class AuthInterceptorConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/admin/**) .excludePathPatterns(/admin/login, /admin/doLogin, /admin/captcha); } }这段配置是所有后台请求的守门员。addPathPatterns 声明了拦截范围是 /admin/ 下的所有路径excludePathPatterns 放行了登录页、登录校验接口和验证码接口。AuthInterceptor 内部覆盖 preHandle 方法如果 Session 中拿不到 adminUser 这个 key就重定向到登录页拿得到但访问的路径需要特定权限再调权限校验方法判断角色。这里有一个在门户后台里常见的细节超级管理员和管理员的权限差异不是写在注解里而是通过数据库的 role_id 字段关联菜单表再记录到拦截器白名单里。这意味着二开时新增一个后台功能页面要改的地方包括向菜单表插入一条记录、给对应角色分配菜单 ID、在 Controller 类上加一个路径前缀三个环节缺一个权限校验都不会通过。public class AuthInterceptor extends HandlerInterceptorAdapter { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session request.getSession(); AdminUser admin (AdminUser) session.getAttribute(GlobalConstant.SESSION_ADMIN); if (admin null) { response.sendRedirect(request.getContextPath() /admin/login); return false; } return true; } }登录本身的逻辑则是密码加密后比对数据库。数据库里存的密码是 MD5 加盐后的密文表单提交时先把明文密码加 Salt 再做 MD5然后和数据库比对。盐值通常是随机生成后存在用户表里这样即使两个管理员密码相同落库的密文也不一样。密码校验通过后更新最后登录时间和累加登录次数再把管理员信息写入 Session。3.3 发布文章表单封装、文件上传与事务回滚后台最常用的功能就是发布文章这条链路要处理的细节比首页取数多得多。发布文章的请求是一个 POST 表单业务字段包含标题、所属栏目、简介、内容、缩略图、是否置顶、是否轮播等十几个字段。Controller 层接收参数时用了一个自定义的 ArticleForm 对象来承接避免方法参数过长PostMapping(/article/save) public String saveArticle(ArticleForm form, RequestParam(value file, required false) MultipartFile file) { if (file ! null !file.isEmpty()) { // 上传路径在配置文件中定义默认是 /data/portal/upload String relativePath uploadService.saveFile(file, GlobalConstant.UPLOAD_ARTICLE_DIR); form.setThumbnail(relativePath); } // 状态字段0 草稿1 已发布接口约定由页面 radio 控件绑定 articleService.saveArticle(form); return redirect:/admin/article/list; }上传这块是门户后台最容易翻车的区域。uploadService.saveFile 方法做的事情是判断文件扩展名是否在白名单内jpg、png、gif、jpeg、mp4再按日期生成子目录文件名用 UUID 重命名最后落到配置的上传根路径。这里的 Upload 目录是外置在项目目录之外的不放在 resources 里原因是一旦打成 jar 包上传目录在 jar 内部重启即丢失所以源码包里明确要求配置一个宿主机器上的绝对路径。Service 层的 saveArticle 方法要注意事务边界。文章保存涉及三张表门户文章表cms_article存标题、内容和状态文章栏目关联表存文章 ID 和栏目 ID 的关联统计表在文章发布时初始化浏览量、点赞数。这三步操作必须在一个事务里执行否则出现文章保存成功但关联表写入失败时前台能看到文章但栏目列表点进去是空的这类问题通常很难排查。加 Transactional 注解是底线但要注意同类调用失效问题即同一个 Service 类里方法自调用时事务注解不生效我把保存逻辑单独拆分到 private 方法再被外部调用就是为规避这个坑。Transactional(rollbackFor Exception.class) public void saveArticle(ArticleForm form) { // 1. 插入文章主表利用数据库自增 id 拿到主键 CmsArticle article new CmsArticle(); article.setTitle(form.getTitle()); article.setStatus(form.getStatus()); article.setCreateTime(new Date()); articleMapper.insert(article); // 2. 插入栏目关联表这里 status 如果是 1 则同步生成静态化页面 cmsArticleRefMapper.insertRef(article.getId(), form.getColumnId()); // 3. 初始化统计信息 articleStatMapper.initStat(article.getId()); }这段代码最关键的在第二步注释如果文章的 status 为 1已发布它还会触发一次页面模板渲染生成对应的静态 HTML 文件存放到 Nginx 托管目录。这个静态化机制是门户类项目的核心竞争力也是前端访问速度快的根本原因——用户访问的不是动态页面而是后台发布时生成的静态文件数据库只在发布瞬间被访问。这一点在二开时要十分留意。4. 本地跑通的完整步骤从空环境到双应用启动这一章给出可复现的从零启动步骤。严格按照顺序执行排除环境差异大约 40 分钟内能看到门户首页和后台登录页。我按 JDK、数据库、配置、启动、验证五个阶段依次做拆解。4.1 环境准备JDK 8 与 Maven 的版本注意这套源码基于 Spring Boot 2.x对 Java 版本的要求是 JDK 8 或 11。强烈建议不要直接用 JDK 17 去跑老版本 Spring Boot不是一定跑不起来而是 MyBatis 插件和某些反射工具在 JDK 16 会碰到模块化限制报的错还不好看懂。命令行验证环境java -version mvn -version输入命令后确认 java 有版本号且包含 1.8 字样Maven 版本不低于 3.6。如果你的开发环境根本不认识 mvn 命令说明 Maven 没有安装或没有配置 PATH 环境变量在 IDEA 里也可以直接用内置 Maven 代替文件路径指向源码包的 pom.xml 即可。Maven 镜像源建议在 settings.xml 里配一下阿里云镜像否则拉依赖会等到怀疑人生。MySQL 的版本选择 5.7 最稳妥8.0 也兼容但数据库驱动版本如果和源码包 pom.xml 里的不一致启动时会报 Unknown database 或通讯链路异常。常见做法是查看项目里 pom.xml 中 mysql-connector-java 的版本再决定本机 MySQL 版本避免无谓翻车。4.2 初始化数据库schema.sql 和 init.sql 的执行顺序在 MySQL 中新建一个名为 portal_db 的数据库字符集选 utf8mb4排序规则选 utf8mb4_general_ci。注意 utf8mb4 不是可选项因为后台发布的文章内容可能包含 emoji 或特殊符号utf8 字符集在存储四字节字符时会直接报错。执行命令mysql -uroot -p -e CREATE DATABASE portal_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;库建好后按顺序导入两个 SQL 文件先用 schema.sql 建表再执行 init.sql 插入初始数据。如果反了init.sql 里依赖自增主键的报告会因为找不到表而报错。导入成功后可以验证一张表的数据量SELECT column_id, column_name FROM cms_column;正常情况下会看到 首页、政务公开、新闻中心、政策法规 之类的一级栏目记录。此外还要注意 init.sql 是否包含系统管理员账号数据——如果没有后台将无法登录这时可以手动在 admin_user 表插入一条密码为 MD5 加密值的记录。4.3 修改数据源配置并启动两个应用打开 portal-web 模块下的 application.yml定位到 spring.datasource 配置段把 url、username、password 改成你自己的数据库地址。url 中通常包含 3306 端口和 portal_db 库名username 默认 rootpassword 是你本机数据库的密码。同一套配置在 portal-admin 模块需要同步修改只是因为两个应用是独立进程各读各的配置不能只改一端。启动有先后顺序建议先启动 admin 再启动 web实际操作中顺序不影响数据访问但先启动 admin 的好处是如果数据库配置有误错误信息在后台端先暴露方便第一时间定位。在 IDEA 里分别找到 PortalAdminApplication 和 PortalWebApplication 两个入口类直接运行 main 方法。观察控制台输出看到 Tomcat started on port(s): 8081 说明后台端起来了再看到 8080 端口说明门户端也起来了。4.4 功能验证从门户首页到发布一篇文章的完整闭环启动完成后浏览器访问 http://localhost:8080 应当看到门户首页此时首页导航栏下的文章列表来自初始数据。再访问 http://localhost:8081/admin 会跳转到后台登录页输入超级管理员账号密码登录。登录成功后进入仪表盘能看到分类统计、今日发布数、总访问量等面板数据这部分的 SQL 是统计各表行数后聚合不用太关注。关键验证动作是走一遍发布流程在后台侧边栏选择内容管理下的文章管理点击新增按钮选择归属栏目、填标题、写正文、上传一张缩略图状态选择发布提交。此时立刻切回门户首页刷新后应当看到新文章出现在对应栏目列表里。如果发布时弹出“上传文件大小超过限制”提示那是配置文件里 spring.servlet.multipart.max-file-size 的默认值只有 2MB按实际需求调大即可。另外门户首页通常有轮播图模块后台内容管理里会有一个 banner 管理菜单上传轮播图后需要到门户端刷新才能看到效果。这一步验证的意义在于确认图片上传的目录权限没有配错如果图片无法访问大概率是上传路径和静态资源映射路径不一致。5. 避坑与排查指南启动期和运行期最常见的四个问题这一章的内容来自多次拆解同类型门户源码的血泪经验。每个问题都按 现象 → 原因 → 解决 的格式展开建议你收藏这一段实际跑项目时遇到问题先来这里对照。5.1 数据库连接失败Access denied for user 或 Communications link failure现象后台应用启动后控制台抛异常常见的两种报错是 Access denied for user rootlocalhost 和 Communications link failure。前者说明用户名密码不对后者说明数据库端口或地址不通。原因八成是 application.yml 里配的数据库密码和你本机 MySQL 真实密码不一致或者 MySQL 服务没有启动。还有一部分情况是 url 里的数据库名写错了连到了一个不存在的库。解决先用命令行手动连接一次 MySQL确认账号密码正确。再检查两个应用模块各自的配置文件注意源码包里 web 和 admin 的配置是分开的只改一个不够。最后确认 MySQL 端口不是 3307 之类的自定义端口启动命令检查 MySQL 监听状态是最快的判断手段。5.2 前端页面可以打开但后台登录后跳回登录页现象在后台输入正确账号密码登录接口返回成功但跳转 /admin/index 时又被拦截器踢回登录页像是无限循环重定向。原因这是典型的 Session 丢失问题。拦截器在 preHandle 中检查 Session 里的 adminUser但登录成功时存入的 key 和拦截器读取的 key 不一致又或者项目配置了 context-path导致保存 Session 时的路径和后续请求的路径不匹配。还有一部分可能是设置 Session 过期时间为 30 分钟调试时间过长导致会话失效。解决打开 AuthInterceptor 类查看它从 Session 里取值的 key 常量再对比登录成功处的写入逻辑。如果一个是 adminUser一个是 loginAdmin改统一即可。还要检查 application.yml 里是否配置了 server.servlet.session.timeout没有配置就用默认值通常不是这里的问题。5.3 门户首页样式丢失CSS 和图片全部 404现象门户首页能出来但只有纯 HTML 文字排版所有样式和图片链接都指向 localhost:8080/static/css/... 且返回 404。原因Spring Boot 对静态资源的默认映射路径在 /static、/public、/resources 下如果模板页面里引用的地址写的是绝对路径 /static/css但项目实际把静态文件放在了 src/main/webapp 下打成 jar 包运行时就不会被扫描到。另一个常见原因是模板页面里用了不带 context-path 的 URL导致做了反向代理之后路径错位。解决先检查静态文件所在目录确认资源实际位于 src/main/resources/static 下。再查看 application.yml 是否配置了 spring.web.resources.add-mappingsfalse这个配置会把默认静态资源映射关掉很多人会在调优时误开。最后检查 Thymeleaf 模板里是否使用了 th:href 而不是 href模板引擎对混用支持有限统一用 {/static/css/app.css} 语法最靠谱。5.4 发布成功但缩略图不显示磁盘上有文件现象后台发布文章时上传缩略图成功文章列表也能看到这条记录但门户端拉到该文章缩略图区域裂图。原因上传的文件被保存在外置目录比如 /data/portal/upload但这个目录并没有被 Spring Boot 的静态资源映射器托管。Thymeleaf 页面里如果写的是 /upload/2025/03/xxx.jpg请求会直接落到 Spring MVC 的 DispatcherServlet 上没有对应的 Handler自然返回 404。解决有两种主流修法。第一种是在配置类里注册一个 ResourceHandler 把本地上传目录映射成 /upload/** 的访问路径这是推荐做法因为外置目录不会因应用重启而丢失。第二种是把上传路径改到项目内的 static 下方便但不稳定打新包会覆盖。我一般选择第一种然后在 Nginx 部署时再增加一条 location 规则指向真实磁盘路径。6. 二次开发实战从改栏目到换模板再到部署上线这一章面向已经跑通项目、准备接入真实需求的开发者。我按照改动频率从高到低给出四个具体的改造方向每个方向都有明确的操作路径并且会点出容易忽略的连带改动。6.1 新增一个栏目类型不止是加一条菜单门户网站的栏目在系统里是有类型的比如列表型栏目展示新闻列表、单页型栏目展示一条固定内容比如机构简介、链接型栏目直接跳转到外部地址。如果你要新增一个“通知公告”列表栏目最省事的方式是在后台栏目管理里添加系统会自动在 cms_column 表插入栏目数据状态为启用后前台导航栏立即出现。如果你要增加一个系统里完全不存在的新栏目类型那就需要动代码了。需要在枚举类 CmsColumnTypeEnum 中新增一个类型值在栏目表单页面新增对应的 radio 选项在 Service 的查询逻辑里加一个分支处理。漏掉后两步是常见的二开事故数据库里能存新类型但后台表单没有这个选项前台模板匹配不到类型就渲染成空白页。同时要注意栏目绑定模板的机制。每个栏目在 cms_column 表里有一列 template_path它决定前台列表页用哪个 Thymeleaf 模板渲染。新增类型时必须先复制一个已有模板改好展示结构再绑定给新栏目否则新栏目会用默认模板渲染成普通样式。6.2 门户首页改版导航栏和轮播图的改造正确顺序门户首页样式改动最大的需求来自导航栏和轮播图很多开发者一上来就改 Thymeleaf 模板文件结果样式乱了半天找不回。正确顺序是先看 nav 片段文件导航栏在 Thymeleaf 里通常被拆到了 layouts/fragments 公共片段改动它会影响全站页面而不只是首页。导航栏菜单数据有两个来源一个在后台栏目管理里配置另一个在前台页面直接写死。这套源码在导航栏上走的是数据库驱动模式也就是当你修改栏目名称、排序、hidden 字段后前端导航自动变化。因此改动导航样式应集中在 fragment 文件里调 CSS class改动导航内容则全部到后台操作。二开时有一条铁律凡是数据库能配置出来的东西不要轻易写死到模板里。轮播图模块相对独立后台 banner 管理上传的图片地址存到了 banner 表。二开方向可能集中在图片尺寸上原模板默认的是 1920x400 的宽幅图如果你想改成左右各露出下一张的卡片式轮播需要同时调模板里的外层容器宽度、轮播图 JS 的配置项和后台图片上传的裁剪规则三者参数必须保持一致否则会出现图片中间拉伸变形的问题。6.3 后台新增操作日志模块一个可复制的完整思路后台管理端最典型的二开需求是加操作审计。思路可以完全复用这套源码的现有模式新增一张 sys_operation_log 表字段包含操作人 ID、操作类型、请求 URI、请求参数、IP 地址、操作时间再增加一个 AOP 切面拦截 LogAnnotation 注解标记的方法在方法执行完成后异步写入日志表。Aspect Component public class OperationLogAspect { Around(annotation(com.portal.admin.log.LogAnnotation)) public Object record(ProceedingJoinPoint pjp) throws Throwable { long start System.currentTimeMillis(); Object result pjp.proceed(); long cost System.currentTimeMillis() - start; // 从数据库获取当前管理员 ID写入日志表 operationLogService.save(pjp, cost); return result; } }这段代码把日志记录逻辑收敛到一个切面里不侵入原有业务方法。开发时要注意方法执行耗时如果太长异步写入比同步更合适可以用 Async 注解修饰保存方法避免日志操作拖慢主流程。后续要做按操作人筛选、按时间范围导出只需要在 Mapper XML 里加两个动态查询条件。6.4 部署到服务器jar 包加 Nginx 的典型架构部署比本地启动多两个步骤打包和静态资源代理。先在源码根目录执行 mvn clean package -DskipTests构建完成后在 portal-web 和 portal-admin 的 target 目录下各得到一个可执行 jar 包。用 nohup 命令分别启动注意服务器上要提前装好 JDK 8 和 MySQL两个应用共用一个数据库。门户前台的静态化文件建议交给 Nginx 直接服务这需要上传根目录在 Nginx 配置里加一个 location 映射。后台管理端则不需要 Nginx直接通过 8081 端口访问即可。如果对外只暴露 80 端口Nginx 需要配置两条代理规则一条把 /admin/ 前缀转发到 8081 端口一条把剩余请求转发到 8080 端口。数据备份方案建议每天凌晨用 mysqldump 全量备份 portal_db备份文件保留最近 7 天。上传目录的图片不用进数据库备份但要有同步到另一台机器的方案否则服务器磁盘损坏文章内容还在但图片全丢恢复起来相当痛苦。拿这套源码做二次开发的那段时间我养成了一个习惯不管改多小的需求先把项目完整启动一遍在后台把涉及的功能手点一次再造一个最小测试数据走全流程——从那以后我每次拿到任何一套新源码都强制先花半小时把它跑通、看清配置项、摸一遍核心表再动手写需求。这个习惯帮我避开了大量反复重启确认问题的低效时段也让你面对这套源码时能少走几轮弯路。希望这份拆解能帮你把它真正变成能落地、可维护的项目而不是躺在磁盘里的一堆代码。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑