0
点赞
收藏
分享

微信扫一扫

基于SpringBoot的SSMP(Spring+SpringMVC+Mybatis-Plus)整合实现CURD功能

基于SpringBoot的SSMP(Spring+SpringMVC+Mybatis-Plus)整合实现CURD功能

项目结构

在这里插入图片描述

1 环境搭建

新建项目:
在这里插入图片描述
修改配置文件格式为yml

2 实体类开发------Lombok

Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发,需要引入相关坐标,lombok版本由SpringBoot提供,无需指定版本;常用注解:@Data,为当前实体类在编译期设置对应的get/set方法,toString方法,hashCode方法,equals方法等

在pom.xml中导入Lombok坐标:

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

创建book实体:

package com.lifeilin.domain;

import lombok.Data;

@Data
public class Book {
    private Integer id;
    private String type;
    private String name;
    private String description;
}

3 Dao开发------MyBatisPlus + Druid

创建项目时使用阿里云网站创建,勾选了MyBatisPlus,即项目中有了MyBatisPlus坐标,只需要pom.xml中导入Druid坐标:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

配置数据源与MyBatisPlus对应的基础配置(id生成策略使用数据库自增策略)

# 应用名称
spring.application.name: SpringBoot_06_ssmp
# 应用服务 WEB 访问端口
server.port: 8080
# 数据库驱动:
spring.datasource.driver-class-name: com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name: defaultDataSource
# 数据库连接地址
spring.datasource.url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username: root
spring.datasource.password: LIFEILIN

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
      id-type: auto

继承BaseMapper并指定泛型:BaseMapper中已经定义好了基本的增删查改语句,直接调用对应的方法即可使用。
在这里插入图片描述

@Mapper
public interface BookDao extends BaseMapper<Book> {
}

为方便调试可以开启MyBatisPlus的日志
在这里插入图片描述

3.1 分页功能

分页操作需要设定分页对象IPage:
在这里插入图片描述

@Test
void testGetPage(){
    IPage page = new Page(2,5);
    bookDao.selectPage(page,null);
}

在这里插入图片描述
分页操作是在MyBatisPlus的常规操作基础上增强得到,内部是动态的拼写SQL语句,因此需要增强对应的功能,使用MyBatisPlus拦截器实现
在项目下建立config包,该包下建立拦截器类实现拦截器:

package com.lifeilin.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MPConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return interceptor;
    }
}

3.2 条件查询功能

@Test
void testGetBy(){
    QueryWrapper<Book> queryWrapper = new QueryWrapper<>();
    queryWrapper.like("name","Spring");
    bookDao.selectList(queryWrapper);
}
@Test
void testGetBy2(){
    String name = null;
    LambdaQueryWrapper<Book> lambdaQueryWrapper = new LambdaQueryWrapper<>();
    lambdaQueryWrapper.like(name!=null,Book::getName,name);
    bookDao.selectList(lambdaQueryWrapper);
}

4 Service开发------基于MyBatisPlus进行增量开发

4.1 标准开发

定义接口:

public interface BookService {
    Boolean save(Book book);

    Boolean update(Book book);

    Boolean delete(Integer id);

    Book getById(Integer id);

    List<Book> getAll();

    IPage<Book> getPage(int currentPage,int pageSize);
}

定义接口的实现:

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;

    @Override
    public Boolean save(Book book) {
        return bookDao.insert(book) > 0;
    }

    @Override
    public Boolean update(Book book) {
        return bookDao.updateById(book) > 0;
    }

    @Override
    public Boolean delete(Integer id) {
        return bookDao.deleteById(id) > 0;
    }

    @Override
    public Book getById(Integer id) {
        return bookDao.selectById(id);

    }

    @Override
    public List<Book> getAll() {
        return bookDao.selectList(null);
    }

    //分页查询
    @Override
    public IPage<Book> getPage(int currentPage, int pageSize) {
        Page page = new Page(currentPage, pageSize);
        return bookDao.selectPage(page, null);
    }
}

4.2 基于MyBatisPlus快速开发(避免重复代码)

