SpringBoot基础篇3(SpringBoot+Mybatis-plus案例)

环境搭建:配置起步依赖pom.xml和配置文件application.yml

1.创建模块时,勾选的依赖有springMVC和MySQL驱动

2.手动添加的依赖有:MyBatis-plus、Druid、lombok

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.17</version>
        </dependency>

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

3.设置数据源、端口、框架技术相关配置等

将数据库连接和数据源连接池配置在一起,注意密码是0开头的话要加""。
配置mybatis-plus的表前缀(取决于你自己的表名)、配置自增的方式为表中默认自增,设置为auto(mybatis-plus默认的是雪花算法)、再配置mybatis-plus的日志。

server:
  port: 80

spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
      username: root
      password: "0630"

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
      id-type: auto
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

一、实体类快速开发(lombok)(pojo或domain)

一个标准的bean应该有成员变量、构造器、get/set、toString等方法。
使用lombok组件,使用@Data注解直接标注一个bean为实体类。(该注解没有构造器方法,需要自己添加)

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

二、数据访问层(Dao或Mapper)

数据访问层只管理数据库的连接和操作。数据访问层和持久层有撒子区别,俺也不知道,有木有小伙伴回答一下。。。

1.Dao层

Dao层直接使用mybatis-plus提供的方法。Mapper接口继承BaseMapper<实体类>、并注解@Mapper

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

2.对mybatis-plus提供的访问数据库的方法进行测试

@SpringBootTest
public class BookDaoTestCase {
    @Autowired
    private BookDao bookDao;

    /**
     * 根据id查询
     */
    @Test
    void testGetById() {
        Book book = bookDao.selectById(1);
        System.out.println(book);
    }

    /**
     * 增加一条数据
     */
    @Test
    void testSave() {
        Book book = new Book();
        book.setType("测试数据123");
        book.setName("测试数据123");
        book.setDescription("测试数据123");
        bookDao.insert(book);
    }

    @Test
    void testUpdate() {
        Book book=new Book();
        book.setId(21);
        book.setType("测试数据abc");
        book.setName("测试数据abc");
        book.setDescription("测试数据abc");
        bookDao.updateById(book);
    }
    @Test
    void testDelete() {
        bookDao.deleteById(21);
    }

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

    /**
     * 分页的两个基本数据:这是哪一页数据,这一页有多少条数据
     * 第一页数据,显示5条
     */
    @Test
    void testGetPage() {
        IPage page=new Page(2,5);
        //qw在什么地方都能加  加到这里就是连条件带分页查询
        bookDao.selectPage(page,null);
        System.out.println(page.getCurrent());
        System.out.println(page.getRecords());
    }

    @Test
    void testBy1() {
        QueryWrapper<Book> qw=new QueryWrapper<>();
        qw.like("name",2);
        bookDao.selectList(qw);
    }

    @Test
    void testBy2() {
        String name=null;
        LambdaQueryWrapper<Book> lqw=new LambdaQueryWrapper<>();
        //name不为空就连数据
        lqw.like(name!=null,Book::getName,name);
        bookDao.selectList(lqw);
    }
}

分页方法:

需要两个基本数据:第几页,一页显示几条数据。
分页方法返回的是IPage对象

条件查询:

QueryWrapper和LambdaQueryWrapper可以实现按条件查询。
拼接后的效果:
SELECT id,type,name,description FROM tbl_book WHERE (name LIKE ?)
qw对象可以放在任意地方,放在分页功能里就是带条件查询的分页功能。

三、业务层

业务层的方法名称关注的是业务名称,数据层方法名称关注的是数据库的操作。
调用数据层接口(自己写)或MyBatis-plus提供的接口快速开发。

1.service接口中

继承Iservice<Book>方法,就可以使用mybatis-plus提供的业务层方法。当然页可以自己定义。后两个方法是定义的两个重载的分页方法,一个是普通的分页方法,有两个参数(哪一页,一页有几条数据)。
一个是带条件查询的分页方法,浏览器将条件传到后端,后端再拼接sql查出来。
为什么要用Book接收?
浏览器发送过来的值刚好是Book的属性
请求参数是如何传到后台的? springMVC的知识
请求参数和形参同名,自动注入。或者直接模型类中的属性和请求参数相同,也会直接注入到模型类中(参数绑定 自动注入)

public interface IBookService extends IService<Book> {
    boolean saveBook(Book book);
    boolean modify(Book book);
    boolean delete(Integer id);

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

2.service的实现类

实现类中要extends ServiceImpl<BookDao, Book>
分页就把IPage对象return出去就行,IPage里有记录,大小,总数,当前页等信息。

@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements IBookService {
    @Autowired
    private BookDao bookDao;
    @Override
    public boolean saveBook(Book book) {
        return bookDao.insert(book)>0;
    }

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

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

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

    @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;
    }
}

