THIS IS B3c0me

记录生活中的点点滴滴

0%

Javeweb综合项目-商城后台管理系统

一、后台管理系统介绍

对卖淘乐购物平台的后台进行管理

二、软件系统的开发流程

软件开发的生命周期:一个软件系统从无到有的过程

软件开发生命周期

  • 问题定义:明确要开发一个什么样的软件系统完成后台管理系统
  • 可行性分析:从技术、经济、社会因素等多个方面综合考虑这个项目是否可做
  • 需求分析:从细节上探讨这个项目要完成的功能
  • 概要设计:系统技术、技术栈、数据库
  • 详细设计:针对一个具体功能实现的详细步骤
  • 编码:按照功能实现的详细步骤进行代码的编写
  • 测试:检测软件系统功能的实现及性能(黑盒测试,白盒测试)
  • 项目交付:将项目部署运行到甲方的生产环境

三、后台管理系统功能需求

二手手机回收的业务流程

后台管理系统功能清单

  • 管理员登录
  • 商品管理
  • 评估管理
    • 评估类目管理
    • 评估选项管理
  • 订单管理
    • 全部订单
    • 待处理订单
    • 已完成订单
    • 已取消订单
  • 评价管理
    • 全部评价
    • 待审核评价
  • 会员管理
    • 全部会员
    • 已锁定会员
    • 已注销会员
  • 系统管理
    • 系统设置
    • 系统日志
  • 权限管理
    • 管理员管理
    • 角色管理
    • 权限、菜单管理

四、后台管理系统业务流程设计

概要设计:

  • 系统的业务流程
  • 系统的数据库设计
  • 系统的UI设计

4.1 HIPO图

项目功能的层次结构图:列出系统的功能,并建立起功能之间的层级关系

4.2 功能流程分析

针对于HIPO图中的每个功能进行详细的业务流程分析

例如以管理员登录为例:

  • 流程图:

  • 功能说明

    功能名称 管理员登录
    功能说明 管理员通过登录页面输入登录信息之后,验证登录信息是否合法
    输入项 管理员登录账号,字符串类型,长度限制
    管理员登录密码,字符串类型,长度限制
    登录验证码
    处理 接收账号、密码、验证码,首先验证验证码是否正确;;如果验证码正确则继续校验账号和密码
    输出项 如果登录成功则进入到系统管理的首页;失败则重新进入登录页面并进行提示

五、后台管理系统数据库设计

5.1 数据库设计流程

  • 根据系统的功能需求分析涉及到的数据实体(系统中需要对哪些数据进行处理和存储)
  • 提取数据实体的数据项(数据的属性)
  • 根据数据库设计范式规范和约束实体的数据项是否合理
  • 数据库建模:整理项目中涉及的数据实体的关系
    • E-R图
    • PD
    • PDman
  • 建库建表:使用sql脚本、借助建模工具导出

5.2 mtl数据库分析

mtl后台管理系统和用户系统共用同一个数据库,因此需要对已经创建好的数据库、数据表进行分析

5.2.1 相关数据表的归类说明

  • 系统管理相关
    • 管理员
    • 菜单
    • 角色
    • 系统属性
  • 产品相关
  • 用户相关
    • 用户
    • 购物车
    • 订单

5.3 数据库创建

导入sql文件

六、后台管理系统的UI设计

在企业开发中,web前端的HTML模板通常是由UI团队设计并完成静态网页的创建

七、mtl后台管理系统技术选型与项目搭建

7.1技术选型

  • 前端静态网页:HTML/CSS/JS+JQuery
  • Servlet/JSP
  • JDBC:Druid+apache commons DBUtils

7.2创建Javaweb项目工程

mtlMgs

  • 视图层:JSP
  • 控制层:Servlet
  • 业务逻辑层:Service
  • 持久层:DAO

7.3 项目开发环境搭建

  • JDBC开发环境
    • 添加jar包:mysql驱动、druid.jar、apache commons DBUtils
    • 配置创建druid的配置文件并完成属性的配置
  • 在utils中创建Druid的工具类
  • JSTL导入

八、管理员登录功能的设计与实现

8.1管理员登录实现流程设计