快速开发方案
 使用MyBatisPlus提供有业务层通用接口(ISerivce)与业务层通用实现类(ServiceImpl<M,T>)
 在通用类基础上做功能重载或功能追加
 注意重载时不要覆盖原始操作,避免原始提供的功能丢失

定义接口:

package com.lifeilin.service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.lifeilin.domain.Book;

public interface IBookService extends IService<Book> {
    //自增的分页查询
    IPage<Book> getPage(int currentPage,int pageSize);
}

在这里插入图片描述
定义实现类:

package com.lifeilin.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lifeilin.dao.BookDao;
import com.lifeilin.domain.Book;
import com.lifeilin.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl2 extends ServiceImpl<BookDao, Book> implements IBookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public IPage<Book> getPage(int currentPage, int pageSize) {
        Page page = new Page(currentPage, pageSize);
        bookDao.selectPage(page,null);
        return page;
    }
}

5 Controller开发------Restful开发 + 前后端开发协议

表现层消息一致性处理:在controller包下新建utils包,新建一个类处理消息数据一致性

package com.lifeilin.controller.utils;

import lombok.Data;

@Data
public class Result {
    private Boolean flag;
    private Object data;

    public Result() {
    }

    public Result(Boolean flag) {
        this.flag = flag;
    }

    public Result(Boolean flag, Object data) {
        this.flag = flag;
        this.data = data;
    }
}

controller层类返回上面创建类的类型以统一数据格式:

package com.lifeilin.controller;

import com.lifeilin.controller.utils.Result;
import com.lifeilin.domain.Book;
import com.lifeilin.service.IBookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/books")
public class BookController2 {
    @Autowired
    private IBookService iBookService;

    //查询所有
    @GetMapping
    public Result getAll() {
        return new Result(true, iBookService.list());
    }

    //保存 json请求体数据
    @PostMapping
    public Result save(@RequestBody Book book) {
        return new Result(iBookService.save(book));
    }

    //更新 json请求体数据
    @PutMapping
    public Result update(@RequestBody Book book) {
        return new Result(iBookService.updateById(book));
    }

    //删除 使用路径参数
    @DeleteMapping("{id}")
    public Result delete(@PathVariable Integer id) {
        return new Result(iBookService.removeById(id));
    }

    //查询单个 使用路径参数
    @GetMapping("{id}")
    public Result getById(@PathVariable Integer id) {
        return new Result(true, iBookService.getById(id));
    }

    //分页查询 使用路径变量传参数
    @GetMapping("{currentPage}/{pageSize}")
    public Result getPage(@PathVariable int currentPage, @PathVariable int pageSize) {
        return new Result(true, iBookService.getPage(currentPage, pageSize));
    }
}

6 页面开发------基于VUE+ElementUI,前后端联调,页面数据处理,页面消息处理(列表、新增、修改、删除、分页、查询)

初始页面:
在这里插入图片描述
前端核心业务代码:

