SSMP整合案例含分页查询功能

SSMP整合案例

一个模块的增删改查
在这里插入图片描述

模块创建

  1. 勾选SpringMVC和Mysql坐标
  2. 修改配置文件为yml格式
  3. 设置端口为80方便访问

实体类快速开发(lombok)

  • 工具lombok,一个java类库,提供了一组注解,简化pojo实体类开发

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

    常用注解:@Data

    @Data
    //@NoArgsConstructor//无参构造方法
    public class Book {
        private Integer id;
        private String type;
        private String name;
        private String description;
    
    }
    
    

    为当前实体类在编译期设置对应的get/set方法,toString方法,hashCode方法,equals方法等

数据层标准开发

手工导入starter坐标2个

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

MybatisPlus和Druid相关配置

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ssm_db
      username: root
      password: 123456

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

开发Dao接口(继承BaseMapper)

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

测试

@SpringBootTest
class BookDaoTest {

    @Autowired
    private BookDao bookDao;

    @Test
    void getById() {
        bookDao.selectById(1);
    }
    @Test
    void save() {
        Book book = new Book();
        book.setType("测试数据1");
        book.setName("测试数据1");
        book.setDescription("测试数据1");
        bookDao.insert(book);
    }
    @Test
    void update() {
        Book book = new Book();
        book.setId(2);
        book.setType("测试数据2");
        book.setName("测试数据2");
        book.setDescription("测试数据2");
        bookDao.updateById(book);
    }
    @Test
    void delete() {
        bookDao.deleteById(3);
    }

    @Test
    void getAll() {
        bookDao.selectList(null);
    }
  }

开启MyBatisPlus日志

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

分页

@Test
    void testGetpage() {
        //current 当前页
        IPage page = new Page(1,5);
        bookDao.selectPage(page,null);
        System.out.println(page.getCurrent());
        System.out.println(page.getPages());
        System.out.println(page.getRecords());
        System.out.println(page.getSize());
    }
  • IPage对象中封装了分页操作中的所有数据

    • 数据

    • 当前页码值

    • 每页数据总量

    • 最大页码值

    • 数据总量

MyBatisPlus拦截器,实现动态拼写SQL语句

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

固定格式

条件查询功能

  • 使用QueryWrapper对象封装查询条件,推荐使用LambdaQueryWrapper对象,所有查询操作封装成方法调用
@Test
    void GetBy(){
        //select*from tbl_book where(name LIKE ?)
        QueryWrapper<Book> qw = new QueryWrapper<>();
        qw.like("name","java");
        bookDao.selectList(qw);
    }

//安全性更强:
@Test
    void GetBy2(){
        String name = "java";
        //select*from tbl_book where(name LIKE ?)
        LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
//        if (name!=null) lqw.like(Book::getName,name);
        lqw.like(name!=null,Book::getName,name);
        bookDao.selectList(lqw);
    }
  • 带分页的条件查询,支持动态拼写查询条件
@Test
void testGetByCondition(){
    String name = "java";
    IPage page=new Page(1,10);
    LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
    lqw.like(Strings.isNotEmpty(name),Book::getName,name);
    bookDao.selectPage(page,lqw);
}

业务层开发

Service层接口定义与数据层接口定义具有较大区别,不要混用

  • selectByUserNameAndPassword (String username,stringpassword);

    数据层对应的名称

  • login(String username,String password );

    业务层对应的名称

  • 接口

public interface BookService {
    Boolean save(Book book);
    Boolean update(Book book);
    Boolean delete(Integer id);
    Book getById(Integer id);
    List<Book> selectAll();
    IPage<Book> getPage(int currentPage,int pageSize);
}
  • 实现类

    @Service
    public class BookServiceImpl implements BookService {
       @Autowired
       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> selectAll() {
            return bookDao.selectList(null);
        }
    
        @Override
        public IPage<Book> getPage(int currentPage, int pageSize) {
            IPage page = new Page(currentPage,pageSize);
            return bookDao.selectPage(page,null);
        }
    }
    
    
  • 测试

@SpringBootTest
class BookServiceImplTest {

@Autowired
private BookService bookService;

    @Test
    void getById() {
        System.out.println(bookService.getById(2));
    }

    void save() {
        Book book = new Book();
        book.setType("测试数据1");
        book.setName("测试数据1");
        book.setDescription("测试数据1");
        bookService.save(book);
    }
    @Test
    void update() {
        Book book = new Book();
        book.setId(2);
        book.setType("测试数据2");
        book.setName("测试数据2");
        book.setDescription("测试数据2");
        bookService.update(book);
    }
    @Test
    void delete() {
        bookService.delete(3);
    }

    @Test
    void getAll() {
        bookService.selectAll();
    }

    @Test
    void testGetPage(){
        IPage<Book> page = bookService.getPage(2,5);
        System.out.println(page.getCurrent());
        System.out.println(page.getPages());
    }


}

业务层快速开发

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

    //    @Override