测试分页功能:

@Test
    void testGetPage(){
        IPage<Book> page = new Page<Book>(2,5);
        bookService.page(page);
        System.out.println(page.getCurrent());//2
        System.out.println(page.getSize());//5
        System.out.println(page.getTotal());//总数
        System.out.println(page.getPages());//总共有几页
        System.out.println(page.getRecords());//记录
    }

四、表现层(表述层:页面到servlet)

基于Restful进行表现层接口开发;使用Postman测试表现层接口功能

  • 新增:POST
  • 删除:DELETE
  • 修改:PUT
  • 查询:GET

controller中写上测试方法,在postman中进行测试
接收参数总体分为两类:(服务器接收参数,浏览器发送请求参数)

  • 请求体操作(传的是json数据)。实体数据@RequestBody
  • 路径变量:@PathVariable
@RestController
@RequestMapping("/books")
public class BookController2 {
    @Autowired
    private IBookService bookService;

    /**
     * 查询全部 发送的是get请求
     * @return
     */
    @GetMapping
    public List<Book> getAll(){
        //通用工具类提供的方法
        return bookService.list();
    }

    /**
     * 新增一个book 发送的是post请求
     * 新增:异步提交发送,通过请求体传json数据过来。传json数据就不能跳转页面了
     * @param book
     * @return
     */
    @PostMapping
    public Boolean save(@RequestBody Book book){
        return bookService.save(book);
    }

    /**
     * 修改book  发送put
     * 修改:传json数据
     * @param book
     * @return
     */
    @PutMapping
    public Boolean update(@RequestBody Book book){
        return bookService.modify(book);
    }

    /**
     * 使用路径参数来传参
     * @PathVariable 从路径中获取的变量 传给形参
     * @param id
     * @return
     */
    @DeleteMapping("{id}")
    public Boolean delete(@PathVariable Integer id){
        return bookService.delete(id);
    }

    @GetMapping("{id}")
    public Book getById(@PathVariable Integer id){
        return bookService.getById(id);
    }

    /**
     * 几乎所有的查询都是get请求
     * @return
     */
    @GetMapping("{currentPage}/{pageSize}")
    public IPage<Book> getPage(@PathVariable int currentPage,@PathVariable int pageSize){
        return bookService.getPage(currentPage,pageSize);
    }
}

在postman中测试一下:发现从后台得到的数据有的是true,有的是json数据,有的是json数组,不方便前端开发。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因此需要有一个固定的格式:一个flag和一个data的形式,(后面根据情况携带了一个信息,后面再说)
在这里插入图片描述
将这些数据封装成上述类型的对象:

@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(Boolean flag, String msg) {
        this.flag = flag;
        this.msg = msg;
    }

    public R(String msg) {
        this.flag = false;
        this.msg = msg;
    }
}

将控制层的返回值都改成统一的格式R:

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private IBookService bookService;

    /**
     * 查询全部 发送的是get请求
     * @return
     */
    @GetMapping
    public R getAll(){
        //通用工具类提供的方法
        return new R(true,bookService.list());
    }

    /**
     * 新增一个book 发送的是post请求
     * 新增:异步提交发送,通过请求体传json数据过来。传json数据就不能跳转页面了
     * @param book
     * @return
     */
    @PostMapping
    public R save(@RequestBody Book book){
        boolean flag=bookService.saveBook(book);
        return new R(flag,flag?"添加成功^_^":"添加失败-_-!");
    }

    /**
     * 修改book  发送put
     * 修改:传json数据
     * @param book
     * @return
     */
    @PutMapping
    public R update(@RequestBody Book book){
        return new R(bookService.modify(book));
    }

    /**
     * 使用路径参数来传参
     * @PathVariable 从路径中获取的变量 传给形参
     * @param id
     * @return
     */
    @DeleteMapping("{id}")
    public R delete(@PathVariable Integer id){
        return new R(bookService.delete(id));
    }

    @GetMapping("{id}")
    public R getById(@PathVariable Integer id){
        return new R(true,bookService.getById(id));
    }

    /**
     * 几乎所有的查询都是get请求
     * 对查询结果进行校验,如果当前页码值大于最大页码值,使用最大页码值作为当前页码值重新查询
     * 基于业务需求维护删除功能
     * @return
     */
