目录
1. 用户业务实现
1.1 用户修改数据回显
1.1.1 业务需求分析
当用户点击修改按钮时应该出现弹出框.其中展现用户的数据信息.
展现方式:
1. 获取用户ID,动态查询后台数据库信息,之后实现数据回显. 最新数据!!!
2. 可以利用作用域插槽,获取当前行的对象,之后实现数据回显. 页面数据!!!
1.1.2 页面JS分析
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="small" @click="updateUserBtn(scope.row)"></el-button>
<el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
</template>
</el-table-column>
//JS方法
async updateUserBtn(user){
this.updateDialogVisible = true
const {data: result} = await this.$http.get("/user/"+user.id)
if(result.status !== 200) return this.$message.error("用户查询失败")
this.updateUserModel = result.data
},
1.1.3 业务接口文档
- 请求路径: /user/{id}
- 请求类型: GET
- 返回值: SysResult对象
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 返回user对象 |
- JSON格式如下:
{
"status":200,
"msg":"服务器调用成功!",
"data":{
"created":"2021-02-18T11:17:23.000+00:00",
"updated":"2021-05-17T11:33:46.000+00:00",
"id":1,
"username":"admin",
"password":"a66abb5684c45962d887564f08346e8d",
"phone":"13111112222",
"email":"1235678@qq.com",
"status":true,
"role":null
}
}
1.1.4 编辑UserController
/**
* 业务: 根据id查询数据库
* URL: /user/{id}
* 参数: 主键id
* 返回值: SysResult(User对象)
*/
@GetMapping("/{id}")
public SysResult getUserById(@PathVariable Integer id){
User user = userService.getUserById(id);
return SysResult.success(user);
}
1.1.5 编辑UserService
@Override
public User getUserById(Integer id) {
return userMapper.selectById(id);
}
1.1.6 页面效果展现
1.2 用户修改实现
1.2.1 页面JS分析
说明: 当用户点击确定按钮时,会触发点击事件
<span slot="footer" class="dialog-footer">
<el-button @click="updateDialogVisible = false" >取 消</el-button>
<el-button type="primary" @click="updateUser">确 定</el-button>
</span>
点击确定之后,页面JS 发送情况.
1.2.2 业务接口文档
- 请求路径: /user/updateUser
- 请求类型: PUT
- 请求参数: User对象结构
参数名称 | 参数说明 | 备注 |
---|---|---|
ID | 用户ID号 | 不能为null |
phone | 手机信息 | 不能为null |
邮箱地址 | 不能为null |
- 返回值: SysResult对象
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | null |
- JSON格式如下:
{
"status":200,
"msg":"服务器调用成功!",
"data":{}
}
1.2.3 编辑UserController
/**
* 业务需求: 实现用户更新操作
* URl: /user/updateUser
* 参数: 对象提交 JSON串 注解接收
* 返回值: SysResult
*/
@PutMapping("/updateUser")
public SysResult updateUser(@RequestBody User user){
userService.updateUser(user);
return SysResult.success();
}
1.2.4 编辑UserService
//不为null的元素当作set条件,Id当作唯一where条件
@Override
public void updateUser(User user) {
userMapper.updateById(user);
}
1.3 用户删除业务实现
1.3.1 页面JS分析
<el-table-column label="操作">
<template slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="small" @click="updateUserBtn(scope.row)"></el-button>
<el-button type="danger" icon="el-icon-delete" size="small" @click="deleteUser(scope.row)"></el-button>
</template>
</el-table-column>
async deleteUser(user){
//1.消息确认框
const result = await this.$confirm('此操作将永久删除 '+user.username+', 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(error => error)
//如果确认 confirm 如果取消 cancel
if(result !== 'confirm'){
return this.$message.info("删除取消")
}
const {data: result2} = await this.$http.delete(`/user/${user.id}`)
if(result2.status !== 200) return this.$message.error("删除失败")
this.$message.success("删除成功")
//重新加载 数据
this.getUserList()
}
}
1.3.2 业务接口文档
- 请求路径: /user/{id}
- 请求类型: delete
- 请求参数:
参数名称 | 参数说明 | 备注 |
---|---|---|
ID | 用户ID号 | 不能为null |
- 返回值: SysResult对象
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | null |
1.3.3 编辑UserController
/**
* 业务: 根据ID删除用户数据
* URL: /user/{id}
* 参数: id
* 返回值: SysResult对象
*/
@DeleteMapping("/{id}")
public SysResult deleteUserById(@PathVariable Integer id){
userService.deleteUserById(id);
return SysResult.success();
}
1.3.4 编辑UserService
@Override
public void deleteUserById(Integer id) {
userMapper.deleteById(id);
}
2. 全局异常处理机制
2.1 业务需求说明
说明: 如果后台服务器发生运行时异常,应该第一时间通知用户.否则用户没有任何提示.影响用户体验.
分析:
1.页面没有提示的原因是服务器没有返回201的报错数据.
2.后端服务器报错之后,没有异常处理机制
总结:
异常的处理是项目中经常用到的机制,但是如果将大量的异常处理代码写在方法中,则影响程序的结构.导致代码混乱.
2.2 全局异常处理用法
2.2.1 实现原理 AOP
AOP说明:
名称: “面向切面编程”
作用: 在不影响源码的条件下,对方法进行扩展,降低了业务的耦合性.
通知:
1.前置通知: before
2.后置通知: afterReturning
3.异常通知: afterThrowing
4.最终通知: after
上述的四大通知,不能改变程序的运行的状态.
5.环绕通知: around
环绕通知是功能最为强大的通知方法,可以控制程序的流转过程.
2.2.2 全局异常处理实现
/**
* 注解的作用:
* 1.该注解只拦截Controller层抛出的异常信息!
* controller ---Service-----Mapper 异常向上抛出.
* 2.需要配合指定异常的类型.
*/
@RestControllerAdvice
public class SystemAOP {
//当前Controller层,只拦截运行时异常.
//@ExceptionHandler({RuntimeException.class, SQLException.class})
@ExceptionHandler({RuntimeException.class})
public SysResult exception(Exception e){
//控制台打印异常.
e.printStackTrace();
return SysResult.fail();
}
}
3. Spring中的事务机制
3.1 事务
如果后台服务器发生问题,则数据信息应该回滚,而不是提交操作.
事务(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
事务作用: 可以保证数据的 /持久性(永久性)/一致性/隔离性/原子性
3.2 控制事务
说明: 在业务层 执行数据库更新操作时,添加注解,控制数据库事务.
4. 实现数据自动填充功能
4.1 业务说明
在完成数据库入库操作时,其中创建时间和修改时间 都是用户必须添加的参数.但是该参数完全由用户填写,显得不智能. 公共的内容应该由框架完成.
4.2 自动填充实现
4.2.1 编辑POJO属性
说明: 在入库操作时,自动填充 created/updated时间.
在修改操作时,自动填充 updated时间.
4.2.2 配置自动填充功能
@Component //将该对象交给Spring容器管理
public class MyMetaObjectHandler implements MetaObjectHandler {
//完成新增入库操作应该如何填充 created/updated
//MetaObject代表自动填充的默认配置.
@Override
public void insertFill(MetaObject metaObject) {
Date date = new Date();
this.setFieldValByName("created",date,metaObject);
this.setFieldValByName("updated",date,metaObject);
}
//完成修改操作应该如何填充 updated
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updated",new Date(),metaObject);
}
}
5. 商品分类实现
5.1 实现商品分类页面跳转
5.1.1 页面分析
需求: 当用户跳转/itemCat时,应该展现ItemCat.vue组件.
5.2 ItemCat 设计说明
5.2.1 表设计说明
说明: 商品分类结构的字段信息. 通过parent_id 控制父子级关系.
5.2.2 常见业务说明
说明: 每个层级下,都会有自己的单独的子级. 1级下边有2级 2级下边有3级.
一般层级结构,不要超过3级.
5.2.3 定义POJO属性
5.3 层级代码结构展现
5.4 商品分类数据查询结构
/*查询一级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id=0
/*查询二级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id=438
/*查询三级商品分类信息*/
SELECT * FROM item_cat WHERE parent_id=486
5.5 商品分类页面分析
- 生命周期函数
- 页面Ajax调用
5.6 商品分类业务接口文档
- 请求路径: /itemCat/findItemCatList/{level}
- 请求类型: get
- 请求参数: level
参数名称 | 参数说明 | 备注 |
---|---|---|
level | 查询级别 | 1查询一级分类 2查询1-2 级商品分类 3查询1-2-3级商品分类 |
- 业务说明: 查询3级分类菜单数据 要求三层结构嵌套
- 返回值: SysResult对象
参数名称 | 参数说明 | 备注 |
---|---|---|
status | 状态信息 | 200表示服务器请求成功 201表示服务器异常 |
msg | 服务器返回的提示信息 | 可以为null |
data | 服务器返回的业务数据 | 3级商品分类信息 |
5.7 编辑ItemCatController
/**
* 业务说明: 实现商品分类查询
* URL: /itemCat/findItemCatList/{level}
* 参数: level 查询的层级
* 返回值: SysResult(List)
*/
@GetMapping("/findItemCatList/{level}")
public SysResult findItemCatList(@PathVariable Integer level){
List<ItemCat> itemCatList = itemCatService.findItemCatList(level);
return SysResult.success(itemCatList);
}
5.8 编辑ItemCatService
/**
* 1.查询所有的一级菜单
* 2.遍历一级查询所有的二级菜单
* 3.遍历二级查询所有的三级菜单
* 4. 2级封装3级菜单, 1级封装2级菜单
* @param level
* @return
*/
@Override
public List<ItemCat> findItemCatList(Integer level) {
//记录开始时间
long startTime = System.currentTimeMillis();
QueryWrapper<ItemCat> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id",0);
List<ItemCat> oneList = itemCatMapper.selectList(queryWrapper);
//2.遍历一级菜单 根据一级查询二级菜单
for (ItemCat oneItemCat : oneList){
queryWrapper.clear();
queryWrapper.eq("parent_id",oneItemCat.getId());
List<ItemCat> twoList = itemCatMapper.selectList(queryWrapper);
//3.将二级列表进行遍历,根据二级ID查询三级
for(ItemCat twoItemCat : twoList){
queryWrapper.clear();
queryWrapper.eq("parent_id",twoItemCat.getId());
List<ItemCat> threeList = itemCatMapper.selectList(queryWrapper);
//数据的封装
twoItemCat.setChildren(threeList);
}
//将二级数据封装到一级中
oneItemCat.setChildren(twoList);
}
long endTime = System.currentTimeMillis();
System.out.println("程序耗时:"+(endTime - startTime));
return oneList;
}
5.9 页面效果展现
作业
- 完成课堂代码,完成课堂业务要求. 用户模块/商品分类模块列表展现
- 完成用户模块的重构
1.1 手写User.VUE页面和JS
1.2 重写用户模块业务 列表/新增/状态修改/修改/删除操作. - 选做 优化ItemCat查询方式 将查询速度优化到 100毫秒之内.