2.2 权限列表查询
说明: 如果需要查询父子结构的数据,则可以通过parent_id的方式查询子级信息.
/*查询一级权限列表信息*/
SELECT * FROM rights WHERE parent_id=0
/*查询二级权限列表信息*/
SELECT * FROM rights WHERE parent_id=1
/*查询三级权限列表信息*/
SELECT * FROM rights WHERE parent_id=2
1.4.2 登录步骤
- 再次校验用户的数据是否有效
- 发起Ajax请求实现用户登录请求. username/password post请求
- 在后端服务器 通过username/password 进行数据的查询.
结果 1.有数据 用户名密码正确. 2.无数据 用户名或密码错误 - 后端将数据处理完成之后,返回特定的数据. 告知前端 数据处理情况(回执!!!)
status=200 代表操作成功!!! status=201 表示业务操作失败 - 前端通过JS判断服务器的回执. 如果状态码等于200 提示用户登录成功, 否则告知用户用户名或密码错误.
- 一般为了校验用户是否登录,会返回一个特殊的密钥-TOKEN(密文),如果没有密钥则需要重新登录.
3.2 用户模块说明
3.2.1 需求说明
用户管理模块主要负责用户相关信息的维护,
1.展现用户列表
2.更新用户列表
3.修改用户的状态
4.删除用户
5.新增用户
1.5 商品分类新增
1.5.1 页面分析
业务说明:
1. 如果只写商品分类名称 则表示一级菜单
2. 如果父级分类为一级时, 则表示二级菜单
3. 如果父级分类为二级时, 则表示三级菜单
1. 项目概述
1.1 核心业务
- 用户登录操作
- 后台首页展现/展现左侧菜单列表
- 完成用户模块的CRUD
- 完成商品分类模块的CRUD
- 完成商品模块的CRUD
- 完成商品关联入库、关联删除
- 完成商品图片文件上传
- 实现图片的回显 nginx反向代理
- 完成项目服务器部署 准备3台tomcat服务器。实现负载均衡/搭建tomcat集群
- 实现项目Linux 真实环境部署.
阶段目标: 达到初-中级开发工程师的水平. 业务思维!!! 2-3遍
3.3 用户登录业务流程
- 用户输入用户名和密码 admin123/admin123456 点击登录按钮
- 通过vue中的 axios 发起post请求 /user/login,实现用户登录
- 在UserController中接收用户的请求和参数(json).
- 先将密码进行加密处理(SHA1,MD5,MD5HASH),根据参数查询数据库.
4.1 查询成功有数据 输入正确 有且只有一个数据
4.2 查询失败没有数据 输入有误. - 如果登录成功,则返回token的秘钥(安全性), 利用SysResult对象返回
3.4.2 MD5说明
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。
MD5特点:
1.只能由明文加密为密文,不可逆. 不可破解
2. 目前的破解只能破译其中的某些函数或者是反向查询.
3. md5升级 md5hash = 明文+盐 几乎不可破解
例子:
md5(123) = xxxxxxxx
md5(123 + lyj) = yyyyyyyyy
md5(123lyj+lyj) = zzzzzzzz
1.4.5 用户登录实现数据存储
说明: 当用户登录成功之后,将秘钥保存到Session中,后期需要校验是否有token,如果token有数据,则表示用户登录过,可以直接访问目标网址. 如果发现token数据没有值,说明用户没有登录.,则跳转到登录页面.
1.6.3 业务需求
说明: 用户在未经登录的条件下,可以直接访问其它页面,导致系统不安全.如果需要控制该漏洞,则需要在前端进行权限的校验.
校验的规则:
1. 如果用户访问没有token信息,则表示用户没有登录,则需要跳转到登录页面.
难点: 如何才能实现每一次的请求都要校验?
解决方案: 拦截器
用户状态修改(两个参数ID和stater)根据ID去修改状态updateById()方法
用户新增:
利用表单提交post请求 把前端传输过来的JS串形式封装到User对象中
1.密码加密 * 2.设定默认状态 * 3.设定默认时间
新增的用户信息的SQL语句写在Mapper.xml中,与UserMapper接口中的方法同名,进行绑定
<insert id="saveUser">
insert into user value (null,#{username},#{password},#{phone},#{email},#{status},#{created},#{updated})
</insert>
用户修改:
- 请求类型: PUT
- 请求参数: User对象
在UserServiceImpl中添加用户新增时间,把时间参数添加到User中
@Override
public void updateUser(User user) {
//设定当前时间
user.setUpdated(new Date());
userMapper.updateUser(user);
}
Updated这个字段user可以点是因为User继承了Basepojo,basepojo这个类中有updated这个属性
public class BasePojo implements Serializable{ //新增操作时 自动填充 @TableField(fill = FieldFill.INSERT) private Date created; //新增和修改操作时自动填充 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updated; }
在Usermapper中写以下
@Update("update user set phone=#{phone},email=#{email},updated=#{updated} where id=#{id}")
void updateUser(User user);
用户删除操作
- 请求类型: delete
请求参数ID,不能为nall
把ID当做参数传入后端方法中
4.6 MybatisPlus工作原理
4.6.1 MP核心
核心: 以对象的方式操作数据库
Mybatis操作的实质: Sql
调用步骤:
1. 用户执行userMapper.insert(user);
2. 根据继承的关系 BaseMapper.insert(user).
3. MP在内部生成Sql之后交给Mybatis调用最终实现数据操作.
4.6.2 MP动态生成Sql的基础
核心问题: MP是如何动态的生成Sql语句?
例子:
Sql1: insert into user(字段名…) value (属性的值…)
Sql2: insert into dept(字段名…) value (属性的值…)
变化的: 表名–字段名称—属性的值
4.6.3 MP动态Sql实现原理
1. 用户调用接口方法 userMapper.insert(User)方法
2. 根据UserMapper的接口找到父级接口BaseMapper<T>
3. 根据父级接口动态获取当前接口的泛型对象T
4. 根据泛型T 获取指定的注解@TableName("demo_user"),之后获取表名demo_user
5. 根据泛型对象T,获取其中的属性,之后再找到属性的注解@TableField("id"),之后再次获取注解的值, 即字段名称.
6. 根据字段名称,获取对应属性的值.
7. 根据Sql拼接 形成最终的可以执行的Sql.
8. MP将生成的Sql交给Mybatis执行入库操作.
Sql拼接:
insert into demo_user(id,name,age,sex) value( 100,“张三”,18,“男”)
条件构造器
/**
* 查询name="大乔",sex="女"的用户
* 方式2: 利用条件构造器,构建条件
* 说明:
* 1. eq =
* 2. gt >
* 3. lt >
* 4. ge >=
* 5. le <=
* 6. ne <>
*/
5.1 注解总结
- 全局异常处理机制
1.@RestControllerAdvice 标识全局异常处理的
2.@ExceptionHandler({RuntimeException.class}) 拦截指定的异常类型 - 事务控制注解
@Transactional 控制事务 更新操作 - MP映射注解
1.@TableName(“demo_user”) //对象与表名映射
2.@TableId(type = IdType.AUTO) //主键自增
3.@TableField(“age”) //实现属性与字段映射 - 测试类注解
@SpringBootTest 可以引入注入spring容器中的对象之后进行单元测试
1. 商品分类实现
- 请求类型: get
- 请求参数: level
在Service层构建方法利用条件构造器queryWrapper.eq("parent_id",0); selectList(queryWrapper);
去查询一级商品分类信息,第二次查询要把条件构造器里的数据清空查询二级数据 parent_id = 一级ID //遍历二级列表 查询三级数据,封装数据返回 oneItemCat.setChildren(twoList);
1.5 商品分类新增
1.5.1 页面分析
业务说明:
1. 如果只写商品分类名称 则表示一级菜单
2. 如果父级分类为一级时, 则表示二级菜单
3. 如果父级分类为二级时, 则表示三级菜单
1.5.2 业务接口说明
- 请求路径: /itemCat/saveItemCat
- 请求类型: post
- 请求参数: 表单数据
参数名称 | 参数说明 | 备注 |
---|---|---|
name | 商品分类名称 | 不能为null |
parentId | 用户父级ID | 不能为null |
level | 分类级别 | 1 2 3 商品分类级别 |
1.6 商品分类删除
1.6.1 业务说明
说明: 如果不是父级则直接删除. 如果是父级,应该先删除子级
1.6.3 业务接口文档
- 请求路径: /itemCat/deleteItemCat
- 请求类型: delete
- 业务描述: 当删除节点为父级时,应该删除自身和所有的子节点
- 请求参数:
参数名称 | 参数说明 | 备注 |
---|---|---|
id | 用户id号 | 不能为null |
level | 商品分类级别 一级,二级,三级 |
/** *
业务: 如果是父级 则应该删除子级和自己. *
思路: * 1. 判断是否为3级标签 直接删除 *
2. 判断是否为2级标签 先删除三级再删除二级 *
3. 判断是否为1级标签 先查询二级,再删除三级和二级再删除一级
* */
如果是3级商品直接获取itemCat的id 利用deleteById(id)删除
若果是二级的标签,利用二级的id等于三级的parent_id查出三级数据,然后删除三级数据,再删除二级数据
//删除1级商品分类信息 先删除3级.再删除2级. //1.首先获取商品分类2级信息 parent_id= 1级ID
利用循环二级的的ID=三级的parent_id,查询出三级的商品,放在条件构造器,然后itemCatMapper.delete(queryWrapper);//删除3级菜单
itemCatMapper.deleteById(twoItemCat.getId());//删除2级 itemCatMapper.deleteById(itemCat.getId()); //删除1级.
1.4.10 mybatis入门案例总结
Mysql入门实现步骤:
1.编辑mybatis-config.xml核心配置文件
1.1执行数据源配置
2.编辑POJO实体对象.要求与数据库表中的字段一一对应
3.编辑Mapper接口. 添加接口方法
4.编辑接口的实现类(配置文件方式) 要求namespace id resultType
5.mybatis加载指定的mapper映射文件
6.创建SqlSessionFactory工厂对象
7.获取SqlSession,开启数据库链接
8.获取接口对象(代理对象)
9.调用接口方法,获取返回值结果
10.关闭sqlSession链接.