//    当想要添加已有功能以外的业务时,如果担心写的方法名跟已有的重名
//    就添加@Override,如果报错则没有重名
    boolean savaBook1(Book book);
}
@Service
//ServiceImpl<?, ?> 第一个是引用的实现类,第二个是对应的实体类
public class IBookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {

        @Autowired
        private BookDao bookDao;

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

表现层标准开发

  • 基于Restful进行表现层接口开发
  • 使用Postman测试表现层接口功能
@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService iBookService;

    @GetMapping
    public List<Book> getAll(){
        return iBookService.list();
    }


    //请求体传json数据
    @PostMapping
    public boolean save(@RequestBody  Book book){
        return iBookService.save(book);
    }

    @PutMapping
    public Boolean update(@RequestBody Book book){
        return iBookService.updateById(book);
    }

    //路径传参
    @DeleteMapping("{id}")
    public Boolean delete(@PathVariable Integer id){
        return iBookService.removeById(id);
    }

    //http://localhost/books/2
    @GetMapping("{id}")
    public Book getById(@PathVariable Integer id){
        return iBookService.getById(id);
    }

    @GetMapping("{currentPage}/{pageSize}")
    public IPage<Book> getPage(@PathVariable int currentPage,@PathVariable int pageSize){
        return iBookService.getPage(currentPage,pageSize);
    }

}
  • 查询Get(路径传参@PathVarriable)
  • 修改Put(请求体传参@RequestBody)
  • 新增Post(请求体传参@RequestBody)
  • 删除Delete(路径传参@PathVarriable)

消息一致性处理

  • 格式A:true/false
  • 格式B:json
  • 格式C:json数组

统一格式:

data来封装数据

为避免null不清楚是数据null还是抛出异常null 使用flag来代表查询结果的成功或失败

  • 设计表现层返回结果的模型类,用于前后端进行数据格式统一,即前后端数据协议

    @Data
    public class R {
        private Boolean flag;
        private Object data;
    
         public R(){}
    
        public R(Boolean flag){
            this.flag=flag;
        }
    
        public R(Boolean flag,Object data){
            this.flag=flag;
            this.data=data;
        }
    }
    
    
  • 修改表现层,返回值改为R

    @RestController
    @RequestMapping("/books")
    public class BookController2 {
        @Autowired
        private IBookService iBookService;
    
        @GetMapping
        public List<Book> getAll(){
            return iBookService.list();
        }
    
    
        //请求体传json数据
        @PostMapping
        public R save(@RequestBody  Book book){
    //        R r = new R();
    //        boolean flag = iBookService.save(book);
    //        r.setFlag(flag);
            return new R(iBookService.save(book));
        }
    
        @PutMapping
        public R update(@RequestBody Book book){
    
            return new R(iBookService.updateById(book));
        }
    
        //路径传参
        @DeleteMapping("{id}")
        public R delete(@PathVariable Integer id){
    
            return new R(iBookService.removeById(id));
        }
    
        //http://localhost/books/2
        @GetMapping("{id}")
        public R getById(@PathVariable Integer id){
            return new R(true,iBookService.getById(id));
        }
    
        @GetMapping("{currentPage}/{pageSize}")
        public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
            return new R(true,iBookService.getPage(currentPage,pageSize));
        }
    
    }
    

数据统一为Json格式:
在这里插入图片描述

前后端协议联调

  • 前后端分离结构设计中页面归属前端服务器
  • 单体工程中页面放置在resource目录下的static目录中(建议执行clean)

单体项目中页面放置在resources/static目录下

created钩子函数用于初始化页面时发起调用

