【基于springboot的SSMP整合案例1】业务消息一致性处理及页面功能开发5

1. 业务消息一致性处理

目前的功能制作基本上达成了正常使用的情况,什么叫正常使用呢?也就是这个程序不出BUG,如果我们搞一个BUG出来,你会发现程序马上崩溃掉。比如后台手工抛出一个异常,看看前端接收到的数据什么样子
在这里插入图片描述
面对这种情况,前端的开发者又懵了,他们不知道该如何解析这组数据,因此,不仅要对正确的操作数据格式做处理,还要对错误的操作数据格式做同样的格式处理

  1. 首先在当前的数据结果中添加消息字段,用来兼容后台出现的操作消息
@Data
public class R {

    private boolean flag;
    private Object data;
    private String msg;

    public R(){}

    public R(boolean flag){
        this.flag = flag;
    }

    public R(boolean flag,Object data){
        this.flag = flag;
        this.data = data;
    }
    public R(String msg){
        //this.flag = false;
        this.msg = msg;
    }
    public R(boolean flag ,String msg){
        this.flag = flag;
        this.msg = msg;
    }
}

  1. 后台模拟错误,做出相对应的修改操作
    我们在新增请求上添加了一个异常信息,当输入的name为123就会报错,否则就会调用相对于的语句进行返回。
 @PostMapping
    public R insert(@RequestBody Book book) throws Exception {

        if (book.getName().equals("123")) throw new Exception();

        boolean flag = bookService.save(book);
        //return new R(bookService.save(book));
        return new R(flag, flag ? "添加成功^_^" : "添加失败");
    }

  1. 表现层做统一的异常处理,使用SpringMVC提供的异常处理器做统一的异常处理

我们新建一个工具加强类ProjectExceptionAdvice,这是aop的思想,了解过aop的小伙伴应该清楚。

这是在表现层定义的异常处理器,小伙伴们肯定会好奇说那么数据层和业务层出现异常怎么办呢,其实不然,数据层和业务层的异常最后都会抛到表现层,因此我们只需要在表现出设置一个异常处理器解决异常即可。

//做为springmvc的异常处理器
//1.定义为controller的异常处理器
//@ControllerAdvice
@RestControllerAdvice//其实就是一个Bean
public class ProjectExceptionAdvice {
    //拦截所有的异常信息,也可以在字节码对象中指定异常类型
    @ExceptionHandler(Exception.class)
    public R doException(Exception ex){
        //记录日志
        //通知运维
        //通知开发
        ex.printStackTrace();//控制台输出异常信息方便调试
        return new R(false,"服务器故障,稍后再试");
    }
}
  1. 页面上得到数据后,先判定是否有后台传递过来的消息,标志就是当前操作是否成功,如果返回操作结果false,就读取后台传递的消息
//添加
    handleAdd () {
        //post发送新增的数据,将发送的数据传给formData
        axios.post("/books",this.formData).then((res)=>{
            //判断当前操作是否成功
            if(res.data.flag){
                //1.关闭弹层
                this.dialogFormVisible = false;
                this.$message.success(res.data.msg);
            }else {
                this.$message.error(res.data.msg);
            }
        }).finally(()=>{
            //2.重新刷新数据
            this.getAll();
        })
    },

我们看一下修改过后出现异常的报错信息
在这里插入图片描述
这时候前端就知道程序出现异常,然后通知相关开发进行维护。

总结:
1. 使用注解@RestControllerAdvice定义SpringMVC异常处理器用来处理异常的
2. 异常处理器必须被扫描加载,否则无法生效
3. 表现层返回结果的模型类中添加消息属性用来传递消息到页面

2. 页面功能开发

2.1 分页功能

2.1.1 页面使用el分页组件添加分页功能
<!--分页组件-->
<div class="pagination-container">
    <el-pagination
		class="pagiantion"
		@current-change="handleCurrentChange"
		:current-page="pagination.currentPage"
		:page-size="pagination.pageSize"
		layout="total, prev, pager, next, jumper"
		:total="pagination.total">
    </el-pagination>
</div>
2.1.2 封装分页对应的数据模型
data:{
	pagination: {	
		//分页相关模型数据
		currentPage: 1,	//当前页码
		pageSize:10,	//每页显示的记录数
		total:0,		//总记录数
	}
},
2.1.3 修改查询全部功能为分页查询,通过路径变量传递页码信息参数
getAll() {
    axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {
    });
},
2.1.4 后台提供对应的分页功能
@GetMapping("/{currentPage}/{pageSize}")
public R getAll(@PathVariable int currentPage,@PathVariable int pageSize){
    IPage<Book> pageBook = bookService.getPage(currentPage, pageSize);
    return new R(null != pageBook ,pageBook);
}
2.1.5 页面根据分页操作结果读取对应数据,并进行数据模型绑定
getAll() {
    axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res) => {
        this.pagination.total = res.data.data.total;
        this.pagination.currentPage = res.data.data.current;
        this.pagination.pagesize = res.data.data.size;
        this.dataList = res.data.data.records;
    });
},
2.1.6 切换页码功能
	//切换页码
      handleCurrentChange(currentPage) {
          //1.修改页码值为当前选中的页码值
          this.pagination.currentPage = currentPage;
          //2.重新查询
          this.getAll();
      },

