行业资讯
📅 2026/7/15 23:39:29
SpringBoot + LayUI 实战:从零构建一个简易内容管理后台(附源码)
1. 为什么选择SpringBootLayUI搭建CMS后台最近在帮朋友改造一个内部使用的文章管理系统需求很明确要快速上线、维护简单、团队成员都能上手操作。在对比了多种技术方案后最终选择了SpringBootLayUI的组合。这个搭配可能不是最时髦的但绝对是中小型后台管理系统的最实用选择。先说SpringBoot它就像乐高积木的基础底板所有常用功能都给你预制好了。数据库连接一个starter搞定。接口开发注解配置简单到哭。我见过有新手用SpringBoot两天就搭出了可用的API服务这开发效率在传统SSM时代根本不敢想。而LayUI则是后台开发者的福音。作为典型的前端开箱即用框架它把表格、表单、弹窗这些后台高频组件都封装成了傻瓜式API。最让我心动的是它的文档示例——所有组件都有现成的代码片段直接复制粘贴就能跑起来。对于不擅长前端设计的后端开发者比如我来说简直是救命稻草。实测下来用这套技术栈开发一个基础CMS后台核心功能包括文章管理增删改查富文本编辑用户权限控制基于角色的菜单权限数据可视化简单的统计图表文件上传支持本地和云存储全部开发周期不超过3人/周。下面我就把实战中积累的经验和踩过的坑毫无保留地分享给大家。2. 项目初始化与基础配置2.1 创建SpringBoot项目推荐使用阿里云的start.aliyun.com来初始化项目比官方的start.spring.io访问更稳定。关键依赖选择WebSpring Web MVC核心Thymeleaf模板引擎版本选3.0.12以上MyBatis-Plus数据库操作比JPA更符合国人习惯Lombok简化实体类编写这是我的pom.xml核心配置dependencies !-- 基础依赖 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-thymeleaf/artifactId /dependency !-- 数据库相关 -- dependency groupIdcom.baomidou/groupId artifactIdmybatis-plus-boot-starter/artifactId version3.5.3.1/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency !-- 工具类 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies2.2 前端资源准备LayUI的引入有两种方式直接使用CDN适合快速原型开发下载本地资源推荐生产环境使用我选择下载2.8.0版本最后一个稳定版目录结构这样安排resources/ ├── static/ │ ├── layui/ # LayUI核心文件 │ ├── uploads/ # 上传文件目录 └── templates/ ├── admin/ # 后台页面 └── front/ # 前台页面可选在application.yml中配置关键参数spring: thymeleaf: prefix: classpath:/templates/ suffix: .html mode: HTML cache: false # 开发时关闭缓存 mvc: static-path-pattern: /static/** datasource: url: jdbc:mysql://localhost:3306/cms_db?useSSLfalse username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver server: port: 80803. 核心功能实现3.1 文章管理模块开发先建数据库表MySQL示例CREATE TABLE cms_article ( id bigint NOT NULL AUTO_INCREMENT, title varchar(100) NOT NULL COMMENT 标题, content longtext COMMENT 内容, cover_img varchar(255) DEFAULT NULL COMMENT 封面图, status tinyint DEFAULT 0 COMMENT 状态0-草稿 1-已发布, view_count int DEFAULT 0 COMMENT 浏览量, create_time datetime DEFAULT CURRENT_TIMESTAMP, update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;对应的实体类用Lombok简化Data TableName(cms_article) public class Article { TableId(type IdType.AUTO) private Long id; private String title; private String content; private String coverImg; private Integer status; private Integer viewCount; private LocalDateTime createTime; private LocalDateTime updateTime; }Controller层实现增删改查Controller RequestMapping(/admin/article) public class ArticleController { Autowired private ArticleService articleService; // 文章列表页 GetMapping(/list) public String listPage() { return admin/article_list; } // 获取文章列表数据供LayUI表格渲染 ResponseBody PostMapping(/list) public TableDataInfo list(Article article, Page page) { PageArticle result articleService.selectPage(page, article); return TableDataInfo.build(result); } // 新增/编辑页 GetMapping(/edit/{id}) public String editPage(PathVariable(required false) Long id, Model model) { if (id ! null) { model.addAttribute(article, articleService.getById(id)); } return admin/article_edit; } // 保存操作 ResponseBody PostMapping(/save) public Result save(Valid Article article) { return articleService.saveOrUpdate(article) ? Result.success() : Result.error(保存失败); } }3.2 LayUI表格与表单集成在article_list.html中实现数据表格table classlayui-table idarticleTable lay-filterarticleTable/table script layui.use([table, form], function(){ var table layui.table; // 初始化表格 table.render({ elem: #articleTable, url: /admin/article/list, page: true, cols: [[ {field: id, title: ID, width:80}, {field: title, title: 标题}, {field: viewCount, title: 浏览量, width:100}, {field: status, title: 状态, width:100, templet: #statusTpl}, {field: createTime, title: 创建时间, width:180}, {fixed: right, title: 操作, width:150, align:center, toolbar: #barTpl} ]] }); // 工具条事件 table.on(tool(articleTable), function(obj){ var data obj.data; if(obj.event edit){ layer.open({ type: 2, title: 编辑文章, content: /admin/article/edit/ data.id, area: [800px, 600px] }); } else if(obj.event del){ layer.confirm(确认删除, function(index){ $.post(/admin/article/delete, {id: data.id}, function(res){ if(res.code 0){ table.reload(articleTable); } layer.msg(res.msg); }); }); } }); }); /script !-- 状态模板 -- script typetext/html idstatusTpl {{# if(d.status 1){ }} span classlayui-badge layui-bg-green已发布/span {{# } else { }} span classlayui-badge草稿/span {{# } }} /script !-- 操作按钮模板 -- script typetext/html idbarTpl a classlayui-btn layui-btn-xs lay-eventedit编辑/a a classlayui-btn layui-btn-danger layui-btn-xs lay-eventdel删除/a /script编辑页集成富文本编辑器form classlayui-form input typehidden nameid th:value${article?.id} div classlayui-form-item label classlayui-form-label标题/label div classlayui-input-block input typetext nametitle lay-verifyrequired th:value${article?.title} classlayui-input /div /div div classlayui-form-item label classlayui-form-label封面图/label div classlayui-input-block div classlayui-upload button typebutton classlayui-btn iduploadBtn上传图片/button div classlayui-upload-list img classlayui-upload-img idpreviewImg th:src${article?.coverImg} ?: input typehidden namecoverImg th:value${article?.coverImg} /div /div /div /div div classlayui-form-item label classlayui-form-label内容/label div classlayui-input-block textarea idcontent namecontent styledisplay:none; th:text${article?.content}/textarea /div /div div classlayui-form-item div classlayui-input-block button classlayui-btn lay-submit lay-filterformSubmit保存/button /div /div /form script layui.use([form, layedit, upload], function(){ var form layui.form; var layedit layui.layedit; var upload layui.upload; // 初始化富文本编辑器 var editorIndex layedit.build(content, { height: 300, uploadImage: { url: /admin/upload/image // 图片上传接口 } }); // 图片上传 upload.render({ elem: #uploadBtn, url: /admin/upload/image, done: function(res){ if(res.code 0){ $(#previewImg).attr(src, res.data.src); $(input[namecoverImg]).val(res.data.src); } } }); // 表单提交 form.on(submit(formSubmit), function(data){ data.field.content layedit.getContent(editorIndex); $.post(/admin/article/save, data.field, function(res){ layer.msg(res.msg); if(res.code 0){ setTimeout(function(){ parent.layer.closeAll(); parent.layui.table.reload(articleTable); }, 1500); } }); return false; }); }); /script4. 权限控制与系统优化4.1 基于拦截器的权限控制在CMS后台中简单的权限控制可以通过拦截器实现public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String uri request.getRequestURI(); // 放行登录页和静态资源 if(uri.startsWith(/login) || uri.startsWith(/static)){ return true; } // 检查session HttpSession session request.getSession(); if(session.getAttribute(adminUser) null){ response.sendRedirect(/login); return false; } // 更精细的权限控制可以在这里实现 return true; } }注册拦截器Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/admin/**) .excludePathPatterns(/admin/login); } }4.2 性能优化技巧静态资源缓存生产环境开启Thymeleaf缓存spring: thymeleaf: cache: trueLayUI组件按需加载layui.config({ base: /static/layui/modules/ }).use([table, form, layedit], function(){ // 按需加载模块 });MyBatis-Plus性能优化Configuration public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); // 分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 性能分析插件开发环境使用 if(isDev){ interceptor.addInnerInterceptor(new PerformanceInnerInterceptor()); } return interceptor; } }5. 项目部署与源码分享5.1 打包与部署使用SpringBoot的Maven插件打包mvn clean package -DskipTests生成的jar包可以直接运行java -jar cms-backend.jar --spring.profiles.activeprod推荐的生产环境配置# application-prod.yml spring: datasource: url: jdbc:mysql://db-server:3306/cms_prod?useSSLtrue username: prod_user password: ${DB_PASSWORD} # 从环境变量读取 thymeleaf: cache: true server: compression: enabled: true mime-types: text/html,text/css,application/javascript5.2 完整源码获取我把这个CMS后台的完整代码放在了Gitee上包含前后端完整实现数据库SQL脚本部署文档常见问题解答获取方式访问 [Gitee仓库地址] 克隆或下载zip包。项目采用MIT协议你可以自由地用于学习和商业项目。在实际开发中我还扩展了以下功能源码中都已包含七牛云文件上传集成数据导出Excel功能登录验证码支持操作日志记录遇到任何问题都可以在仓库的Issues区提问我会定期查看并回复。也欢迎提交Pull Request一起完善这个项目。