页面使用axios发送异步请求获取数据后确认后端是否联通

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

        methods: {
            //列表
            getAll() {
                //发送异步请求
                axios.get("http://localhost:80/books ").then((res)=>{
                    console.log(res.data);
                });
            },
//由于idea默认端口是63442端口,而服务器是80端口,导致无法直接访问,需要跨域
@CrossOrigin("http://localhost:63342")

将查询数据返回到页面,利用前端数据双向绑定进行数据展示
在这里插入图片描述

getAll() {
                //发送异步请求
                axios.get("http://localhost:80/books ").then((res)=>{
                    // console.log(res.data);
                    this.dataList=res.data.data;
                    // console.log(this.dataList);
                });
            },

新增操作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

点击新增后打开弹窗

//弹出添加窗口
            handleCreate() {
                this.dialogFormVisible=true;
                this.resetForm();
            },

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

            //添加
            handleAdd () {
                axios.post("http://localhost:80/books",this.formData).then((res)=>{
                    //判断当前操作是否成功
                    if(res.data.flag){
                        this.dialogFormVisible=false;
                        this.$message.success("添加成功!");
                    }else{
                        this.$message.error("添加失败!");
                    }
                }).finally(()=>{
                    this.getAll();
                })
            },

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

删除功能

// 删除
            handleDelete(row) {
                // // console.log(row);

                this.$confirm("此操作永久删除,是否继续?","提示",{type:"info"}).then(()=>{
                    axios.delete("http://localhost:80/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("http://localhost:80/books/"+row.id).then((res)=>{
                    // console.log(res.data);
                    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("http://localhost:80/books",this.formData).then((res)=>{
                    //判断当前操作是否成功
                    if(res.data.flag){
                        this.dialogFormVisible4Edit=false;
                        this.$message.success("修改成功!");
                    }else{
                        this.$message.error("修改失败!");
                    }
                }).finally(()=>{
                    this.getAll();
                })
            },

抛出异常消息:

{

“timestamp”: “2023-08-10T07:52:26.836+00:00”,

“status”: 500,

“error”: “Internal Server Error”,

“path”: “/books”

}

  • 后台代码BUG导致数据格式不统一性

异常处理器

//异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
    @ExceptionHandler
    public R doException(Exception ex){
        //记录日志
        //通知运维
        //通知开发
        ex.printStackTrace();
        return new R("服务器故障,请稍后再试!");
    }
}

业务消息一致性处理

  • 修改表现层返回结果的模型类,封装出现异常后对应的信息
    • flag: false
    • Data: null
    • 消息(msg):要显示信息
@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,String msg){
        this.flag=flag;
        this.data=data;
        this.msg=msg;
    }
    public R(boolean flag,String msg){
        this.flag=flag;
        this.msg=msg;
    }
    public R(String msg){
        this.flag=false;
        this.msg=msg;
    }
}
  • 页面消息处理,没有传递消息加载默认消息,传递消息后加载指定消息

     //添加
                handleAdd () {
                    axios.post("http://localhost:80/books",this.formData).then((res)=>{
                        //判断当前操作是否成功
                        if(res.data.flag){
                            this.dialogFormVisible=false;
                            this.$message.success(res.data.msg);
                        }else{
                            this.$message.error(res.data.msg);
                        }
                    }).finally(()=>{
                        this.getAll();
                    })
                },
    
                    
    
  • 在表现层Controller中进行消息统一处理

     @PostMapping
        public R save(@RequestBody  Book book) throws IOException {
            if(book.getName().equals("123")) throw new IOException();
            boolean flag=iBookService.save(book);
            return new R(flag,flag?"添加成功":"添加失败!");
        }
    

分页功能

  • 页面使用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>
    
  • 定义分页组件需要使用的数据

    data:{
        pagination: {//分页相关模型数据
            currentPage: 1,//当前页码
            pageSize:5,//每页显示的记录数
            total:0//总记录数
        }
    },
    
  • 替换查询全部功能为分页功能,并加载分页数据

    //分页查询
                getAll() {
                    //发送异步请求
                    axios.get("http://localhost:80/books/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res)=>{
                        // console.log(res.data);
                        this.pagination.pageSize=res.data.data.size ;
                        this.pagination.currentPage=res.data.data.current ;
                        this.pagination.total=res.data.data.total ;
                        this.dataList=res.data.data.records;
                        // console.log(this.dataList);
                    });
                },
    

    完善切换页码功能

    //切换页码
    handleCurrentChange(currentPage) {
          //修改页码值为当前选中的页码值
          this.pagination.currentPage=currentPage;
           //执行查询
           this.getAll();
    },
    

Bug:当最后一页只剩一条数据时,删掉该数据但页码并不减少,仍停留在这一页

后台处理:

  • 对查询结果进行校验,如果当前页码值大于最大页码值,使用最大页码值作为当前页码值重新查询(补救型方案)

    @GetMapping("{currentPage}/{pageSize}")
        public R 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 R(true,page);
        }
    
    

分页+条件查询

  • 页面数据模型绑定
    在这里插入图片描述

  • 组织拼接数据成为get请求发送的数据
    在这里插入图片描述

  • Controller接受参数

    //接受条件查询结果
        @GetMapping("{currentPage}/{pageSize}")
        public R getPage(@PathVariable int currentPage,@PathVariable int pageSize,Book book){
    //        System.out.println("参数==》"+book);
            IPage<Book> page = iBookService.getPage(currentPage,pageSize,book);
            //如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码
            if(currentPage > page.getPages()){
                page = iBookService.getPage((int)page.getPages(),pageSize,book);
            }
            return new R(true,page);
        }
    
  • 业务层接口功能开发

    public interface IBookService extends IService<Book> {
        IPage<Book> getPage(int currentPage,int pageSize);
        IPage<Book> getPage(int currentPage,int pageSize,Book book);//新增接收book
    }
    
    
    //条件分页查询
    @Override
    public IPage<Book> getPage(int currentPage, int pageSize, Book book) {
        LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
        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);
         return bookDao.selectPage(page,lqw);
    }
    
    
    
    
  • 业务层接口功能开发

    public interface IBookService extends IService<Book> {
        IPage<Book> getPage(int currentPage,int pageSize);
        IPage<Book> getPage(int currentPage,int pageSize,Book book);//新增接收book
    }
    
    //条件分页查询
    @Override
    public IPage<Book> getPage(int currentPage, int pageSize, Book book) {
        LambdaQueryWrapper<Book> lqw = new LambdaQueryWrapper<Book>();
        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);
         return bookDao.selectPage(page,lqw);
    }
    
  • 51
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值