可以看到,右下角分页数据已经绑定成功。
在这里插入图片描述

2.2 删除功能维护

由于使用了分页功能,当最后一页只有一条数据时,删除操作就会出现BUG,最后一页无数据但是独立展示,对分页查询功能进行后台功能维护,如果当前页码值大于最大页码值,重新执行查询。
此时,我们需要对分页操作做出相对应的处理操作

@GetMapping("{currentPage}/{pageSize}")
    public R testPage(@PathVariable int currentPage, @PathVariable int pageSize) {
        IPage<Book> page = bookService.getPage(currentPage, pageSize);
        if(currentPage > page.getPages()){
            //如果当前页码大于总页码,重新查询一遍
            //加int强转是因为getPages返回long型,然后将getPage里面的参数currentPage换成page.getPages()
            page = bookService.getPage((int)page.getPages(), pageSize);
        }
        return new R(true,page);
        //return new R(true, bookService.getPage(currentPage, pageSize));
    }

在这里插入图片描述
这样,当我们删除第三页这条数据页面就会自动跳转到第二页,而不会出现显示第三页每有数据的尴尬。

2.3 条件查询

​ 最后一个功能来做条件查询,其实条件查询可以理解为分页查询的时候除了携带分页数据再多带几个数据的查询。这些多带的数据就是查询条件。比较一下不带条件的分页查询与带条件的分页查询差别之处,这个功能就好做了

  • 页面封装的数据:带不带条件影响的仅仅是一次性传递到后台的数据总量,由传递2个分页相关的数据转换成2个分页数据加若干个条件

  • 后台查询功能:查询时由不带条件,转换成带条件,反正不带条件的时候查询条件对象使用的是null,现在换成具体条件,差别不大

  • 查询结果:不管带不带条件,出来的数据只是有数量上的差别,其他都差别不大,这个可以忽略

    经过上述分析,看来需要在页面发送请求的格式方面做一定的修改,后台的调用数据层操作时发送修改,其他没有区别

    页面发送请求时,两个分页数据仍然使用路径变量,其他条件采用动态拼装url参数的形式传递

2.3.1 页面封装查询条件字段
pagination: {//分页相关模型数据
                currentPage: 1,//当前页码
                pageSize:10,//每页显示的记录数
                total:0,//总记录数
                type:"",
                name:"",
                description:""
            }
        },
2.3.2 页面添加查询条件字段对应的数据模型绑定名称

找到条件查询相关的表单,绑定数据模型。
在这里插入图片描述

2.3.3 将查询条件组织成url参数,添加到请求url地址中
//分页查询
 getAll() {
     //组织参数,拼接url请求地址
     //   /books/1/10?type=???&name=???&description=???
     param = "?type="+this.pagination.type;
     param += "&name="+this.pagination.name;
     param += "&description="+this.pagination.description;
     //console.log(param);

     //使用axios发送异步请求
     axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res)=>{
         //console.log(res.data);
         //第一个data包含全数据,即有flag,又有data,第二个data就表示上一级的data中的data
         //data里面的records才是查询到的前十条数据
         this.dataList = res.data.data.records;
     });
 },
2.3.4 后台代码中定义实体类封查询条件
@GetMapping("{currentPage}/{pageSize}")
    public R testPage(@PathVariable int currentPage, @PathVariable int pageSize,Book book) {
        IPage<Book> page = bookService.getPage(currentPage, pageSize,book);
        if(currentPage > page.getPages()){
            //如果当前页码大于总页码,重新查询一遍
            //加int强转是因为getPages返回long型,然后将getPage里面的参数currentPage换成page.getPages()
            page = bookService.getPage((int)page.getPages(), pageSize,book);
        }
        return new R(true,page);
        //return new R(true, bookService.getPage(currentPage, pageSize));
    }
2.3.5 修改业务层接口及实现类
public IPage<Book> getPage(int currentPage,int pageSize,Book book);
@Override
    public IPage<Book> getPage(int currentPage, int pageSize, Book book) {
        LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<>();
        lqw.like(Strings.isNotEmpty(book.getType()),Book::getType,book.getType());
        lqw.like(Strings.isNotEmpty(book.getName()),Book::getName,book.getName());
        lqw.like(Strings.isNotEmpty(book.getDescription()),Book::getDescription,book.getDescription());

        IPage page = new Page(currentPage,pageSize);
        bookDao.selectPage(page,lqw);
        return page;
    }
2.3.6 页面回显数据
 //分页查询
getAll() {
     //组织参数,拼接url请求地址
     //   /books/1/10?type=???&name=???&description=???
     param = "?type="+this.pagination.type;
     param += "&name="+this.pagination.name;
     param += "&description="+this.pagination.description;
     //console.log(param);

     //使用axios发送异步请求
     axios.get("/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res)=>{
         //console.log(res.data);
         //第一个data包含全数据,即有flag,又有data,第二个data就表示上一级的data中的data
         //data里面的records才是查询到的前十条数据
         this.dataList = res.data.data.records;
         this.pagination.currentPage = res.data.data.current;
         this.pagination.total = res.data.data.total;
         this.pagination.pageSize = res.data.data.size;
     });
 },

ok,条件查询到这里就结束了,做了这么多,我们来看一下实现效果吧。
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值