一个简单的后台管理系统(1.0)
使用须知
该项目是由动吧项目更改而来,目的是为巩固自己的基础,提升手动能力。
文末提供了动吧项目源码、以及本作源码。(如有问题,请留言)
推荐idea插件:Easy Code、Free MyBatis plugin
一、数据库
数据库表设计不好,写后台代码会出现很多问题(我自己的表修改了n次)。
1.1关于数据库的设计(重点)
在设计数据库表的时候,要考虑的就是表的结构、字段以及表与表之间的关系。而且要符合数据库的三范式(表中字段必须最简、字段必须一一对应、表中字段不能与其他字段有所联系(递推关系))。
部门表、日志表就是比较简单的,因为这两张表不需要牵扯什么,而且设计起来相对简单。
单就表的设计而言权限表就比部门和日志上升了一点难度,以为权限表的设计中牵涉到了上级权限的问题。
上面三张表基本是一对一的关系,所以设计起来还是比较简单的。
在设计角色表的时候,需要注意复杂的多对多关系,此类关系直接建表会不符合三范式,需要拆表。
例如:角色表的设计,在设计角色表的时候,需要考虑角色与权限之间的关系。一个角色可能对应对各权限,如果直接写入会不符合第二范式,所以需要进行拆表,建立角色与权限表。
在用户表的设计的时候,也是一样的,用户与角色之间也需要进行拆分(此处如果不拆分,不符合第三范式)。但用户与部门之间就不需要进行拆分。
1.2具体表设计
此处只举例角色表和用户表,用来理解表设计(三范式)
1.2.1角色表
CREATE TABLE `y_roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`note` varchar(500) COLLATE utf8_bin DEFAULT NULL,
`createdTime` datetime DEFAULT NULL,
`modifiedTime` datetime DEFAULT NULL,
`createdUser` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`modifiedUser` varchar(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1.2.1.1角色与权限
此表不拆分,会不符合第二范式。因为一个角色可能拥有多种权限。
CREATE TABLE `y_role_menus` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`role_id` int(11) DEFAULT NULL,
`menu_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1.2.2用户表
CREATE TABLE `y_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`password` varchar(100) COLLATE utf8_bin DEFAULT NULL,
`salt` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`mobile` varchar(100) COLLATE utf8_bin DEFAULT NULL,
`createdTime` datetime DEFAULT NULL,
`modifiedTime` datetime DEFAULT NULL,
`modifiedUser` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`valid` tinyint(4) DEFAULT NULL,
`deptId` varchar(50) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=84 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
1.2.2.1用户与角色
此表不拆分,会不符合第三范式。因为角色与权限之间有着递推关系。
CREATE TABLE `y_user_roles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`role_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
二、前端
对于前端这一块基本没有什么好说的,因为主题框架都是采用的动吧项目的框架,只需要进行简单的修改即可。但是还是需要注意一些问题。
1.关于需要注意的地方
- Logout按钮,没有找到控制层的方法,所以自己写了一个
- 前端修改时一定要细心
- edit是编辑页面
- list是表头
- post提交(参数为键值对形式)
- form表单是post提交(post和get的区别)
- 如果感觉前端出现了错误,需要排除
- 使用console.log(),输出参数,查找错误
- debugger
2.新增注册页面
- 新增了注册页面,但该页面还存在一些BUG尚未解决
- 前端的一些校验(但是如果是在同一个班级只能,出现BUG的概率会很小)
三、后端
后端会进行重点说明。但是一些基础配置(pom、yml)不会进行说明。
后端的设计也很灵性,也是符合人的逻辑的,在进行后端操作的时候,也是一样由简入繁、由前端操作后端。
3.1后端总体概述
- 根据模块来看,后端分为两个大的模块:通用模块、业务实现模块
- 通用模块:切面、异常处理、分页以及配置
- 业务实现模块:控制层、业务层、实体类
- 下面的分析也会按照两个模块进行分析
3.2业务实现模块
在业务模块中还是一些常见的包:controller、dao、entity、service、vo,下面将以控制层为主,依次跳入每个包,进行具体分析说明。
在访问时主要的流程还是基础流程Controller->Service->ServiceImpl->Dao->XML
3.2.0杂谈(重点)
- 在后端编写代码的时候,需要打开前端一块编写,因为后端所需要写的Controller层的代码,前端都明确指出了
- 每个控制层的主要方法都是CRUD + list、edit的跳转,但在实现类中会有区别(需要考虑的点不同),每个实现类还需要考虑健壮性
- 在Controller层搭好CRUD的框架需要注意
- 返回值对象:String,JsonResult
- 注解:@ResponseBody、@RequestMapping
- 方法参数
- 在Service层实现Controller时需要注意
- 对前端产生了什么影响,对后端产生了什么影响
- 举例:doFindObjects方法,从后端查询所有数据返回前端。
- 前端:返回所有数据
- 后端:将数据封装成List<Map<String,Object>>返回给前端
- 举例:doSaveObject方法,保存从前端而来的数据
- 前端:将数据传输给后端,并且需要知道是否成功
- 后端,保存前端数据,并返回结果
- 举例:doFindObjects方法,从后端查询所有数据返回前端。
- 返回值类型
- 对前端产生了什么影响,对后端产生了什么影响
- 在ServiceImpl层实现Service接口
- 注入Dao层
- 需要考虑健壮性(数据是否合法)
- Dao层
- 根据Service层,调动数据库,实现具体的数据库操作
- VO
- 通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要。
3.2.1PageController
-
在PageController中主要控制的是大的页面的跳转(登录、注册、首页等)他所对应的前端页面有(login、register、stater、page)
-
在此处基本没有需要注意的点,此页面只负责实现大型页面的跳转。唯一需要注意的地方就是在logout的时候。
-
@RequestMapping("/") //没有logout public String Logout() { Subject subject = SecurityUtils.getSubject(); //交给shiro处理 subject.logout(); return "redirect:doLoginUI"; //重定向 }
-
3.2.2YDeptsController
- YDeptsController是第一个处理的,因为Dept表的结构也简单,不太有什么与之关联的表。
- 该层的具体业务实现,也与杂谈中的基本一样
3.2.3YMenusController
- Controller层需要搭建的框架,基本与杂谈中一样
- doFindZtreeMenuNodes方法,查询id,parentId,依照树形打开
- 在业务实现类中:
- 删除权限的时候需要注意判断是否为子权限,必须先删除子权限,然后在删除顶级权限
- 增加与修改的时候,需要特别注意健壮性:考虑对象是否为空、考虑是否写入数据库
3.2.4YRolesController
- Controller层需要搭建的框架,基本与杂谈中一样
- 在业务实现类重点需要注意
- 多表删除
- 因为角色表与权限表之间还有关联,删除角色的时候,需要注意一同删除权限
- 多表删除
3.2.5YUserController
- 除了和以上几层一样,需要搭建自身的CRUD框架外还需要
- 判断合法
- 修改密码
- 登陆(提交信息给shiro)
- 重复校验(本应该放置在前端)
- 注册
- 在业务实现层需要注意
- 健壮性
- 关联删除
- 用户表与角色,角色与权限
3.2.6总结
- 以上几个Controller主要业务基本都是增删改查,主要还是业务层的不同
- 在实现业务层的时候一定要注意
- 健壮性
- 与前端的联系
- 与数据库的联系
- 是否为多表删除
- 如果出现问题,先检查一边逻辑(controller—>xml),排除不了就打断点尝试
- 凡是带有带有页面的,都要进行页面的校验
3.3通用模块
通用模块实现的就比较多了,比如切面、异常、配置等。
这里需要注意几个必须的:JsonResult、PageObject、GlobalExceptionHandler
这里的讲解从后端业务模块中最常见的说起(分包讲)。
3.3.1VO包
- JsonResult对象
-
JR对象是controller层中最常见的,再返回的时候,不是返回String类型的页面,就是返回一个JR对象
-
JR对象主要作用还是与前端进行交互,方便在前端对数据进行统一处理
-
JR包含的主要内容:
-
属性 备注 success 返回是否成功, true or false message 提示的消息 data 返回的数据,这个数据可以是任意的数据对象 show 在前端是否默认显示消息,默认为true code 返回编码,默认为200 ,这个可以在返回前端时 前后端双方协定好做一些判断
-
-
主要方法:
- 构造函数,让其在返回前端的时候,返回我们想要返回的指定信息
-
- PageObject
- PageObject主要的作用就是控制页面(可能意思有些不太准确)
-
属性 备注 records 当前页要呈现的记录 rowCount 总记录数 pageCount 总页数 pageCurrent 当前页码 pageSize 页面大小(每页最多显示多少条记录)
-
- 在util包中的PageUtil类里面,有对页面进行封装的方法,方便后期页面进行校验
- PageObject主要的作用就是控制页面(可能意思有些不太准确)
- Node
- Node封装树节点信息
- CheckBox
- 封装了id、name
3.3.2Exception
- GlobalExceptionHandler
- 全局异常处理类(与前端进行交互)
- @ControllerAdvice:异常集中处理,更好的使业务逻辑与异常处理剥离开;其是对Controller层进行拦截
- @ExceptionHandler:统一处理某一类异常,从而能够减少代码重复率和复杂度
- 对ShiroException、ServiceException、RuntimeException进行了处理
- 全局异常处理类(与前端进行交互)
- ServiceException
- 自定义的一个ServiceException,返回异常信息
3.3.3annotation
- @interface声明是一个注解
- @Target注解,是专门用来限定某个自定义注解能够被应用在哪些Java元素上面的
- @Retention注解,翻译为持久力、保持力。即用来修饰自定义注解的生命力。
- 注解的生命周期有三个阶段:
- Java源文件阶段;
- 编译到class文件阶段;
- 运行期阶段
- 注解的生命周期有三个阶段:
3.3.4Aspect
- @Aspect 注解修饰的类通常认为一个切面对象类型
切面对象是对扩展业务的封装,它通常会在内部声明
如下几个部分.- 实现扩展业务的方法(一般会称为通知-advice)
- 切入扩展业务的点(一般会称为切入点-PointCut)
- @Around注解修饰方法为一个环绕通知,其目的是在目标业务方法执行之前和之后都可以进行扩展业务的处理
- bean() 为切入点表达式
- @Around(“bean(sysUserServiceImpl)”)
- @annotation()为细粒度的切入点表达式定义方式
- @annotation(com.cy.common.annotation.RequiredLog)
3.3.5config
- @annotation(com.cy.common.annotation.RequiredLog)
- bean() 为切入点表达式
- shiro框架
- ShiroUserRealm
- setCredentialsMatcher
- 设置凭证匹配器,告诉认证管理器使用什么加密算法对用户输入的密码进行加密操作
- AuthenticationInfo(认证)
- AuthorizationInfo(授权)
- setCredentialsMatcher
- SpringShiroConfig
- SecurityManager
- ShiroUserRealm userRealm(注入Realm)
- 设置Realm、Session、Remember、Cache
- ShiroFilterFactoryBean
- SecurityManager securityManager(注入SecurityManager )
- 设置securityManager、文件拦截
- DefaultAdvisorAutoProxyCreator
- @DependsOn控制加载顺序
- 相当于一个切面
- 需要配合AuthorizationAttributeSourceAdvisor一起使用,否则权限注解无效
- @RequiresPermissions(权限标识)
- AuthorizationAttributeSourceAdvisor
- 相当于切点
- LifecycleBeanPostProcessor
- 管理shiro生命周期
- SecurityManager
- FilterRegistrationBean
- 从ShiroFilterFactoryBean工厂中获取所有的shirofilter过滤器
- 抑制单类型的警告:
@SuppressWarnings(“unchecked”)
- ShiroUserRealm
总结
第一次写这种东西,还有很多不足,日后翻修项目如果还有所发现 ,将继续修改该文章。
如有不足与错误,希望大家可以指出
- 此版为第一版,还有一些问题未修复,些许功能还未实现,以后陆续增加
- 关于优化
- 使用MP
- 增加Redis
- 修改xml文件中多余的代码
- 本作源码:https://github.com/Fan1931/Management
- 动吧源码:https://github.com/Fan1931/DB