拓冰建站拓冰建站
首页 / 资讯中心 / 正文

基于SSM框架的广告管理系统开发实践与详解

简介面向Java Web方向毕业设计、课程设计的学生这套基于SSM框架与Vue前端、MySQL数据库的广告管理系统实战项目能直接用于选题参考或二次开发。系统覆盖管理员、广告客户、广告商、广告制作商四类角色功能含广告需求管理、提案管理、设计图交付、设计预览、签署与结算等流程业务链路完整。资源共540个文件压缩包约83.42MB主要包含135个Java源码文件、50个Vue页面、23个XML配置、2个SQL数据库脚本及若干静态资源、构建脚本和演示视频目录结构清晰前后端代码与配置分离。目前已有150人学习下载。随包附带演示视频和安装运行脚本可帮助快速理解SSMVue整合方式梳理广告业务流转逻辑节省环境搭建与联调时间适合具备Java基础、需要完整毕业设计案例的本科及高职学生参考。1. 基于SSM框架的广告管理系统到底解决什么问题把「Java毕业设计-基于SSM框架的广告管理系统.rar」解压开里面大概率是一个标准Maven工程根包名类似com.xxx.advertisementController、Service、Mapper三层一目了然。SSM框架在Java毕业设计里出现频率极高和java面试题里常考的Spring IoC、AOP、MyBatis动态代理一一对应Spring管对象装配SpringMVC管请求分发MyBatis管SQL与Java对象的映射。广告管理系统恰好需要这套分层——广告位、投放计划、素材审核三类核心数据天然要处理多表关联、登录权限、文件上传和状态流转复杂度适中既能展示基本功又不至于在答辩时被深挖到回答不上来。本文按一套可复现的工程结构沿着SSM架构链路、建库建表、参数配置与联调排错一路讲下去适合正在准备毕设的学生也适合想快速搭一个轻量管理后台的初级工程师。2. SSM架构下广告管理系统的分层职责与登录链路这里先给一个结论不是所有毕设项目都适合SSM但广告管理系统偏偏合适。广告领域的实体有清晰的主次关系——用户管理员与广告主、投放计划、创意素材、广告位彼此之间是标准外键关联没有复杂领域模型也没有高频缓存需求把压力全部放在MySQL和MyBatis上就很清爽。Spring Boot固然配置更省但答辩时被问得最多的一句是“请求进来以后怎么分发的”用SSM可以把这条链路从头到尾讲完整。2.1 从java八股文反向看SSM三层为什么要这么切java八股文里最高频的三个框架题——控制反转、AOP动态代理、MyBatis代理机制恰好也是SSM工程的分层理由。Spring容器启动时扫描Service、Repository注解并完成bean装配SpringMVC通过DispatcherServlet拦截请求经HandlerMapping定位到Controller方法MyBatis则为Mapper接口生成动态代理对象调用接口方法时按“命名空间方法名”找到XML里的SQL。放到广告系统里这条链路就是用户提交登录表单请求打到DispatcherServlet再进LoginController的login方法方法里调用LoginServiceService注入LoginMapper接口动态代理把selectUserByLoginName转成一条预编译SQL从ad_user表查询回结果Controller拿到结果写入Session重定向到首页。每层各管一段事务边界落在ServiceController不碰SQL这让后期加广告主角色、加权限拦截时改动范围可控。2.2 用ER图的思路先定四张核心表毕设文档里ER图几乎是必画项广告管理系统的ER图一般围绕五张表ad_user、ad_plan、ad_creative、ad_position、ad_record。字段不用多主外键关系明确即可一张简表先列清楚表名业务含义关键外键典型状态字段ad_user管理员、广告主无statusad_plan一次投放计划user_idstatus、start_date、end_datead_creative广告创意素材plan_idstatus、audit_statusad_position广告位无status、price建表时ad_plan可以按下面这个最简结构起步后面再加索引和冗余字段CREATE TABLE ad_plan ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 计划ID, user_id BIGINT NOT NULL COMMENT 所属用户ID外键到ad_user, plan_name VARCHAR(64) NOT NULL COMMENT 计划名称, start_date DATE NOT NULL COMMENT 投放开始日期, end_date DATE NOT NULL COMMENT 投放结束日期, budget DECIMAL(12,2) DEFAULT 0 COMMENT 预算单位元, status TINYINT NOT NULL DEFAULT 0 COMMENT 0待审核 1上线 2下线, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES ad_user(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这段建表语句的关键在于status字段用TINYINT存编号而不用VARCHAR存中文描述Java侧用枚举或常量类解释避免中文值直接进SQL。时间字段用DATE而不是VARCHARbudget用DECIMAL(12,2)而不是DOUBLE答辩时被问到“预算为什么不用double”用二进制精度问题作答会比较加分。2.3 登录链路的最小代码三层各写一段Controller层只负责参数接收和视图跳转业务判断下沉到Service这是SSM工程最常见的分工。登录Controller大致长这样Controller RequestMapping(/login) public class LoginController { Autowired private LoginService loginService; PostMapping(/doLogin) public String doLogin(String loginName, String password, HttpServletRequest request, Model model) { AdUser user loginService.checkLogin(loginName, password); if (user null) { model.addAttribute(msg, 用户名或密码错误); return login; } request.getSession().setAttribute(loginUser, user); return redirect:/index; } }这段代码有三个看点loginService.checkLogin方法上挂了Transactional(readOnly true)登录查询不开启写事务密码哈希比对在Service内部完成不在Controller里拼明文条件返回字符串直接对应视图名redirect:/index避免表单重复提交。Mapper层对应一条带login_name和password条件的查询但要注意密码字段存的是密文SQL里比对密文即可明文校验规则不要出现在SQL注释中。3. 用Maven配置在本地跑通SSM广告系统的关键参数解压后的rar里如果自带pom.xml先检查依赖版本是否匹配JDK与Tomcat如果没有就自己补一个最小依赖集。SSM工程的本地跑通80%的时间花在配置对齐上真正写业务的代码反而好排错。3.1 pom.xml里的最小依赖集与版本匹配一个能启动的SSM广告系统依赖不需要多五个核心坐标足矣spring-webmvc、spring-jdbc、mybatis、mybatis-spring、mysql-connector-java再加jstl做视图层遍历。很多网上模板还会带druid连接池、fastjson、shiro这些能用但先别急着删确认一下是否被Spring配置文件引用着。dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.3.30/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.11/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.7/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency版本号不必追新上述组合在Tomcat 8和JDK 8下非常稳定。这里有个容易踩的兼容性坑spring-webmvc 5.3系列走的是javax.servlet坐标对应Tomcat 8/9一旦换到Tomcat 10Servlet API变成了jakarta前缀启动时会直接报NoClassDefFoundError。如果你本地装的是新版Tomcat要么降级Tomcat要么整套Spring升到6.x不要在5.x上硬改包名。3.2 spring-mybatis.xml里三个必调的参数Spring与MyBatis整合通常写在spring-mybatis.xml中最核心的就是数据源、SqlSessionFactoryBean、MapperScannerConfigurer三件套bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSource property namedriverClassName valuecom.mysql.cj.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/ad_system?useUnicodetrueamp;characterEncodingutf8/ property nameusername valueroot/ property namepassword value123456/ /bean bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property nametypeAliasesPackage valuecom.ad.entity/ /bean bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.ad.mapper/ /beanDriverManagerDataSource适合毕设演示生产环境换成Druid或HikariCP参数含义不变。url里的characterEncodingutf8对中文广告素材名入库非常关键不加这条MyBatis写入中文后查到的是问号。typeAliasesPackage把com.ad.entity包下所有POJO注册成短别名后面Mapper XML里写resultTypeAdUser即可不用写全限定类名。3.3 Tomcat启动后404与500的固定排查次序演示时最常见的故障是index.jsp能打开点登录按钮却404。按固定顺序查第一步看web.xml中DispatcherServlet的url-pattern是/还是*.do决定了Controller映射要怎么写第二步看spring-mvc.xml里有没有 mvc:annotation-driven/ 没有它ResponseBody和RequestParam注解全部不生效第三步确认Controller的包路径在component-scan扫描范围内。而500大多数指向数据库连接串没加useSSLfalse导致的SSL握手超时属于配置类问题把url补成jdbc:mysql://localhost:3306/ad_system?useUnicodetruecharacterEncodingutf8useSSLfalse就能解决。4. 广告位CRUD从Mapper接口到Controller参数绑定广告管理系统最核心的业务就是广告位与投放计划的增删改查。SSM里CRUD能不能写得优雅取决于Mapper接口和XML的配合以及Controller参数绑定的处理。4.1 Mapper接口与XML的对应规则Java基础里那道经典面试题——为什么Mapper接口不需要实现类答案是动态代理。MyBatis启动时扫描MapperScannerConfigurer配置的包路径为每个接口生成JDK动态代理调用时按接口全限定名找XML的namespace按方法名找SQL id。约束因此非常严格接口名、XML的namespace、方法id必须一字不差。广告位查询接口可以这样定义public interface AdPositionMapper { AdPosition selectById(Param(id) Long id); ListAdPosition selectList(Param(posName) String posName, Param(status) Integer status); int insert(AdPosition position); int updateById(AdPosition position); }对应的XML里selectList用动态SQL实现多条件组合查询select idselectList resultTypeAdPosition SELECT id, pos_name, pos_desc, width, height, status FROM ad_position where if testposName ! null and posName ! AND pos_name LIKE CONCAT(%, #{posName}, %) /if if teststatus ! null AND status #{status} /if /where ORDER BY id DESC /select这段有两个细节值得在答辩时主动讲出来 标签会自动去掉多余的AND避免了手写WHERE 11被老师挑毛病LIKE模糊查询用CONCAT拼接而不是直接写LIKE %${posName}%后者存在SQL注入风险前者走预编译占位符。4.2 Controller参数绑定的三种写法及注解含义广告位列表页通常带着查询条件广告位名称、状态、页码。Controller里接收参数有三种写法对应不同场景GetMapping(/position/list) public String list(RequestParam(defaultValue 1) Integer pageNow, String posName, PathVariable(required false) String source, HttpServletRequest request) { // 调用service层查列表把结果放进ModelAndView return position/list; }RequestParam(defaultValue 1)解决第一次进入页面时pageNow为null导致分页空指针的问题String posName不加注解时SpringMVC按参数名自动绑定前端传不传都行PathVariable配RequestMapping(/list/{source})用于REST风格的路径参数。这里有个容易翻车的规则没有defaultValue的RequestParam是必填参数前端少传一个直接400。所以除了id这种明确唯一的参数列表查询条件全部定义成可空或带默认值。4.3 分页选择与手写limit的参数设计广告计划列表超过几十条后必然要分页SSM项目里有两种主流方案。其一是PageHelper插件pom中引入pagehelper依赖MyBatis配置中加PageInterceptor查询前调用PageHelper.startPage(pageNow, pageSize)原理是通过拦截器在SQL外层包装count和limit。其二是手写limit适合先理解分页本质也方便答辩演示。手写分页时Service层需要额外计算offsetpublic ListAdPosition pagePositions(int pageNow, int pageSize) { int offset (pageNow - 1) * pageSize; // 注意offset不能为负数 return adPositionMapper.selectPage(offset, pageSize); }PageHelper虽省事但很多人把startPage和下一次查询写得不连续导致后续某条查询被意外分页。我的建议是毕设阶段优先手写offset分页因为LIMIT #{offset}, #{pageSize}的语义在答辩时一句话讲得清等表格量大了再决定要不要引入PageHelper减少一次无效的count查询反而更可控。5. 登录拦截器、广告图上传与状态机设计广告管理系统的毕设演示除了CRUD评委最关心三个点权限控制、文件上传、业务状态流转。把这三点做出彩整个项目的完成度会有明显提升。5.1 用HandlerInterceptor拦截广告后台页面广告位申请、素材编辑、投放计划修改都必须登录后操作最直接的办法是写一个LoginInterceptor在preHandle里校验Sessionpublic class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser request.getSession().getAttribute(loginUser); if (loginUser null) { response.sendRedirect(request.getContextPath() /login); return false; } return true; } }在spring-mvc.xml中注册拦截器时有个经典坑拦截路径写成/会把CSS、JS、图片全部拦住页面打开后样式全丢。正确做法是把静态资源目录通过mvc:resources mapping/static/ location/static//放行再把拦截器路径缩小为/position/**、/plan/**这类业务路径。5.2 广告图上传的目录、类型与大小参数广告素材管理涉及文件上传SSM通过CommonsMultipartResolver解析请求。配置上只需注意几个参数就能避开文件丢失和类型绕过问题参数推荐值作用maxUploadSize10MB单次上传总大小上限maxInMemorySize1MB超过后自动转临时文件类型白名单jpg/png/gif/webp按contentType校验存储目录部署目录外的绝对路径避免重启Tomcat丢文件访问映射/upload/** 映射到本地目录通过ResourceHandler暴露上传逻辑大体是校验扩展名、生成UUID新文件名、把MultipartFile写入目标目录、再往ad_creative表插一条记录。注意不要用原始文件名直接落盘中文名和重名问题会同时爆发。存储目录推荐放在Tomcat部署目录之外的绝对路径这样重启不丢、war包重发也不被覆盖。5.3 广告状态机用枚举而不是散落的if-else广告计划的生命周期远比普通增删改查有看头待审核、投放中、已下线、已过期。大量if-else判断status数值会让代码难以维护常见做法是定义枚举public enum PlanStatus { PENDING(0, 待审核), ONLINE(1, 投放中), OFFLINE(2, 已下线), EXPIRED(3, 已过期); private final int code; private final String desc; PlanStatus(int code, String desc) { this.code code; this.desc desc; } // getter省略 }状态迁移里最容易被忽略的是“已过期”这个状态。毕设项目不需要定时任务去批量刷新在查询SQL里用CASE WHEN判断end_date和CURRENT_DATE动态得出过期状态即可。这样避免了定时任务扫描全表的额外复杂度也让答辩演示时能当场展示时间边界逻辑。6. 用日志与接口联调把答辩风险降到最低6.1 三个让日志“可视化”的配置答辩演示时控制台能看到带参数的SQL比空荡荡的INFO日志可信得多。第一mybatis-config.xml里设置logImpl为STDOUT_LOGGING让每条SQL和参数占位直接打到控制台第二logback或log4j的root级别设为INFO过滤掉无意义的DEBUG刷屏第三把DispatcherServlet的日志级别单独调到DEBUG请求从DispatcherServlet到Controller的分发痕迹会非常清楚。排错时优先看SQL日志里的实际参数值#{}绑定乱序在日志里一眼可见。6.2 Postman用例清单参考联调阶段准备三组Postman用例覆盖CRUD主链路。第一组列表页查询GET请求带posName广告和status1断言HTTP 200且返回数据非空第二组新增广告位POST提交JSON格式的广告位信息断言返回新增记录的id第三组状态流转创建计划后调用审核接口把status从0改为1再查询确认状态已变更。要注意的是RequestBody接收JSON和表单提交对应MultipartFile的接收方式不同测试脚本要按接口约定分别准备Content-Type。6.3 一个高概率被问住的MyBatis点#{}与${}最后说一个答辩高概率问题MyBatis的#{}和${}有什么区别。核心只一句——#{}走预编译最终替换成?通过PreparedStatement的setObject赋值能防SQL注入${}是字符串直接拼接进SQL适合动态表名和排序字段。广告系统的分页和模糊查询全部用#{}排序字段如果要做成可选的用${}时也要用白名单限定。补一句底层机制把分讲满MyBatis解析SQL时遇到#{}用ParameterMapping建参数映射底层交给JDBC的PreparedStatement处理遇到${}则是在BoundSql阶段直接文本替换不存在预编译环节。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门