尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

从JSP到SSM:会员管理系统的数据库设计与权限改造

从JSP到SSM:会员管理系统的数据库设计与权限改造 简介一份面向计算机相关专业毕业设计使用的JavaSSM会员管理系统论文文档以会员信息、积分、商品、订单等模块管理为场景展示从需求分析、UML建模到数据库与后端实现的全过程适合需要参考系统设计思路与论文写作框架的本科生。压缩包内共有1个docx文件整体大小约7.17MB文档结构包含中英文摘要、绪论、关键技术介绍、系统分析、系统设计、系统实现等章节便于直接阅读或按章节修改复用。已有53人学习下载可作为基于SSM框架的管理系统类毕业设计的选题参考和写作蓝本。结合提供的预览内容论文中详细介绍了MySQL数据库、JSP技术、Tomcat服务器及Eclipse开发环境在会员管理场景中的落地方式并针对代码可读性、扩展性和安全性做了说明能够帮助读者快速梳理同类系统的开发要点与论文行文结构。1. 从 JSP 到 SSM这套会员管理系统到底在解决什么问题很多计算机毕业设计拿到手的题目写着“JavaSSM”打开正文却是 JSP Servlet MySQL这套模板就是典型的例子。业务上它是一个带购物车和订单的会员管理系统管理员维护商品分类、商品信息、用户和订单用户注册登录后浏览商品、加入购物车、下单还能看积分和余额前台首页承担商品展示、新闻资讯和购物车入口。核心价值不是单个功能多复杂而是把“商品—购物车—订单—积分”这条业务闭环完整地走了一遍同时覆盖了可行性分析、UML 用例、E-R 建模、数据库设计、系统实现和测试等毕业设计必须的环节。适合两类人一类是拿这个题目做毕设、需要快速理解模块边界和表结构的初学者另一类是拿到手后想把它从 JSP 改造上 SSM 的开发者。2. 用例驱动拆解系统分析与权限边界2.1 管理员、用户、游客三条业务线原论文在第三章用 UML 用例图把系统分成三个视角管理员、用户和前台首页。管理员登录后进入后台拥有的功能是主页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理用户登录后看到主页、个人中心、我的收藏管理和订单管理未登录的游客在前台首页只能浏览商品信息、新闻资讯和购物车想要下单就必须登录。这个划分决定了项目的包结构后面做 SSM 改造时Controller 基本按照这三个视角拆成 AdminController、UserController 和前台 IndexController。可以按下表建立角色与功能的映射后面开发接口和配置权限拦截器时直接照抄角色功能域典型操作权限要求管理员用户管理查看、编辑、删除用户登录 admin管理员商品分类管理新增、修改、删除分类登录 admin管理员商品信息管理商品上下架、库存修改登录 admin管理员订单管理查看订单、发货、退款登录 admin用户我的收藏管理添加收藏、取消收藏登录用户订单管理查看已支付/已发货/已退款订单登录游客前台首页浏览商品、新闻、购物车无这套映射在 JSP 阶段是靠每个页面的 session 判断来实现的但因为 JSP 页面本身可以直接访问 session很多同学会把校验逻辑散落在每个页面里后期维护成本很高。常见做法是抽一个 Filter 统一拦截未登录请求改造 SSM 后则交给拦截器或 Spring Security 处理。2.2 登录流程与添加、删除流程的代码位置论文 3.5 节画了三张流程图操作流程、添加信息流程、删除信息流程。操作流程描述的是登录验证输入账号密码和登录类型系统去数据库比对成功后进入功能界面失败则提示信息错误。这段逻辑在 JSP 项目里通常写在一个 LoginServlet 里。以登录为例典型的 Servlet 处理链是这样protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username request.getParameter(username); String password request.getParameter(password); String role request.getParameter(role); // admin / user UserDao dao new UserDao(); User user dao.findByUsernameAndPassword(username, password, role); if (user ! null) { HttpSession session request.getSession(); session.setAttribute(loginUser, user); session.setAttribute(role, role); response.sendRedirect(role.equals(admin) ? admin/index.jsp : user/index.jsp); } else { request.setAttribute(error, 账号或密码错误); request.getRequestDispatcher(login.jsp).forward(request, response); } }这段代码对应流程图的“验证信息是否正确”分支。注意几个细节第一UserDao.findByUsernameAndPassword 里传入的 role 决定了查询哪个角色JSP 阶段常见做法是 user 表里加一个 role 字段来区分而不是分表第二登录成功后用 session 保存用户对象后续所有页面都能通过 session 判断登录态第三失败时用 forward 回到 login.jsp 并携带 error 参数刷新页面不会重复提交表单这一点比 sendRedirect 更适合做表单校验回显。添加信息和删除信息的流程相对简单添加时系统自动生成编号数据库自增 id写入前做合法性校验不合法就重新输入删除时先弹出确认确认后执行 DELETE 语句并更新数据库。这里的“编号自动生成”在 MySQL 里对应 AUTO_INCREMENT 字段不需要应用层干预。但如果项目要求订单号可读可追踪常见做法是改成“日期 自增序号”的字符串主键例如 20250612001这在后续对接物流单号时更有用。2.3 从用例图到路由映射把 UML 用例翻译成 URL 路由是做 SSM 改造时最直接的一步。论文没有给出具体 URL但按照这套系统的功能清单可以反向推导出路由映射表功能建议 URL对应 Controller管理员登录POST /admin/loginAdminLoginController商品分类新增POST /admin/category/addAdminCategoryController商品信息维护POST /admin/goods/saveAdminGoodsController订单发货POST /admin/order/shipAdminOrderController用户注册POST /user/registerUserController加入购物车POST /cart/addCartController提交订单POST /order/createOrderController查看收藏列表GET /user/favoritesUserFavoriteController这里要注意一个常见误用很多人会把所有请求都写到同一个 Servlet 里用 method 参数区分操作类型。JSP 阶段维护成本低可以接受一旦功能增多Servlet 会膨胀到上千行且每次新增功能都要改动同一个文件极易引入回归问题。SSM 接管后每个 Controller 按资源拆分再用 RequestMapping 收敛同一资源的操作扩展性会明显改善。3. 数据表字段级拆解与 SSM 建模修正3.1 三张核心表的字段拆解论文第四章给出了三张核心数据表shangpinfenlei商品分类、shangpinxinxi商品信息、yonghu用户。这三张表基本决定了系统的业务深度先看字段设计。表名字段类型说明shangpinfenleiidbigint主键自增shangpinfenleiaddtimetimestamp创建时间默认 CURRENT_TIMESTAMPshangpinfenleishangpinfenleivarchar(200)商品分类名称shangpinxinxiidbigint主键自增shangpinxinxishangpinbianhaovarchar(200)商品编号shangpinxinxishangpinmingchengvarchar(200)商品名称shangpinxinxishangpinfenleivarchar(200)商品分类冗余字符串shangpinxinxishuliangvarchar(200)数量/库存shangpinxinxipinpaivarchar(200)品牌shangpinxinxiguigevarchar(200)规格shangpinxinxixiangqingvarchar(200)详情shangpinxinxifengmianvarchar(200)封面图片路径shangpinxinxijifenfloat可获积分yonghuidbigint主键自增yonghuyonghuzhanghaovarchar(200)用户账号yonghuyonghuxingmingvarchar(200)用户姓名yonghumimavarchar(200)密码yonghuxingbievarchar(200)性别yonghulianxidianhuavarchar(200)联系电话yonghudianziyouxianglongtext电子邮箱yonghumoneyfloat余额yonghujifenfloat积分先看分类表id 加 shangpinfenlei 加 addtime这是 JSP 模板最常见的通用字段组合。商品信息表暴露了第一处需要修正的设计shangpinfenlei 字段直接把分类名称冗余在商品表里而不是用外键关联。数据量小的时候查询方便但一旦分类名称被修改商品表里所有冗余字符串都要同步更新否则会出现分类改名后商品仍然显示旧分类的问题。用户表的问题更明显mima 用 varchar(200) 存密码论文里没有提加密策略传统 JSP 毕业设计里明文存储的比例很高这个在改造时必须一并处理。3.2 建表 SQL 与字段参数说明如果要在本地复现这套数据库可以直接参考下面的建表语句。这里把论文里的字段结构转成可执行的 MySQL DDL并补上索引和外键建议CREATE TABLE shangpinfenlei ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, addtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, shangpinfenlei VARCHAR(200) NOT NULL COMMENT 商品分类名称 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品分类表; CREATE TABLE shangpinxinxi ( id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT 主键, addtime TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, shangpinbianhao VARCHAR(200) COMMENT 商品编号, shangpinmingcheng VARCHAR(200) NOT NULL COMMENT 商品名称, shangpinfenlei_id BIGINT COMMENT 商品分类ID外键, shuliang INT DEFAULT 0 COMMENT 库存数量, pinpai VARCHAR(200) COMMENT 品牌, guige VARCHAR(200) COMMENT 规格, xiangqing TEXT COMMENT 详情, fengmian VARCHAR(200) COMMENT 封面图路径, jifen FLOAT DEFAULT 0 COMMENT 可获积分, INDEX idx_category (shangpinfenlei_id), INDEX idx_bianhao (shangpinbianhao) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT商品信息表;参数说明shuliang 在原论文里是 varchar(200)这里改成 INT 是因为库存数量要参与加减运算varchar 存数字会在每次计算时做隐式类型转换数据量大以后性能问题会逐渐暴露。jifen 用 FLOAT 在小数场景够用但如果积分的业务规则是只增不减且不允许小数更推荐 DECIMAL(10,2) 甚至 INTFLOAT 在计费相关的场景下会有精度误差这是 MySQL 的经典问题之一。fengmian 字段只存图片路径不存图片本身符合 Web 应用的标准做法图片放服务器目录或 OSS数据库只保留相对路径。ENGINEInnoDB 是必须的MyISAM 不支持事务而订单和库存操作强依赖事务。字符集用 utf8mb4否则 emoji 和部分生僻字会写入报错。3.3 表名与字段命名规范的影响原论文的表名是拼音拼写shangpinfenlei、shangpinxinxi、yonghu在小项目里能用但放到 SSM 项目里会带来两个麻烦。第一MyBatis 的 mapper XML 里要写大量 resultMap 把拼音字段映射到实体类属性第二团队协作时阅读成本很高。常见做法是表名换成英文例如 product_category、product_info、member字段用下划线分隔再利用 MyBatis 的 mapUnderscoreToCamelCase 配置自动映射。一个值得注意的现象是论文英文摘要里直接保留了 mother and child e-commerce system 的残留说明这套模板的原型是母婴电商项目这在毕设题材中很常见。实际拆这套代码时不要被摘要干扰系统的真实业务就是会员制电商的商品和订单管理不是母婴垂直业务。按这个理解去设计接口和表结构方向就不会偏。简单算一下改造收益一条商品详情查询在 JSP 直连 JDBC 阶段要手写 ResultSet 封装改造后只需要在 Mapper XML 里写一条 select 并配置驼峰映射实体类字段直接对应数据库列代码量能砍掉一半以上。4. 关键模块实现登录鉴权、购物车与订单状态流转4.1 JSP 请求响应链路与分层边界这套系统的请求链路是典型的 JSP 模式浏览器发起请求到 Servlet或直接到 JSPServlet 调用 DAO 操作 MySQL结果通过 request 或 session 传回 JSP 渲染。问题在于 JSP 本身既能接收请求又能输出页面很多同学会把业务代码直接写进 JSP 的脚本片段中结果是页面里混着 SQL 语句、Java 逻辑和 HTML 标签后续改样式都可能碰到数据访问代码。合格的拆解方式是强制分层JSP 只做视图渲染Servlet 只做参数接收和转发DAO 只做 SQL 操作。比如商品列表页的逻辑可以拆成这样的代码// GoodsServlet.java protected void doGet(HttpServletRequest request, HttpServletResponse response) { String categoryId request.getParameter(categoryId); int page Integer.parseInt( request.getParameter(page) null ? 1 : request.getParameter(page)); int pageSize 12; GoodsDao dao new GoodsDao(); ListGoods goodsList dao.findByCategory(categoryId, page, pageSize); request.setAttribute(goodsList, goodsList); request.getRequestDispatcher(goods_list.jsp).forward(request, response); }逻辑说明doGet 只负责三件事——接收参数、调用 DAO、设置 request 属性并转发。categoryId 是商品分类的筛选条件page 是当前页码pageSize 是一页展示条数。findByCategory 方法内部拼条件 SQL有分类就加 WHERE 子句没有就查全部再用 LIMIT 做分页。参数说明request.getParameter 拿到的全是 String分页参数必须转 int 并做空值兜底否则翻页时 page 为空直接抛 NumberFormatException这是 JSP 阶段最容易踩的坑。4.2 登录鉴权的典型实现与三个缺陷登录模块在论文里是作为操作流程的核心出现的。常见的 JSP 实现是登录时把用户对象放进 session然后每个页面开头检查 session 是否为空。这样有个问题用户直接在浏览器地址栏输入 admin/index.jsp 就能绕过登录进入后台因为 JSP 文件本身不会做权限校验静态资源也没有拦截。给这类项目做改造时第一步永远是加一个统一鉴权 Filter。public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { HttpServletRequest request (HttpServletRequest) req; HttpSession session request.getSession(false); String uri request.getRequestURI(); if (uri.endsWith(login.jsp) || uri.endsWith(LoginServlet)) { chain.doFilter(req, resp); return; } if (session null || session.getAttribute(loginUser) null) { ((HttpServletResponse) resp).sendRedirect(login.jsp); return; } chain.doFilter(req, resp); }这段 Filter 的逻辑是登录页和登录接口放行其余请求一律检查 sessionsession 不存在或没有 loginUser 属性就重定向回登录页。参数说明request.getSession(false) 的 false 很关键它表示如果当前没有 session 就直接返回 null而不是新建一个——如果用 getSession(true)每个未登录请求都会创建一个无用 session造成内存浪费。uri.endsWith 是精确匹配完整项目里建议改成路径前缀匹配例如 /admin/ 开头的请求必须管理员角色这个在 SSM 里对应拦截器或 Spring Security 的配置。三个常见缺陷要单独说。第一是密码明文存储mima 字段直接存明文数据库一旦泄露所有账号裸奔改造后至少用 BCrypt 或 MD5 加盐第二是缺少会话固定攻击防护登录成功后没有重新生成会话 ID攻击者可以在登录前塞一个已知 session ID 给用户第三是登录接口没有防暴力破解正常项目需要加验证码或登录失败次数锁定论文里完全没有覆盖这些。提示改造登录模块时先用 Filter 把未登录访问漏掉的接口全部拦下来再做密码加密和会话修复顺序不要反过来。没有统一拦截之前改密码的意义不大。4.3 订单状态机的设计与状态迁移论文的订单模块把列表拆成了已支付订单、已发货订单、已退款订单三个视图这背后其实是一个状态机。完整的订单状态还应该包含待支付和已完成。用户提交订单后初始状态是待支付支付成功后变已支付管理员发货后变已发货用户确认收货后变已完成退款操作可以从已支付或已发货状态进入已退款。在数据库里这个状态机建议用一个 TINYINT 字段存储而不是直接存中文状态字符串。状态定义如下状态值含义可操作0待支付用户取消、支付1已支付管理员发货、用户申请退款2已发货用户确认收货、管理员强制退款3已完成无4已退款无对应的状态迁移 SQL 可以写成UPDATE orders SET status 2, ship_time NOW() WHERE order_id #{orderId} AND status 1;这条 UPDATE 的含义是“只有在当前状态为已支付1时才能发货改为 2”ship_time 记录发货时间。注意 WHERE 条件带上了 status 1这就是状态机的核心状态迁移必须基于当前状态做条件更新。如果不加这个条件两笔并发请求可能把同一个订单从待支付直接改到已完成破坏状态一致性。在 MySQL 里这是靠 UPDATE 的行锁天然保证的不需要额外加锁。已支付订单列表、已发货订单列表、已退款订单列表本质上是同一条查询语句换了 status 参数SELECT * FROM orders WHERE user_id ? AND status ?。SSM 改造后可以写成一个 Mapper 方法复用。4.4 购物车与下单的数据落库购物车在这个项目里有两种常见的实现方式。临时方案把购物车放 session用户未登录也能加购但换浏览器或清缓存就丢落库方案把购物车放数据库表能跨设备同步但需要额外的购物车表和登录绑定。论文前台首页有购物车入口但没有给出购物车表结构根据系统实现章节的描述可以判断它更接近 session 临时方案。能支撑答辩但作为改进点可以主动提出来。下单时的核心事务至少涉及三张表订单主表、订单明细表、商品表。创建订单时扣减库存、生成订单明细、计算总价这三步必须在同一个事务里完成。JSP 阶段的常见写法是直接在 DAO 里依次执行三条 SQL一旦中间报错就出现“库存扣了但订单没建成”的数据不一致。SSM 改造后用 Transactional 注解解决Transactional public Order createOrder(Long userId, ListCartItem items) { // 1. 计算总价 BigDecimal total calculateTotal(items); // 2. 插入订单主表status 0待支付 Order order new Order(); order.setUserId(userId); order.setStatus(0); order.setTotalPrice(total); orderMapper.insert(order); // 3. 插入订单明细 for (CartItem item : items) { OrderItem oi new OrderItem(item.getGoodsId(), item.getQuantity()); orderItemMapper.insert(oi); } // 4. 扣减库存 goodsMapper.decreaseStock(items); return order; }逻辑说明Transactional 让方法内的多次数据库操作共享一个事务任何一步抛异常都会整体回滚。insert(order) 执行后 order.getId() 会被 MyBatis 回填因为 insert 语句配置了 useGeneratedKeystrue数据库自增主键会写回实体。扣减库存的 decreaseStock 方法对应 UPDATE goods SET stock stock - #{num} WHERE id #{id} AND stock #{num}带库存条件是为了防止超卖。5. JSPServlet 平滑迁移到 SSM 的收敛清单5.1 三层结构映射与改造顺序把论文里的 JSP 项目改成 SSMSpring SpringMVC MyBatis不是一个重写工程而是一个逐层替换的收敛过程。对应关系很清晰原来的 JSP 页面交给 SpringMVC 的 Controller 控制渲染原来的 Servlet 中的业务逻辑下沉到 Service 层原来的 DAO 类全部替换为 MyBatis 的 Mapper 接口。改造顺序建议从数据层向控制层推进先建实体类和 Mapper再写 Service最后改 Controller。每一步都有上一个环节的支撑出错时能快速定位。核心对应关系用表来收敛原 JSP 项目位置改造后的 SSM 位置关键变化login.jsp / LoginServletLoginControllerController RequestMappingsession 判断登录态HandlerInterceptorpreHandle 统一鉴权UserDao 手工 JDBCUserMapper 接口MyBatis 自动参数绑定业务逻辑散落在 ServletUserService 实现类Service Transactionalweb.xml 配置 ServletSpringMVC 注解配置去掉大量 XML 配置手工创建数据库连接Druid 连接池连接复用、监控5.2 MyBatis 驼峰映射与 Mapper 示例原表字段是拼音下划线风格实体类属性是驼峰风格最常见的配置是在 application.yml 里打开 mapUnderscoreToCamelCasemybatis: configuration: map-underscore-to-camel-case: true开启后数据库字段 user_account 会映射到实体类属性 userAccount。对应的 Mapper 查询示例select idfindByAccount resultTypecom.example.entity.Member SELECT id, yonghuzhanghao, yonghuxingming, money, jifen FROM yonghu WHERE yonghuzhanghao #{account} /select参数说明#{account} 是预编译占位符MyBatis 会把它转成 PreparedStatement 的 ? 参数从源头避免 SQL 注入。resultType 配置成实体类后查询结果自动封装到 Member 对象。如果后续把表名和字段改成英文下划线风格这条 SQL 可以进一步简化为 SELECT * 加驼峰映射不需要写 resultMap代码量明显减少。5.3 迁移后必查的五个点迁移完成不代表能跑通业务用下面这份清单过一遍每一项都是 JSP 改 SSM 最容易踩的坑检查项检查方法预期结果中文乱码新增一条含中文的商品数据再查询出来存储和展示都正常登录拦截未登录直接访问 /admin/goods/list跳转登录页不抛 500事务回滚在 createOrder 里人为抛异常订单表和库存表都无变更分页参数访问第 2 页、第 -1 页、pageabc第 2 页正常非法参数兜底为第 1 页静态资源访问直接访问 /static/css/style.css返回 200 且内容正确第二项最容易被遗漏SpringMVC 的 DispatcherServlet 默认会拦截所有请求放行静态资源要在 spring-mvc.xml 里配置 mvc:resources mapping/static/** location/static//否则页面样式全丢。第四项的分页参数原 Servlet 用 Integer.parseInt 直接转遇到非数字直接异常SSM 里可以在 Controller 参数前加 RequestParam(defaultValue 1) int page由框架完成默认值处理。字符集这块顺带提一下MySQL 连接串里要显式声明 useUnicodetruecharacterEncodingutf8否则即使表、库都是 utf8mb4连接层仍然可能乱码。加上这两个参数能解决绝大多数“数据库中文变问号”的场景这也是 JavaWeb 项目里除了开发工具运行报乱码之外最常被搜索的乱码问题之一。本文还有配套的精品资源点击获取
返回列表