1.用户进入系统时显示登录页面,管理员输入账号、密码点击登录进行提交

2.账号和密码提交到ManagerLoginServlet类,在ManagerLoginServlet中接受账号和密码,调用ManagerService验证账号和密码是否正确

3.ManagerService先调用ManagerDAO中的方法,根据管理员名称查询管理员信息,将查询结果返回给ManagerService

4.在ManagerService中:

  • 如果ManagerDAO返回的信息为空,则表示根据用户输入的管理员登录账号没有查询到管理员信息(账号不存在),就返回给ManagerLoginServlet一个NULL

  • 如果不为空,则说明账号存在

    • 如果密码不一致,则返回给managerservlet一个Null
    • 如果密码一致,则登录成功,返回一个管理员对象

8.2 管理员登录功能代码实现

8.2.1 数据库操作实现

根据管理员账号查询管理员信息

  1. 此功能涉及的数据表:tb_managers

2.创建实体类
3.创建DAO类完成操作

8.2.2 业务层实现

实现ManagerService类,在类中检查用户名和密码

8.2.3 视图层和控制层的实现

1.视图层
  • 将HTML模板整合到javaweb工程中
  • 将对应的HTML网页修改为jsp页面
    • Login.html–>login.jsp
    • index.html–>index.jsp
  • 修改java web工程的默认欢迎页面
    • 在web.xml中配置
2.控制层
  • 创建ManagerLoginServlet
  • 在Login.jsp点击登录之后将登录信息提交到servlet类

8.3 验证码功能-实现设计流程

8.4 验证码功能的代码实现

  1. 在登录页面对应的位置添加一个验证码图片的img标签,同时将图片的src设置为checkCodeServlet

  2. 创建checkCodeServlet

  3. 在登录页面实现验证码图片的刷新

  4. 校验验证码

    • CheckCodeServlet中生成验证码之后将正确的验证码存储到session中

    • ManagerLoginServlet中接收用户输入的验证码,和session中存储的正确的验证码进行对比

8.5 用户认证校验

对于系统中的受限资源必须在管理员登录之后才能访问(例如管理系统首页)8.5.1

8.5.1 用户认证校验-流程设计

8.5.2 用户认证校验-代码实现

  1. 用户登录成功,将管理员信息存放到session中

    ManagerLoginServlet
  2. 创建登录过滤器,拦截所有用户请求

  3. 在登录过滤器中实现拦截及校验规则代码见项目源文件

8.6 密码的加密加盐存储

为了保证用户信息的安全性

8.6.1 加密方式

属于密码学范畴,讲得比较浅,不做记录。

8.6.2 密码加密校验实现

  1. 定义MD5加密帮助类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class MD5Utils {

    public static String md5Encode(String pwd) {
    MessageDigest md5 = null;
    String str = null;
    try {
    md5 = MessageDigest.getInstance("MD5");

    md5.update(pwd.getBytes());
    byte[] digest = md5.digest(); //加密
    str = new BigInteger(1, digest).toString(16);//16进制

    } catch (NoSuchAlgorithmException e) {
    throw new RuntimeException(e);
    }
    return str;
    }
    }
  2. 在ManagerService中调用MD5帮助类对密码进行加密

    1
    2
    3
    4
    5
    6
    7
    8
    if(manager != null){
    //判断密码 如果用户输入的密码和数据库的密码相等则登录成功 不相等则密码错误
    //比较之前对登录页面输入的密码进行加密,使用加密后的密文和数据库中的密文进行对比
    String pwd = MD5Utils.md5Encode(loginPwd);//调用加密类对密码进行加密
    if(!pwd.equals(manager.getLoginPwd())){
    return null;
    }
    }

九、系统权限管理功能的设计与实现

9.1 权限管理介绍

9.1.1 权限管理概念

在一个系统中通常会存在不同身份的用户,不同身份的用户进入到系统之后能够完成的操作是不同的。

  • 教务管理:学生 教师
  • 企业OA系统:总监 主管 员工
  • mlt:超级管理员 普通管理员 业务员
    • 超级管理员:所有操作
    • 普通管理员:受限
    • 业务员:受限