//    @GetMapping("{currentPage}/{pageSize}")
//    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize){
//        IPage<Book> page=bookService.getPage(currentPage,pageSize);
//        //如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
//        if(currentPage>page.getPages()){
//            //不使用当前页查了,使用最大的页查
//            page=bookService.getPage((int)page.getPages(),pageSize);
//        }
//        return new R(true,page);
//    }

    /**
     * book里面有从浏览器发送的信息
     * 请求参数和形参同名,自动注入。或者直接模型类中的属性和请求参数相同,也会直接注入到模型类中(参数绑定 自动注入)
     * @param currentPage
     * @param pageSize
     * @param book
     * @return
     * 把条件查询当成分页的一部分值
     */
    @GetMapping("{currentPage}/{pageSize}")
    public R getPage(@PathVariable int currentPage,@PathVariable int pageSize,Book book){
        IPage<Book> page=bookService.getPage(currentPage,pageSize,book);
        //如果当前页码值大于了总页码值,那么重新执行查询操作,使用最大页码值作为当前页码值
        if(currentPage>page.getPages()){
            //不使用当前页查了,使用最大的页查
            page=bookService.getPage((int)page.getPages(),pageSize,book);
        }
        return new R(true,page);
    }
}

在postman中测试一下:可以看到数据格式已经变了
在这里插入图片描述
扩展:前端发给后端的数据格式、协议就是json
后端到这里就结束了~~

五、前后端调用

单体项目中页面放置在resources/static目录下;
created钩子函数用于初始化页面时发起调用;
页面使用axios发送异步请求,获取数据后确认前后端是否联通。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/18785.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

行为型模式-解释器模式

解释器模式 概述 如上图&#xff0c;设计一个软件用来进行加减计算。我们第一想法就是使用工具类&#xff0c;提供对应的加法和减法的工具方法。 //用于两个整数相加 public static int add(int a,int b){return a b; }//用于两个整数相加 public static int add(int a,int …

使用护眼灯台灯哪个牌子好用来保护眼睛?真正做到护眼台灯品牌

现在的家长很多人觉得家里已经有灯光了&#xff0c;没必要在买台灯。但事实上台灯有很多优点&#xff0c;尤其对于小孩子来说&#xff1a;1.提供更好的光线:台灯能够提供更加明亮的光线&#xff0c;有助于保护眼睛健康。2.提高工作效率:台灯光线舒适可提高工作效率或学习效率。…

CPU 架构(x86/ARM)简介

CPU 架构通过指令集的方式一般可分为 复杂指令集&#xff08;CISC&#xff09; 和 精简指令集&#xff08;RISC&#xff09; 两类&#xff0c;CISC 主要是 x86 架构&#xff0c;RISC 主要是 ARM 架构&#xff0c;还有 MIPS、RISC-V、PowerPC 等架构。 本文重点介绍 x86 和 ARM…

SpringBoot整合Nacos配置中心和注册中心

一、背景 公司项目中使用的Nacos作为服务的注册中心和配置中心&#xff0c;但是呢公司的这一套Nacos是经过封装了的&#xff0c;而且封装的不是很友好&#xff0c;想着自己搭建一套标注的Nacos配置中心和服务中心 二、Nacos配置中心和注册中心搭建 2.1 依赖引入 <!--注册…

【Linux】shell编程之循环语句

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、循环语句二、for循环语句1.for 语句的结构2.for语句应用示例 三、while 循环语句1.while 循环语句结构2.while语句应用示例 四、until 循环五、跳出循环六、死循…

新品发布全线添员,九号全力奔向“红海”深处?

5月10日&#xff0c;九号公司2023新品发布会声势达到顶峰。此次发布会的看点为九号电动2023产品线的更新&#xff0c;电动家族再添多员大将。 随着人们出行选择的多样化&#xff0c;国内短途出行工具发展迎来井喷期。在传统的电动两轮车市场上&#xff0c;雅迪、爱玛等品牌仍然…

今年这面试难度,我给跪了……

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;又得准备面试了&#xff0c;不知道从何下手&#xff01; 不论是跳槽涨薪&#xff0c;还是学习提升&#xff01;先给自己定一个小目标&#xff0c;然后再朝着目标去努力就完事儿了&#xff01; 为了帮大家节约时间&a…

关于cartographer建立正确关系树的理解

正确的TF关系map----odom----base_link----laser base_link是固定在机器人本体上的坐标系&#xff0c;通常选择飞控 其中map–odom 的链接是由cartographer中lua文件配置完成的 map_frame "map", tracking_frame "base_link", published_frame "b…

MySQL日志

