资讯详情

SSM框架实战:家乡宣传网站开发全流程从架构到部署

📅 2026/9/28 8:32:20 | 华诺云谱 👁 阅读
SSM框架实战:家乡宣传网站开发全流程从架构到部署
去年秋天我接了一个不算大的活儿给老家做一个宣传介绍网站。表面上这东西简单无非是家乡概况、景点、美食、民俗这几块内容可真正动起手来才发现越是看起来没难度的需求越考验开发者的取舍能力。我最终用SSM框架把这套系统从头到尾做了出来项目代号就叫 java_ssm40。SSM就是Spring、SpringMVC、MyBatis的组合在Java面试和学习路线里常被当作分水岭很多人觉得它已经被Spring Boot取代了但拿来做内容展示型网站它的分层逻辑反而比全家桶式的Boot更容易讲清楚。这篇博文就围绕这个项目把需求分析、数据库设计、三大框架整合、前后端渲染、部署上线的完整过程以及我踩过的那些坑原原本本写出来。如果你正在做Java课程设计、毕业设计或者自学完Java基础后想找一个能练手又能写进简历的项目这篇内容应该能给你省下不少折腾的时间。1. 为什么一个宣传网站要上SSM全家桶1.1 先把需求拆明白这个网站到底要管什么接这种宣传家乡的需求最容易犯的错误就是上来就写页面。你想想一个真实的家乡宣传站背后站着的是村镇干部或旅游部门的人他们不懂代码但他们的需求非常真实今天要换个宣传语明天要加两张新拍的照片后天可能要把某个已经停业的农家乐从景点列表里去掉。如果这些改动都靠改HTML文件上线第一天就是噩梦的开始。所以这个项目的第一步不是建工程而是把网站内容抽象成可被后台管理的数据。拆下来无非这几块大类的固定栏目首页、家乡概况、风景名胜、特色美食、民俗文化、新闻动态每条栏目下的具体内容文字介绍、图片、发布时间、置顶状态、浏览量首页需要特殊展示的内容轮播大图、热门推荐、最新动态后台管理需求管理员登录、内容新增、修改、删除、图片上传想清楚这一点技术选型的答案就自然而然地浮出来了。这个项目要有数据库存内容要有后台管理页面要有前端展示页面还要能让非技术人员方便地更新数据。SSM的核心价值恰好就在这儿Spring管对象SpringMVC管请求分发MyBatis管数据库操作三层各管一摊出了问题容易排查也方便后来的人接手。1.2 为什么不直接用Spring Boot给还在纠结选型的你一个参考我知道现在很多人看到SSM会直接说用Spring Boot不香吗。这里得说实话如果你是自己学习、没有历史包袱单独看开发效率Spring Boot确实省事。但如果你是在做课程设计、需要体现Java企业级开发的基本功或者学校/公司现有项目就是SSM架构那么SSM的价值就显现出来了。SSM最大的特点是把很多Spring Boot自动配置掉的东西重新摊开在你面前。比如你在SSM里要亲手写web.xml、要手动配置数据源、要自己决定Spring容器和SpringMVC容器如何协同。这些配置看起来繁琐但它能帮你把Spring IOC容器是什么MyBatis会话怎么管理DispatcherServlet怎么分发请求这些在面试里被反复问的技术点真正落地一遍。另外还有一个很现实的原因很多老系统、外包项目、课程设计参考源码都是SSM。你如果只会Spring Boot遇到这类存量代码会手足无措。学会SSM再去学Spring Boot最多两天就能切换过去反过来只懂Boot突然接手一个SSM项目那你连从哪里改配置都找不到。java_ssm40这个项目对我来说就是一次把理论彻底转化为实践的机会。1.3 环境和版本选定的那点事儿做SSM项目版本混乱是第一个拦路虎。我这边实际用的组合是JDK 1.8、Maven 3.6.3、Tomcat 8.5、MySQL 5.7框架版本分别是Spring 5.1.8、MyBatis 3.5.4、MyBatis-Spring 2.0.3。之所以强调这套组合是因为它们在我反复测试下兼容性最稳。如果用JDK 17去跑旧版框架很可能会碰到源发行版17需要目标发行版17之类的编译警告或者反射相关的兼容问题。不要在这种地方给自己挖坑老项目就用老一套版本组合先把功能跑通再考虑升级。项目结构上我建议拆成标准的Maven web工程而不是随便建一个动态Web项目。用Maven的好处是依赖可以声明在pom.xml里团队协作时每个人拉下来都能构建不至于出现在我机器上能跑这种尴尬。2. 把家乡拆成数据表内容建模与数据库设计2.1 内容分类设计栏目不是拍脑袋想出来的数据库表的设计直接决定了后台管理页面的形态。我第一次设计时把栏目做成了一张栏目表后来发现过度设计因为栏目就那几种写死反而更好维护。最终我采用的是固定栏目内容表的方案也就是在Article表里用一个category字段去区分文章属于哪个栏目不需要一张category表去维护动态分类。栏目我定了这几个对应地在代码里用常量去约束栏目编号栏目名称展示内容1家乡概况历史沿革、地理位置、基本情况一到两篇长文2风景名胜每个景点单独一篇带多图、简介、游玩建议3特色美食每种小吃/餐馆单独一篇重点突出图片和推荐理由4民俗文化节庆、传统手艺、非遗项目周期性更新5新闻动态乡镇新闻、活动通知按时间倒序展示首页的轮播图、热门景点、最新动态其实都不需要单独的表直接从内容表里按条件查询就行。轮播图可以取状态为已发布且推荐展示的文章热门景点取浏览量排名前N的景点文章最新动态取新闻栏目最新的几条。这样设计后台只有一个文章管理入口所有栏目共用一套增删改查逻辑前端展示时再按栏目去取管理成本最低。2.2 核心表结构落地文章表是核心中的核心我把主要字段列在这里方便你直接抄CREATE TABLE article ( id INT PRIMARY KEY AUTO_INCREMENT, category INT NOT NULL COMMENT 栏目编号1概况 2景点 3美食 4民俗 5新闻, title VARCHAR(150) NOT NULL COMMENT 标题, summary VARCHAR(500) DEFAULT NULL COMMENT 摘要用于列表页展示, content TEXT COMMENT 正文HTML格式, cover_image VARCHAR(255) DEFAULT NULL COMMENT 封面图URL, is_top TINYINT DEFAULT 0 COMMENT 是否置顶1置顶, status TINYINT DEFAULT 1 COMMENT 状态1发布 0下架, view_count INT DEFAULT 0 COMMENT 浏览量, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );除了文章表还需要两张最基本的管理相关表。一张是管理员表字段就id、username、password、nickname、create_time密码存储必须用MD5以上强度的Hash另一张是轮播配置表不过我这里没有单独建轮播表而是用文章表的is_top和category做联合筛选减少后台维护成本。有一个细节值得专门说正文content字段用的HTML格式。这在宣传站项目里是对的因为后台编辑人员大多不会用Markdown反而直接在富文本编辑器里传图片、加粗、改颜色最顺手。存HTML的代价是前端必须用不转义输出的方式渲染要特别注意XSS问题后台提交时最好过滤掉script标签。我的处理方式是写一个简单的HTML过滤器在保存时把危险的标签去掉再存入数据库。别偷懒这一步真不能少。2.3 图片上传与路径约定新手最容易翻车的地方图片怎么存决定了你部署之后会不会半夜被人叫起来修Bug。我见过很多人在数据库里存Base64或者把图片塞进数据库的BLOB字段小图能忍轮播大图直接让页面卡死。正确做法是图片上传到服务器磁盘目录数据库只存相对路径。我的约定是在项目webapp目录下建立upload目录里面按年月分子目录图片命名用时间戳加随机数上传后返回类似 /upload/20250216/1234567890.jpg 这样的路径。前端页面访问时直接拼上项目上下文路径就可以。这里有两个坑你必须提前知道。第一个坑是在开发环境用IDEA内置Tomcat时图片上传到target目录下的webapp重启后可能会被清理所以开发期最好把上传路径配成绝对路径比如 D:/upload/然后加一个虚拟路径映射。第二个坑是Linux服务器的磁盘路径和Windows不一样代码里不要硬编码路径要把上传根目录放到配置文件里部署时改配置文件而不是改代码。我在第6章会专门讲这个映射怎么做。3. SSM三大框架整合最值得记录的配置细节3.1 web.xml入口和乱码过滤器一个都不能少SSM请求处理的第一站是web.xml。我用的配置里主要有三件事配置SpringMVC的DispatcherServlet、配置Spring的ContextLoaderListener、配置字符编码过滤器。初学者最常犯的错是把DispatcherServlet的url-pattern配成 /导致前端控制器拦截了所有请求静态资源全部404。我的做法是让它拦截 / 这种形式同时配合SpringMVC配置里的静态资源放行机制这个下面会说。字符编码过滤器必须配置在DispatcherServlet之前。Spring自带的CharacterEncodingFilter设置forceEncoding为true强制请求和响应都使用UTF-8。如果不配这个你用POST提交中文数据时到后端十有八九是乱码。数据库连接串里也要显式写上characterEncodingutf8否则MySQL默认连接字符集很可能是latin1又是乱码重灾区。3.2 Spring和SpringMVC的容器关系这个坑不搞懂等于白学SSM整合里最容易把新手搞懵的是Spring的父容器和SpringMVC子容器。简单类比Spring容器是全局的大管家管理Service、Mapper这些业务层和持久层组件SpringMVC容器只管Controller层面的东西。两个容器各扫门前雪但SpringMVC容器能继承Spring容器的Bean。所以配置扫描的时候要分清楚。Spring的applicationContext.xml扫描ServiceImpl和Mapper接口不要扫描ControllerSpringMVC的spring-mvc.xml只扫描Controller。如果你把两边扫描范围写成一样会出现Service事务失效、Bean重复创建之类莫名其妙的问题。我在实施中就遇到过Service里的事务不生效检查半天发现是Controller被Spring容器也扫描了一遍导致代理没走对。事务配置我放在Spring容器里用DataSourceTransactionManager配合tx:annotation-driven来开启注解事务。这样Service方法上标Transactional就能自动管理事务比如后台新增文章时先插文章表再更新栏目统计任何一个失败都会回滚不会留下脏数据。3.3 MyBatis映射细节驼峰转换和动态SQLMyBatis的配置里我强烈建议把mapUnderscoreToCamelCase设为true。这样数据库字段view_count就能自动映射到实体属性viewCount不用每个字段都写resultMap省掉大量重复劳动。SQL层面这个项目用的是Mapper接口加XML文件的写法。文章查询涉及列表分页、按栏目筛选、按标题模糊搜、按发布状态筛选这些组合查询用动态SQL写起来非常清晰。select idlistArticles resultTypeArticle SELECT * FROM article where if testcategory ! null category #{category} /if if teststatus ! null AND status #{status} /if if testkeyword ! null and keyword ! AND title LIKE CONCAT(%, #{keyword}, %) /if /where ORDER BY is_top DESC, update_time DESC /select注意LIKE查询这里用了CONCAT函数拼接而不是直接在字符串里写%#{keyword}%。后者在MyBatis里会被当成参数占位符解析出语法错误这是新手非常容易踩的雷。3.4 整合期那些磨人的经典异常整合SSM的过程一定会遇到几个经典报错我把实际上线的排查结果整理成表格方便你对照定位异常现象根本原因解决办法提示找不到Mapper beanMapper接口没被扫描到在Spring配置里用MapperScannerConfigurer指定扫描包页面报404或405Controller没有被SpringMVC容器扫描检查spring-mvc.xml的component-scan路径SQL语句执行时报无效绑定resultType写错或实体类字段名不匹配打开驼峰映射核对数据库字段与实体属性事务不生效事务管理器没注入或扫描范围重叠检查DataSourceTransactionManager配置和扫描范围请求参数中文乱码编码过滤器未配置/连接串缺UTF-8配置CharacterEncodingFilter并在JDBC URL加characterEncodingutf8我印象最深的一次是部署到Linux服务器后数据库里的中文全部变成问号本机却一切正常。最后定位到MySQL的配置文件里默认字符集是latin1建表的时候没指定utf8mb4。这个问题在第6章的部署经验里还会提到属于典型的开发环境验证不充分教训。4. 核心功能实现的要点与实测4.1 首页数据聚合接口一次查出所有板块要的数据首页是整个网站的门面它要同时展示轮播图、热门景点、最新动态、家乡概况简介。如果每个板块都发一次请求前端体验会差很多。我的做法是在Controller里写一个聚合方法一次调用Service得到首页的全部数据组装成一个Map返回给页面。Service层逻辑不复杂轮播图取status1且is_top1的文章热门景点取category2按view_count倒序前4条最新动态取category5按create_time倒序前5条概况取category1的第一篇。组装数据时要注意返回给前端的字段不能直接扔实体类尤其是富文本content正文字段在列表场景不需要返回减少网络传输量也有利于前端渲染安全。所以聚合返回的每个文章对象只挑id、title、summary、coverImage、viewCount、createTime这几个字段。Controller返回时我统一走的是跳转页面携带模型数据的方式也就是返回ModelAndView或者Model由JSP页面渲染HTML。这也是SSM项目最常见的模式搜索引擎能拿到完整页面对家乡宣传网站的SEO有好处。4.2 浏览量如何自增一个简单的SQL细节景点详情页要展示浏览量很多人的第一反应是先查一次view_count再加上1后再update一次。这种写法在并发高的时候会丢失更新网站访问量虽然不大但养成坏习惯不好。我在详情页的Service里写了两条SQL第一条是select查询文章详情第二条是直接执行 UPDATE article SET view_count view_count 1 WHERE id ?。这样自增操作交给数据库完成天然地保证了原子性不需要加锁也不需要事务里做多余操作。注意顺序上要先查询后自增不然页面刚打开还没看到内容就把浏览量加了会影响统计的准确性。4.3 后台管理增删改查与图片上传的联动后台管理系统我用了一个单独的admin前缀路径管理员登录后能进入文章列表页。列表页支持按栏目筛选、按标题搜索、置顶和上下架操作。新增和编辑文章共用同一个表单页面Controller区分操作类型。图片上传的接口值得单独写一下。前端表单用multipart/form-data提交后端用CommonsMultipartResolver解析然后做以下几件事校验文件类型只允许jpg、png、gif防止上传木马文件、校验文件大小控制在2MB以内、生成唯一文件名、保存到配置的上传目录、返回可访问的URL路径给前端。这里有个提升使用体验的细节我在后台的富文本编辑器里也集成了图片上传接口编辑者写正文时可以随时插入本地图片。但正文里的图片路径和封面图不一样封面图是单独一个表单字段正文里的图片是base64由编辑器处理还是走文件接口取决于你用的富文本插件。我的建议是正文图片也走文件上传接口不要在数据库里存大段base64否则文章表很快会膨胀到几MB一条。4.4 搜索功能与LIKE查询的防坑搜索在宣传网站里容易被忽略但真到内容多了以后没有搜索就没法用。我的实现是标题LIKE模糊匹配加栏目筛选SQL用MyBatis的动态标签拼条件。有一个安全点必须强调LIKE查询这个keyword参数一定使用#{}占位符传值不要用${}拼接否则就是典型的SQL注入漏洞。用#{}时MyBatis会把参数当作预编译参数处理用户输入的%和_也不会被当成通配符去匹配所有行。分页我用的MyBatis原生分页RowBounds还是PageHelper这个项目里我用的是PageHelper理由很简单分页插件能自动帮你算total避免手写COUNT查询对内容列表这种需求足够用。PageHelper有版本适配问题PageHelper 5.x需要对应mybatis版本在有MyBatis-Spring的环境里不要忘记配置PageInterceptor。5. 前端页面渲染与展示细节5.1 页面模板选型JSP在SSM项目里依然是实用选项SSM项目的经典前端方案是JSP加JSTL我这次也是。很多人在这个环节犹豫要不要上Vue我的结论是对家乡宣传网站这种需要兼顾内容展示和搜索引擎收录的站服务端渲染是首选。JSP的好处是天然支持在页面里直接用EL表达式和JSTL标签遍历文章列表、判断栏目状态内容发出去就是完整HTML搜索引擎爬虫抓到的和用户看到的一样。如果你非要给局部加个异步效果比如首页轮播图我建议用纯JavaScript或者轻量级的jQuery插件实现在页面里引入即可不要为这点交互就引一个完整的前端工程。维护成本会瞬间翻倍而且发布流程也要改。5.2 首页、列表页和详情页各需要注意什么首页布局一般是顶部导航、首屏轮播、三个核心栏目区块、底部版权。轮播图数据从Controller传入我用JSTL的c:forEach遍历把每个文章的图片路径和链接地址渲染到轮播结构里。这里踩了一个小坑JSP中直接输出图片路径时如果路径是相对路径 /upload/xxx.jpg在Tomcat部署后需要拼上项目上下文路径。我在Controller里就已经把绝对路径拼好例如 /demo/upload/xxx.jpg避免在模板里到处写死。列表页主要是卡片式列表每个卡片显示封面图、标题、摘要、时间。图片加载要处理图片不存在的情况我给img标签设置了onerror回调图片加载失败时替换成一张默认图不然首页会出现很多裂图观感很差。详情页渲染富文本的时候要使用c:out value${article.content} escapeXmlfalse /这种方式避免HTML被打散显示。同时详情页要显示上一篇和下一篇我用的是根据id比较的简单查询比如找id大于当前文章的第一条作为下一篇id小于当前文章的最后一条作为上一篇。这个逻辑对大多数场景够用不需要做复杂的排序算法。5.3 公共部分复用导航栏和页脚别写十遍一个宣传站至少有首页、列表页、详情页、后台管理页这几套页面。如果你把导航栏在每个页面都复制一份改一个菜单链接就要全局搜索替换非常痛苦。JSP里天然支持include我把header.jsp和footer.jsp抽出来通过jsp:include pagecommon/header.jsp /引入。导航栏的高亮状态用当前请求的路径来判断传一个activeNav参数进去。后台管理页面我用了单独的布局左侧菜单右侧内容区用iframe嵌入子页面。这在SSM老项目里是常见做法虽然技术不新但胜在直观好维护。后台的路由统一走/admin前缀配合一个拦截器做登录校验未登录用户直接跳转到登录页。5.4 移动端适配这个环节不能省宣传网站的访问量来源半数以上是手机。我以前见过一些老项目完全没做移动端适配手机上打开字体巨大、图片溢出、点不到按钮体验几乎等于劝退。这个项目我没有引入复杂的前端UI框架而是用了一套简单的响应式方案栅格布局用百分比图片设置max-width:100%字号用rem或vw再加一个viewport meta声明。结果实测下来虽然比不上原生App那样精致但在普通手机上已经能正常阅读和浏览信息展示清楚这个程度对宣传站来说其实就够了。6. 打包、部署与线上维护中的真实教训6.1 Maven打包成war在Tomcat下的部署流程开发环境跑通只是第一步真正见真章的是部署到服务器。我项目的部署路径是先在IDEA里执行mvn clean package生成war包然后把war包丢到Tomcat的webapps目录下启动Tomcat自动解压。Tomcat安装目录下的conf/server.xml我不建议去改默认端口如果你机器上80端口没被占用直接在Tomcat的配置文件里把Connector端口改成80其余保持不变。这里有一个经常出问题的点本地开发用的数据库连接和线上不一样。我的解决方式是把数据库连接配置放到jdbc.properties文件里打包前用Maven的profile机制切换配置。也就是本地开发用本地配置线上打包用生产配置。如果你不想搞profile至少要在部署时手动确认jdbc.url里的host指向的是线上的MySQL而不是本地的localhost这个坑我见得太多了。6.2 图片404、中文乱码和路径问题线上实测记录我在部署完成自测时首页正常但轮播图全部显示不出来。检查浏览器Network面板发现图片请求返回404看路径是 /upload/xxx.jpg而项目部署后的上下文是 /demo。我意识到Controller里拼接路径时写的是绝对路径没有加上项目上下文。修改方案是使用request.getContextPath()动态获取上下文在Controller里拼接完整访问路径。中文字符乱码那次是这样的本地Windows下页面显示正常线上Linux下后台写入的中文全是问号。后来排查了两处一是MySQL数据库表和字段的字符集没指定成utf8mb4二是JDBC连接串里没加characterEncodingutf8。两个问题都修复后重新插入数据才正常。这个教训说明数据库建表时必须明确CHARSETutf8mb4不能依赖服务器默认配置。6.3 简单性能优化与备份策略宣传网站不会像电商系统那样承受高并发但也不代表不用管性能。我的优化集中在三层数据库层给article表的category、status、is_top这几个查询频繁的字段加上联合索引项目层在Service里对首页聚合数据做了5分钟本地缓存避免每次访问都执行五六条SQL前端层用Nginx做了静态资源缓存图片、JS、CSS这些文件直接在Nginx层返回304或者直接走缓存。备份是运营层面的头等大事。内容是客户一笔一笔录入的丢了就没法交代。我给服务器配置了每天凌晨的crontab任务用mysqldump把数据库导出到指定目录保留最近7天再同步到另一台机器或云存储。这个定时任务写起来很简单但能救命。6.4 上线之后的内容运营建议网站上线不是终点反而是一个新起点。我实际运营体会最深的是内容型网站最大的敌人是半年不更新。搜索引擎对长期不变化的站点会降低收录权重而且游客看到最新的新闻停留在几个月前信任感会大打折扣。我的建议是至少给自己留一个极简的发布流程管理后台里新增一篇文章只需要填标题、选栏目、传封面、写正文、点发布整个过程不超过两分钟。这就要求当初后台的交互设计足够顺手不要为了界面花哨牺牲操作效率。我在后台特意加了一键下架和批量置顶功能日常运营的人用起来很省事。做这套系统的过程让我对SSM的理解有了一个质的提升。以前学Spring、SpringMVC、MyBatis时每个框架单独看都觉得懂了可把它们拼在一起时那些配置文件之间如何协作、请求如何流转、事务边界在哪里才是真正考验人的地方。如果你也打算从零写一个SSM项目我建议别上来就照抄网上的完整代码先自己画出ER图再写配置文件再写SQL这个过程本身就是对Java后端知识体系的重新梳理。到后期维护这个家乡宣传站时我可以很清楚地告诉需求方哪里能改、哪里不能动、多久能上线这种掌控感是单纯看视频、背八股文换不来的。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