9.1.2 权限管理的实现

  • 基于菜单的权限管理:不同身份的用户看到的菜单不同
  • 基于功能的权限管理:所有用户看到的菜单相同,但是操作权限不同

image-20231208094233050

9.2 RBAC权限管理实现流程

9.2.1 RBAC概念

Role Based Access Control 基于角色的访问控制

模型中的三个主体:用户 角色 权限

每个角色可以有多个权限,每个权限可以分配给多个角色

每个用户可以有多个角色,每个角色可以分配给多个用户

——>两个多对多

  • 权限访问控制,需要做的事是:
    • 身份校验:判断是否为合法用户
    • 权限校验:用户要做某件事或使用某些资源,必须拥有某角色,或必须用有某权限
  • 访问控制管理的过程:
    • 记录用户信息
    • 制定角色
    • 对资源制定权限
    • 将权限分配给不同的角色
    • 将角色分配给具体的用户

9.2.2 RBAC数据库设计

9.2.3 RBAC实现流程

基于菜单实现

1.在创建系统用户时,为用户绑定对应的角色(角色对应着一组权限)

2.当用户登录成功进入到主页面时,根据用户查询角色,再根据角色关联查询当前用户的权限列表(菜单列表),并传递显示到主页。

基于功能实现

1.在创建系统用户时,为用户绑定对应的角色

2.当用户登录成功进入到主页面时,显示所有的菜单,当用户点击菜单进行操作时,在操作之前先根据当前用户名查询此用户是否拥有此功能的操作权限,如果有则允许操作,如果用户没有该权限则拒绝用户使用此功能。

9.3 系统主页菜单的加载和显示

根据不同的管理员身份加载并显示当前管理员可以进行操作的菜单

9.3.1 实现流程设计

9.3.2 数据库操作代码实现

操作:根据管理员ID查询当前管理员的菜单

1.涉及的数据表
  • 管理员信息表:tb_managers
  • 管理员角色关联表:tb_mgr_role
  • 角色表:tb_roles
  • 菜单表:tb_menus
  • 角色菜单管理表:tb_role_menu

2.查询sql
  • 使用子查询:

    1
    2
    3
    4
    5
    SELECT * FROM tb_menus WHERE menu_id IN(
    SELECT menu_id FROM tb_role_menu WHERE role_id IN(
    SELECT role_id FROM tb_mgr_role WHERE mgr_id = "10000001"
    )
    );
  • 使用连接查询

    1
    2
    3
    4
    5
    SELECT c.* FROM tb_mgr_role a
    INNER JOIN tb_role_menu b
    INNER JOIN tb_menus c
    ON a.role_id = b.role_id AND b.menu_id = c.menu_id
    WHERE a.mgr_id = "10000001";
3.创建实体类

创建实体类封装查询的菜单信息

  • 二级菜单实体类Menu2
  • 一级菜单实体类Menu1
    • 除了自己的属性外,还用一个List存放了Menu2对象
4.JDBC实现

如何将对应的二级菜单封装到对应的一级菜单下:

  • 方式一:使用上述的SQL一次性查询出当前管理员所有的菜单,在JDBC结果集处理时将查询出的数据进行处理

    ​ 优点:只需查询一次数据库

    ​ 缺点:封装数据的业务比较复杂

  • 方式二:先查询出当前管理员的一级菜单,然后根据一级菜单的ID查询当前管理员拥有的二级菜单

    ​ 优点:业务简单

    ​ 缺点:需要多次查询数据库

查询SQL改造

  • 根据管理员ID查询当前管理员的一级菜单

    1
    2
    3
    4
    5
    6
    SELECT c.menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,menu_icon menuIcon FROM tb_mgr_role a
    INNER JOIN tb_role_menu b
    INNER JOIN tb_menus c
    ON a.role_id = b.role_id
    AND b.menu_id = c.menu_id
    WHERE a.mgr_id = "10000001" and menu_level = 1 ORDER BY menu_order;
  • 根据管理员ID和一级菜单编号查询当前一级菜单下的二级菜单

    1
    2
    3
    4
    5
    6
    SELECT c.menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,parent_menu_code parentMenuCode,menu_url menuUrl FROM tb_mgr_role a
    INNER JOIN tb_role_menu b
    INNER JOIN tb_menus c
    ON a.role_id = b.role_id
    AND b.menu_id = c.menu_id
    WHERE a.mgr_id = "10000001" and menu_level = 2 and c.parent_menu_code = '01' ORDER BY menu_order;