目录 错误日志 查询日志 二进制日志 慢查询日志 redo log 和 undo log &#xff08;事务日志&#xff09; redo log&#xff1a; undo log&#xff1a; mysql> show variables like log_%; 返回所有以"log_"开头的系统变量和它们的值&#xff0c;这些变量控…

研读Rust圣经解析——Rust learn-12(智能指针)

研读Rust圣经解析——Rust learn-12&#xff08;智能指针&#xff09; 智能指针智能指针选择Box<T>使用场景创建Box使用Box在堆上存储递归类型数据解决 通过 Deref trait 将智能指针当作常规引用处理追踪指针的值创建自定义的智能指针&#xff08;*&#xff09; Deref隐式…

开源智慧家居

与家居行业、服务行业等伙伴协同合作&#xff0c;努力创造社会价值&#xff0c;提升行业整体服务 水平&#xff0c;树立家居服务业统一售后标准&#xff0c;构建品质、高效、有温度的居家生活服务新生态。 为企业商家和个人客户提供家居配送、搬运、安装、维修、保养等服务。 …

IPC:匿名管道和命名管道

一 管道初级测试 写两个小程序&#xff0c;一个负责向管道发数据&#xff0c;一个从管道接收数据&#xff1b; pipe.cpp #include <iostream> using namespace std;int main() {cout << "hello world" << endl;return 0; } pipe2.cpp #inclu…

Java线程池及其实现原理

线程池概述 线程池&#xff08;Thread Pool&#xff09;是一种基于池化思想管理线程的工具&#xff0c;经常出现在多线程服务器中&#xff0c;如MySQL。 线程过多会带来额外的开销&#xff0c;其中包括创建销毁线程的开销、调度线程的开销等等&#xff0c;同时也降低了计算机…

【设计模式】单例模式(懒汉和饿汉模式详解)

目录 1.设计模式是什么&#xff1f; 2.单例模式 1.概念&#xff1a; 2.如何设计一个单例 1.口头约定&#xff08;不靠谱&#xff09; 2.使用编程语言的特性来处理 3.使用"饿汉模式"设计单例 1.详细步骤 2.完整代码 4.使用"饿汉模式"设计单例 1.详…

为什么我在大厂待了三个月就选择离开?我聊聊应届生该选择大厂还是小公司

我在互联网大厂只待了3个月就离开了&#xff0c;主要原因不是大厂的福利或者薪资不够好&#xff0c;只是因为我发现在大厂里每天都有开不完的会&#xff0c;忙碌到没有自己的生活。当时我每天10点上班&#xff0c;晚上要工作到11甚至是12点&#xff0c;甚至半夜两三点都接到过工…

Flowable+React+bpmn-js实现工作流

由于新东家使用的是React&#xff0c;不是Vue&#xff0c;而自己一直想做一个关于工作流的应用出来&#xff0c;断断续续&#xff0c;花了几个月的时间&#xff0c;开发了工作流的功能&#xff0c;后面会继续完善。 技术栈 前端 前端是基于React开发的&#xff0c;使用了ant…

OpenCV 直方图统计函数 cv::calcHist算是彻底弄明白了

参数说明 void calcHist( const Mat* images, int nimages,const int* channels, InputArray mask,OutputArray hist, int dims, const int* histSize,const float** ranges, bool uniform true, bool accumulate false );images 图像数组。每个图像的大小要一致&#xff0c…

最强算法视频公开课!(内容硬核,完全免费!

和录友们汇报一下&#xff0c;代码随想录算法公开课已经更新完毕了。 由我亲自录制了140期算法视频&#xff0c;覆盖了 《代码随想录》纸质版上全部题目的讲解。 视频全部免费开放在B站&#xff1a;代码随想录 目录就在视频播放的右边&#xff0c;完全按照代码随想录的顺序讲…

鸿蒙Hi3861学习七-Huawei LiteOS-M(信号量)

一、简介 信号量&#xff08;Semaphore&#xff09;是一种实现任务间通信的机制&#xff0c;实现任务之间同步或临界资源的互斥访问。常用于协助一组相互竞争的任务来访问临界资源。 在多任务系统中&#xff0c;各任务之间需要同步或互斥实现临界资源的保护&#xff0c;信号量功…

面对AI“龙卷风”破坏力 白宫“软着陆”欧盟“硬防御”

ChatGPT的风靡与风险将OpenAI的CEO山姆奥特曼&#xff08;Sam Altman&#xff09;送进白宫&#xff0c;他被蹲守在美国总统府邸的记者们围追&#xff0c;面对5月4日白宫发起的AI风险治理会议&#xff0c;奥特曼很官方地给出“重要也很及时”的回应&#xff0c;自信的反复强调“…