var vue = new Vue({
    el: '#app',
    data: {
        dataList: [],//当前页要展示的列表数据
        dialogFormVisible: false,//添加表单是否可见
        dialogFormVisible4Edit: false,//编辑表单是否可见
        formData: {},//表单数据
        rules: {//校验规则
            type: [{required: true, message: '图书类别为必填项', trigger: 'blur'}],
            name: [{required: true, message: '图书名称为必填项', trigger: 'blur'}]
        },
        pagination: {//分页相关模型数据
            currentPage: 1,//当前页码
            pageSize: 10,//每页显示的记录数
            total: 0//总记录数
        }
    },

    //钩子函数,VUE对象初始化完成后自动执行
    created() {
        //调用查询全部数据的操作
        this.getAll();
    },

    methods: {
        //列表
        getAll() {
            //发送异步请求
            axios.get("/books").then((res) => {
                this.dataList = res.data.data;
            })
        },

        //弹出添加窗口
        handleCreate() {
            //dialogFormVisible: false,//添加表单是否可见
            this.dialogFormVisible = true;
            this.resetForm();
        },

        //重置表单
        resetForm() {
            this.formData = {};
        },

        //添加
        handleAdd() {
            axios.post("/books", this.formData).then((res) => {
                if (res.data.flag) {
                    // 关闭弹层
                    this.dialogFormVisible = false;
                    this.$message.success("添加成功");
                } else {
                    this.$message.error(res.data.msg);//从后台读提示信息
                }
            }).finally(() => {
                // 重新加载列表数据
                this.getAll();
            });
        },

        //取消
        cancel() {
            this.dialogFormVisible = false;
            this.dialogFormVisible4Edit = false;
            this.$message.info("当前操作取消");
        },

        // 删除
        handleDelete(row) {
            this.$confirm("此操作永久删除当前信息,是否继续?", "提示", {type: "info"}).then(() => {
                axios.delete("/books/" + row.id).then((res) => {
                    if (res.data.flag) {
                        this.$message.success("删除成功");
                    } else {
                        this.$message.error("数据同步失败,自动刷新");
                    }
                }).finally(() => {
                    // 重新加载列表数据
                    this.getAll();
                });
            }).catch(() => {
                this.$message.info("取消操作");
            });
        },

        //弹出编辑窗口
        handleUpdate(row) {
            axios.get("/books/", row.id).then((res) => {
                if (res.data.flag && res.data.data != null) {
                    this.dialogFormVisible4Edit = true;
                    this.formData = res.data.data;
                } else {
                    this.$message.error("数据同步失败,自动刷新");
                }
            }).finally(() => {
                // 重新加载列表数据
                this.getAll();
            });
        },

        //修改
        handleEdit() {
            axios.put("/books", this.formData).then((res) => {
                if (res.data.flag) {
                    // 关闭弹层
                    this.dialogFormVisible4Edit = false;
                    this.$message.success("修改成功");
                } else {
                    this.$message.error("修改失败");
                }
            }).finally(() => {
                // 重新加载列表数据
                this.getAll();
            });
        }
    }
})

6.1 分页查询

这里为了避免一个bug:即总共三页时,第三页只有一条数据,删除这一条数据页面仍然停留在第三页的情况,在controller层进行查询判断控制:

//分页查询 使用路径变量传参数
@GetMapping("{currentPage}/{pageSize}")
public Result getPage(@PathVariable int currentPage, @PathVariable int pageSize) {
    IPage<Book> page = iBookService.getPage(currentPage, pageSize);
    //如果当前页码值大于总页码值,那么重新执行查询操作,使用最大页面值作为当前页码值
    if (currentPage > page.getPages()) {
        page = iBookService.getPage((int) page.getPages(), pageSize);
    }
    return new Result(true, page);
}

在这里插入图片描述

//分页查询
getAll() {
    //发送异步请求
    axios.get("/books/" + this.pagination.currentPage + "/" +
        this.pagination.pageSize
    ).then((res) => {
        this.pagination.currentPage = res.data.data.current;
        this.pagination.pageSize = res.data.data.size;
        this.pagination.total = res.data.data.total;
        this.dataList = res.data.data.records;
    })
},
//切换页码
handleCurrentChange(currentPage) {
    //修改页码值为当前页码值
    this.pagination.currentPage = currentPage;
    //执行查询
    this.getAll();
},

7 项目异常处理

业务操作成功或失败返回数据格式是正常前端想要得到的,但后台代码BUG导致数据格式不统一性,这就需要对异常进行统一处理,出现异常后,返回指定信息,使用异常处理器类处理:

修改表现层返回结果的模型类,封装出现异常后对应的信息
 flag:false
 Data: null
 消息(msg): 要显示信息

在这里插入图片描述

package com.lifeilin.controller.utils;

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

//springmvc的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //拦截所有异常信息
    @ExceptionHandler
    public Result doException(Exception ex) {
        ex.printStackTrace();
        return new Result(false, "服务器故障,请稍后再试");
    }
}

8 按条件查询

在这里插入图片描述
Service层增加接口(修改分页查询接口,在分页查询接口上增加参数):
在这里插入图片描述
Service层实现类:
在这里插入图片描述
controller层:
在这里插入图片描述

举报

相关推荐

0 条评论