创建DAO类实现数据库操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class MenuDAO {

/**
*description 通过管理员ID查询其所拥有的的一级菜单列表
*@params mgrId:管理员的ID
*@return 返回一级菜单列表
*/
public List<Menu1> selectFirstLevelMemusByMgrId(String mgrId){

List<Menu1> menu1List = new ArrayList<>();
try {
String sql = "SELECT c.menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,menu_icon menuIcon " +
"FROM tb_mgr_role a " +
"INNER JOIN tb_role_menu b " +
"INNER JOIN tb_menus c " +
"ON a.role_id = b.role_id " +
"AND b.menu_id = c.menu_id " +
"WHERE a.mgr_id = ? and menu_level = 1 ORDER BY menu_order;";
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
menu1List = queryRunner.query(sql,new BeanListHandler<Menu1>(Menu1.class),mgrId);
} catch(SQLException e){
e.printStackTrace();
}
return menu1List;
}

/**
*description 根据管理员ID和父菜单的code查询二级菜单
*@params 管理员ID 父菜单ID
*@return 二级菜单列表
*/
public List<Menu2> selectMenu2ByMgrIdAndParentCode(String mgrId,String parentCode){
List<Menu2> menu2List = new ArrayList<>();
String[] params= {mgrId,parentCode};
try{
String sql = "SELECT c.menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,parent_menu_code parentMenuCode,menu_url menuUrl " +
"FROM tb_mgr_role a " +
"INNER JOIN tb_role_menu b " +
"INNER JOIN tb_menus c " +
"ON a.role_id = b.role_id " +
"AND b.menu_id = c.menu_id " +
"WHERE a.mgr_id = ? and menu_level = 2 and c.parent_menu_code = ? ORDER BY menu_order;";
QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
menu2List = queryRunner.query(sql,new BeanListHandler<Menu2>(Menu2.class),params);
} catch (SQLException e){
e.printStackTrace();
}

return menu2List;
}
}

9.3.3 业务逻辑层代码实现

创建MenuService类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MenuService {

private MenuDAO menuDAO = new MenuDAO();
/**
*description 根据管理员ID查询当前管理员的权限列表 (一级菜单中需要包含相应的二级菜单)
*@params
*@return
*/
public List<Menu1> listMenusByMgrId(String mgrId){
//1.根据管理员ID查询管理员所有的一级菜单
List<Menu1> menu1List = menuDAO.selectFirstLevelMemusByMgrId(mgrId);
//2.查询每个一级菜单中的二级菜单
for(Menu1 menu1 : menu1List){
String parentCode = menu1.getMenuCode();
List<Menu2> menu2List = menuDAO.selectMenu2ByMgrIdAndParentCode(mgrId, parentCode);
//将二级菜单的集合设置给一级菜单的对象
menu1.setChildMenus(menu2List);
}
return menu1List;
}
}

9.3.4 功能流程代码实现

  • 在Servlets包中创建IndexServlet

  • 在ManagerLoginServlet中登录成功重定向到IndexServlet

  • 在IndexServlet中根据管理员id查询菜单列表,并转发到Index.jsp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //1.根据当前登录的管理员ID查询对应的菜单列表
    //a.从session中获取当前管理员的id
    HttpSession session = request.getSession();
    Manager mgr = (Manager) session.getAttribute("mgr");
    String mgrId = mgr.getMgrId();
    //b.调用MenuService查询当前管理员的菜单
    List<Menu1> menu1List = menuService.listMenusByMgrId(mgrId);
    //2.将菜单的集合传递到index.jsp
    request.setAttribute("menu1List",menu1List);
    request.getRequestDispatcher("index.jsp").forward(request,response);
    }

9.4 权限信息管理

9.5 角色信息管理

9.6 管理员信息管理

欢迎关注我的其它发布渠道