创建springboot工程,使用Mybatis框架

目录

如何创建SpringBoot工程?

如何使用MyBatis框架?

基于Mybatis框架且前端同步发出请求

例子:使用Mybatis框架且同步发送请求,采用前后端不分离形式,对产品进行插入,查询,删除,修改的操作

基于Mybatis框架且前端异步(axios框架)发送请求

例子:使用Mybatis框架且异步发送请求,采用前后端分离形式,对用户进行注册登录

基于Mybatis框架weibo上传文件流程(使用ElementUI组件)

Mybatis框架在XML配置文件中书写SQL语句的用法(常用)

POJO :指简单的Java对象 ,是实体类Entity和值对象VO,还有DTO数据传输对象的统称


如何创建SpringBoot工程?

1. 创建Spring Initalizer  工程,  修改URL

   推荐修改为 https://start.springboot.io  如果不能用则可以修改为https://start.aliyun.com 

2. 在第二个页面中勾选Web->Spring Web 然后点击finish 

3. 创建完工程后检查Build里面是否出现了绿色的对勾

如何使用MyBatis框架?

创建boot工程打3个勾:SpringWeb,MybatisFramework,MySQLDriver

如果工程中包含了Mybatis框架,启动工程时需要用到 application.properties 里面配置的连接数据库的信息。

基于Mybatis框架且前端同步发出请求

同步: 指单线程依次做几件事

同步请求(页面整体刷新): 指客户端只有一个主线程,线程负责页面渲染和监听操作。如果需要主线程发出请求时,会停止页面渲染(清空页面) 只负责发请求。当服务器响应了数据之后,主线程再次恢复渲染的职责,把服务器响应的数据显示到页面中,这个过程是将页面内容进行了整体的改变,称为整体刷新。同步请求只能实现页面的整体刷新无法实现局部刷新。

同步请求方式:地址栏发请求、表单发请求、超链接发请求。

例子:使用Mybatis框架且同步发送请求,采用前后端不分离形式,对产品进行插入,查询,删除,修改的操作

准备工作:创建bbsdb数据库,在product表中创建id,title,price,num字段

在application.properties中配置连接数据库信息
spring.datasource.url=jdbc:mysql://localhost:3306/bbsdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root

1:创建3个前端页面index.html,insert.html,update.html,部分代码

index.html
<h1>Mybatis版本商品管理系统</h1>
<a href="/insert.html">添加商品</a>
<a href="/select">商品列表</a>
<a href="/update.html">修改商品</a>
insert.html
<h1>添加商品页面</h1>
<form action="/insert">
  <input type="text" name="title" placeholder="商品标题">
  <input type="text" name="price" placeholder="商品价格">
  <input type="text" name="num" placeholder="商品销量">
  <input type="submit" value="添加">
</form>
update.html
<h1>修改商品页面</h1>
<form action="/update">
  <input type="text" name="id" placeholder="请输入修改商品的id">
  <input type="text" name="title" placeholder="标题">
  <input type="text" name="price" placeholder="价格">
  <input type="text" name="num" placeholder="库存">
  <input type="submit" value="修改商品">
</form>

2:创建entity.Product类,属性名要和数据库中的字段一致,添加get,set,toString方法

3:创建controller.productController类,将前端传入的信息封装到实体类Product中

@RestController:

使用RestController 相当于在每一个方法的上面都添加@ResponseBody注解

@Autowired:

自动装配,此框架添加之后,Mybatis和Spring框架会自动生成ProductMapper的实现类,并且实例化该实现类(实现类里面会实现ProductMapper中的抽象方法,实现的方法里面写的就是JDBC代码),并且把实例化好的对象赋值给了mapper变量(ProductMapper mapper

package cn.tedu.boot03.controller;

import cn.tedu.boot03.entity.Product;
import cn.tedu.boot03.mapper.ProductMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

//使用RestController 相当于在每一个方法的上面都添加了@ResponseBody注解
@RestController
public class ProductController {
/*自动装配 此框架添加之后,Mybatis和Spring框架会生成
  ProductMapper的实现类,并且实例化该实现类(实现类里面会实现ProductMapper中的
  抽象方法,实现的方法里面写的就是JDBC代码),并且把实例化好的对象赋值给了mapper变量*/
    @Autowired
    ProductMapper mapper;
    @RequestMapping("/insert")
    public String insert(Product product){
        System.out.println("product = " + product);
        mapper.insert(product);
        return "添加完成!<a href='/'>返回首页</a>";
    }

    @RequestMapping("/select")
    public String select(){
        List<Product> list = mapper.select();
        String html = "<table border='1'>";
        html+="<caption>商品列表</caption>";
        html+="<tr><th>id</th><th>商品标题</th><th>价格</th><th>库存</th><th>操作</th></tr>";
        for (Product p: list) {
            html+="<tr>";
            html+="<td>"+p.getId()+"</td>";
            html+="<td>"+p.getTitle()+"</td>";
            html+="<td>"+p.getPrice()+"</td>";
            html+="<td>"+p.getNum()+"</td>";
            html+="<td><a href='/delete?id="+p.getId()+"'>删除</a></td>";
            html+="</tr>";
        }
        html+="</table>";
        return html;
    }

    @RequestMapping("/delete")
    public String delete(int id){
        mapper.deleteById(id);
        return "删除完成!<a href='/select'>返回列表页面</a>";
    }
    @RequestMapping("/update")
    public String update(Product product){
        System.out.println("product = " + product);
        mapper.update(product);
        return "修改完成!<a href='/select'>返回列表页面</a>";
    }
}

4:创建mapper.ProductMapper接口

在Mapper接口中写实体类和数据库之间的对应关系,Mybatis框架会自动通过关系生成JDBC代码

@Mapper注释:

是由Mybatis框架中定义的一个扫描数据层接口的注解,注解起到一个描述作用,用于告诉Spring框架此接口的实现类Mybatis负责创建,并将其实现类对象存储到Spring容器中。

package cn.tedu.boot03.mapper;

import cn.tedu.boot03.entity.Product;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface ProductMapper {
//在Mapper接口中书写实体类和数据库中表之间的对应关系
//Mybatis框架会通过此关系生成JDBC代码.
//#{xxx} 代表从参数列表中找同名的参数,
// 如果找不到则调用参数列表中对象的getXXX方法获取数据
    @Insert("insert into product values(null,#{title},#{price},#{num})")
    void insert(Product product);

//查询到的数据会封装到对象里面并且把对象装进list集合,把集合作为返回值
    @Select("select id,title,price,num from product")
    List<Product> select();

    @Delete("delete from product where id=#{id}")
    void deleteById(int id);

    @Update("update product set title=#{title},price=#{price}" +
            ",num=#{num} where id=#{id}")
    void update(Product product);
}

基于Mybatis框架且前端异步(axios框架)发送请求

异步:多线程同时做几件事

异步请求(局部刷新页面,常用)指客户端的主线程负责页面渲染和监听操作,由子线程发出请求获取数据,获取到数据后将数据展示到原有页面,这种就叫做页面的局部刷新,只有通过异步请求才可以实现。

客户端如何发出异步请求:通过Axios框架发出异步请求

Axios:是一个js框架文件,在html页面中引入此文件即可。

<https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js>

发送请求时:GET和POST区别

GET:请求参数写在请求地址的后面,由于参数在地址栏中可见所以不能传递带有敏感信息的参数,,参数大小有限制只能传递几k的数据。

  应用场景: 一般的查询请求都是用get,删除数据一般也使用get。

POST:请求参数在请求体里面,在请求体里面的参数是不可见的所以可以传递带有敏感信息的参数,,请求参数的大小也没有限制 。

  应用场景: 有敏感信息的请求, 上传请求, 参数较多时使用

在前端中,如果发送请求方式是post请求,并且传递过来的是js自定义对象接收参数时

需要在Controller中,要添加@RequestBody注解,如果不加注解,接收参数是null

例子:使用Mybatis框架且异步发送请求,采用前后端分离形式,对用户进行注册登录

准备工作:创建user表字段是username,password,nickname

在application.properties中配置连接数据库信息
spring.datasource.url=jdbc:mysql://localhost:3306/bbsdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root

1:创建3个前端页面index.html,reg.html,login.html

index.html
<h1>工程首页异步测试</h1>
<a href="/reg.html">注册</a>
<a href="/login.html">登录</a>

red.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>注册页面</h1>
<div>
  <input type="text" placeholder="用户名" v-model="user.username"><br>
  <input type="text" placeholder="密码" v-model="user.password"><br>
  <input type="text" placeholder="昵称" v-model="user.nickname"><br>
  <input type="button" value="注册" @click="reg()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
    let v = new Vue({
        el:"body>div",
        data:{
          user:{
            username:"",
            password:"",
            nickname:""
          }
        },
        methods:{
          reg(){
            //异步发送请求
            axios.post("/reg",v.user).then(function (response) {
              if (response.data==1){
                  alert("注册成功!")
                  location.href = "/"; //回到首页
              }else{
                  alert("用户名已存在!");
              }
            })
          }
        }
    })
</script>
</body>
</html>

login.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
  <h1>登录页面</h1>
  <input type="text" placeholder="用户名" v-model="user.username">
  <input type="password" placeholder="密码" v-model="user.password">
    <input type="button" value="登录" @click="login()">
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<script>
    let v = new Vue({
        el:"body>div",
        data:{
            user:{
                username:"",
                password:""
            }
        },
        methods:{
            login(){
    //发出异步请求 服务器返回1成功,2用户名不存在,3密码错误
                axios.post("/login",v.user).then(function (response) {
                    if (response.data==1){
                        alert("登录成功!");
                        location.href="/";
                    }else if(response.data==2){
                        alert("用户名不存在!");
                    }else{
                        alert("密码错误!");
                    }
                })
            }
        }
    })
</script>
</body>
</html>

2:创建controller.UserController类,根据前端发送的请求,处理注册登录业务,

package cn.tedu.boot05.controller;

import cn.tedu.boot05.entity.User;
import cn.tedu.boot05.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    UserMapper mapper;
    @RequestMapping("/reg")
//在前端中,如果发送请求方式是post请求,并且传递过来的是js自定义对象接收参数时
//需要在Controller中,要添加@RequestBody注解,如果不加注解,接收参数是null
    public int reg(@RequestBody User user){
        User u = mapper.selectByUsername(user.getUsername());
        if (u!=null){
            return 2;//用户名已存在
        }
        mapper.insert(user);
        return 1;//注册成功
    }

    @RequestMapping("/login")
    public int login(@RequestBody User user){
        User u = mapper.selectByUsername(user.getUsername());
        if (u!=null){
            if (user.getPassword().equals(u.getPassword())){
                return 1;//登录成功
            }
            return 3;//密码错误
        }
        return 2;//用户名不存在
    }
}

3:创建entity.User实体类,属性名和数据库字段一致

4:创建mapper.UserMapper接口,从数据库中通过用户名查询密码

package cn.tedu.boot05.mapper;

import cn.tedu.boot05.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {
    @Select("select password from user where username=#{username}")
    User selectByUsername(String username);
    @Insert("insert into user values(null,#{username},#{password},#{nickname})")
    void insert(User user);
}

基于Mybatis框架weibo上传文件流程(使用ElementUI组件)

准备工作:创建weibo表,字段为id,content,url,created

1. 创建新工程boot071

2. 在application.properties配置文件中添加5行内容,其中3行数据库相关, 2行文件上传相关

spring.datasource.url=jdbc:mysql://localhost:3306/bbsdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root
#客户端只能访问 static文件下的图片
#
所以要设置一个静态资源文件夹,classpath:static指原来static文件夹
spring.web.resources.static-locations=file:d:/files,classpath:static
#设置上传文件大小,默认为1MB
spring.servlet.multipart.max-file-size=10MB

3. 创建index.html首页

添加上传页面超链接,请求地址 /upload.html,部分代码

<h1>文件上传测试</h1>
<a href="/upload.html">上传页面</a>

4. 创建upload.html页面

从elementUI文档中找到 Upload上传组件中的照片墙,,然后把3部分代码复制到自己的页面中,给el-upload添加 action设置 请求路径为/upload,添加name为pic,添加limit设置上传文件的数量。

属性:

action:设置上传地址

action="/upload"

name:设置上传参数名称

name="pic"

limit:上传图片的数量
limit="3"

el-upload组件里面添加     :on-success="handleSuccess"     并且实现handleSuccess方法。这样上传完成后,就会响应此方法。此方法中的response参数就是服务器响应的数据,把响应的图片路径显示到页面中。

文件传输成功后调用的方法:

:on-success="handleSuccess"

handleSuccess(response,file,fileList){
    //response代表服务器上传成功时响应的数据,此处的response和Axios框架
    //发出请求得到的response不同,类似于response.data
    //file代表当前上传成功的文件
    //fileList代表上传成功的所有文件(是一个数组)
    v.weibo.url = response;
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <!-- import CSS -->
    <link rel="stylesheet" href="https://cdn.staticfile.org/element-ui/2.15.9/theme-chalk/index.css">
</head>
<body>
<div id="app">
    <input type="text" placeholder="说点儿什么" v-model="weibo.content">
    <!--action设置上传地址
        name设置上传参数的名称
        limit设置上传图片数量
    -->
    <el-upload
            action="/upload"
            name="pic"
            limit="3"
            list-type="picture-card"
            :on-success="handleSuccess"
            :on-preview="handlePictureCardPreview"
            :on-remove="handleRemove">
        <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
        <img width="100%" :src="dialogImageUrl" alt="">
    </el-dialog>
    <hr>
    <input type="button" value="发布微博" @click="insert()">

</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>

<!-- import Vue before Element -->
<script src="https://cdn.staticfile.org/vue/2.6.14/vue.min.js"></script>
<!-- import JavaScript -->
<script src="https://cdn.staticfile.org/element-ui/2.15.9/index.min.js"></script>
<script>
   let v = new Vue({
        el: '#app',
        data: function() {
            return {
                dialogImageUrl: '',
                dialogVisible: false,
                weibo:{
                    content:"",
                    url:""
                }
            }
        },
       methods:{
           handleRemove(file, fileList) {
               console.log(file, fileList);
               //当删除页面中图片时触发的方法
               //发请求删除服务器中的图片
               //file代表当前删除的图片文件
               // file.response代表上传该文件成功时服务器响应的内容(当前删除图片路径)
               axios.get("/remove?url="+file.response).then(function () {
                   console.log("删除服务器图片完成!")
               })
           },
           handlePictureCardPreview(file) {
               this.dialogImageUrl = file.url;
               this.dialogVisible = true;
           },
           handleSuccess(response,file,fileList){
               //response代表服务器上传成功时响应的数据,此处的response和Axios框架
               //发出请求得到的response不同,类似于response.data
               //file代表当前上传成功的文件
               //fileList代表上传成功的所有文件(是一个数组)
               v.weibo.url = response;
           },
           insert(){
               if (v.weibo.url==""){
                   alert("请选择上传的图片!");
                   return;
               }
               axios.post("/insert",v.weibo).then(function (response) {
                   alert("发布完成!");
                   location.href="/";//回到首页
               })
           }
       }
    })
</script>
</html>

5. 创建controller.UploadController

添加 upload方法处理/upload请求,在方法中得到唯一文件名,然后把文件保存到指定的文件夹中, 把/文件名,响应给客户端。

package cn.tedu.boot07.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.UUID;

@RestController
public class UploadController {
    @RequestMapping("/upload")
    public String upload(MultipartFile pic) throws IOException {
        //pic代表客户端上传的文件参数
        System.out.println("pic = " + pic);
        //得到图片的原始文件名   a.jpg
        String fileName = pic.getOriginalFilename();
        System.out.println("原始文件名:"+fileName);
        //得到原始文件名的后缀
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        //得到唯一文件名 UUID.randomUUID()获取唯一标识符
        fileName = UUID.randomUUID()+suffix;
        System.out.println("唯一文件名:"+fileName);
        //准备保存图片的路径
        String dirPath = "d:/files";
        File dirFile = new File(dirPath);
        //判断如果不存在 则创建文件夹
        if (!dirFile.exists()){
            dirFile.mkdirs();//创建文件夹
        }
        //得到文件的完整路径   d:/files/xxxx.jpg
        String filePath = dirPath+"/"+fileName;
        //把图片保存到上面的路径中  异常抛出
        pic.transferTo(new File(filePath));

        //把图片的url路径响应给客户端      /文件名
        return "/"+fileName;
    }
    @RequestMapping("/remove")
    public void remove(String url){
        //删除磁盘上的文件
        new File("d:/files"+url).delete();
    }
}

6:创建controller.weiboController类

package cn.tedu.boot07.controller;

import cn.tedu.boot07.entity.Weibo;
import cn.tedu.boot07.mapper.WeiboMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.File;
import java.util.Date;
import java.util.List;

@RestController
public class WeiboController {
    @Autowired
    WeiboMapper mapper;
    @RequestMapping("/insert")
    public void insert(@RequestBody Weibo weibo){
        System.out.println("weibo = " + weibo);
        //new Date()得到当前系统时间
        weibo.setCreated(new Date());
       /* create table weibo(id int primary key auto_increment,
         content varchar(100),url varchar(200),created timestamp);
         */
        mapper.insert(weibo);
    }
    @RequestMapping("/select")
    public List<Weibo> select(){
        return mapper.select();
    }
    @RequestMapping("/delete")
    public void delete(int id){
       //通过微博id查询得到图片的路径
        String url = mapper.selectUrlById(id);
        //   d:/files/xxx.jpg
        //删除指定位置的文件
        new File("d:/files"+url).delete();

        mapper.deleteById(id);
    }
}

7:创建entity.Weibo实体类

文件上传设置时间显示的格式:

通过@JsonFormat注解:设置显示时间的格式和时区

package cn.tedu.boot07.entity;

import com.fasterxml.jackson.annotation.JsonFormat;

import java.util.Date;

public class Weibo {
    private Integer id;
    private String content;
    private String url;   //微博图片的路径
    //通过JsonFormat设置显示的时间格式
    // 2022年10月12号 15时23分22秒    2022-10-12 15:23:22
    ///yyyy年MM月dd号 HH时mm分ss秒    yyyy-MM-dd HH:mm:ss
    @JsonFormat(pattern = "yyyy年MM月dd号 HH时mm分ss秒",timezone = "GMT+8")
    private Date created; //发布微博时间

    @Override
    public String toString() {
        return "Weibo{" +
                "id=" + id +
                ", content='" + content + '\'' +
                ", url='" + url + '\'' +
                ", created=" + created +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }
}

8:创建mapper.Weibo接口

package cn.tedu.boot07.mapper;

import cn.tedu.boot07.entity.Weibo;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface WeiboMapper {
    @Insert("insert into weibo " +
            "values(null,#{content}," +
            "#{url},#{created})")
    void insert(Weibo weibo);
    @Select("select id,content,url,created from weibo")
    List<Weibo> select();

    @Delete("delete from weibo where id=#{id}")
    void deleteById(int id);

    @Select("select url from weibo where id=#{id}")
    String selectUrlById(int id);
}

之前SQL语句是写在Mapper接口中的注解里面,有以下缺点:

  • 如果SQL语句太长 存在字符串折行拼接问题 不够直观
  • 一些关联查询的操作不易复用

Mybatis框架在XML配置文件中书写SQL语句的用法(常用)

优点:对于DBA(数据库管理员)更友好,不需要去Java代码中改SQL语句而是从配置文件中进行修改

Mybatis框架使用XML配置文件的步骤:

例子一、对产品进行插入,查询,修改,批量插入,批量删除,动态插入,动态修改

准备工作:创建product表,字段为id,tittle,price,num

1:创建Mybatis配置类(有@Configuration注解的类为配置类),通过@MapperScan注解取代每个Mapper接口类中的@Mapper注解

package cn.tedu.boot08.config;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;

//告诉编译器此工程的所有Mapper接口都在这个包路径里面
@Configuration
@MapperScan("cn.tedu.boot08.mapper")
public class MyBatisConfig {
}

2:创建实体类 entity.Product,和数据库中的字段一致

package cn.tedu.boot08.entity;

public class Product {
    private Integer id;
    private String title;
    private Double price;
    private Integer num;

    public Product() {
    }

    public Product(Integer id, String title, Double price, Integer num) {
        this.id = id;
        this.title = title;
        this.price = price;
        this.num = num;
    }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", price=" + price +
                ", num=" + num +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }
}

3:创建mapper.ProductMapper接口

在配置类中使用了@MapperScan注解,所以不需要写@Mapper注解

@Insert等注解也不写,sql语句写在xml配置文件中单独配置

package cn.tedu.boot08.mapper;

import cn.tedu.boot08.entity.Product;

import java.util.List;

//此时使用了MapperScan注解 则不需要再写@Mapper注解
public interface ProductMapper {
    //此处不再写@Insert等注解,SQL语句写在xml配置文件中
    void insert(Product product);
    //删除
    void deleteById(int id);
    //修改
    void update(Product product);
    //查询所有
    List<Product> select();
    //通过id查询单个
    Product selectById(int id);
    //查询数量
    int count();

    // 1,3,5,6,7    delete from product where id in(1,3,5)
    //批量删除 int返回值 返回的是生效的行数(删除了多少条)
    int deleteByIds1(List<Integer> ids);    //集合
    int deleteByIds2(Integer[] ids);       //数组
    int deleteByIds3(Integer... ids);

    //insert into product values(null,'',100,30),(null,'',100,30),(null,'',100,30)
    int insertProducts(List<Product> list);

    //动态插入数据,自动识别对象属性是否有值
    int dynamicInsert(Product product);


    void dynamicUpdate(Product p);
}

4:创建ProductMapper.xml文件:

在resources目录下创建mappers文件夹,网上下载Mybatis Mapper映射文件Mapper.xml,将名字改为ProductMapper.xml,专门用来写sql语句。

1:配置当前配置文件和哪个接口有关系:

        namespace="cn.tesu.boot08.mapper.ProductMapper":

2:id和接口中的方法名相同:

        id="insert"

3:查询时通过resultType属性,设置返回结果类型

4:批量使用:

        foreach循环遍历标签

        属性:collection:的值如果是List集合则写list,如果不是List集合则写array  

                   item:代表遍历的集合中变量

                   separator:代表分隔符

5:动态插入数据时使用:

        trim标签

        属性:prefix:前缀

                   suffix:后缀

                   suffixOverrides去掉多余的逗号 ,

6:动态修改数据使用:

        set标签:会自动去掉后面的逗号

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.boot08.mapper.ProductMapper">
<!--插入数据-->
    <insert id="insert">
        INSERT INTO product VALUES (
                                    NULL,#{title},#{price},#{num}
                                   )
    </insert>

<!--通过id删除数据-->
    <delete id="deleteById">
        DELETE FROM product WHERE id=#{id}
    </delete>

<!--通过id修改数据-->
    <update id="update">
        UPDATE product SET
                           title=#{title},price=#{price},num=#{num}
                        WHERE id=#{id}
    </update>

<!--查询所有数据-->
    <select id="select" resultType="cn.tedu.boot08.entity.Product">
        SELECT id,title,price,num FROM product
    </select>

<!--通过id查询数据-->
    <select id="selectById" resultType="cn.tedu.boot08.entity.Product">
        SELECT id,title,price,num FROM product WHERE id=#{id}
    </select>

<!--查询数量-->
    <select id="count" resultType="int">
        SELECT count(*) FROM product
    </select>

<!--批量删除,3种方法-->
    <!--foreach循环遍历标签 collection的值如果是List集合则写list
    如果不是List集合则写array  item代表遍历的集合中变量, separator代表分隔符
    -->
    <delete id="deleteByIds1">
        DELETE FROM product
        WHERE id in(
            <foreach collection="list" item="id" separator=",">
                #{id}
            </foreach>
            )
    </delete>
    <delete id="deleteByIds2">
        DELETE FROM product
        WHERE id in(
        <foreach collection="array" item="id" separator=",">
            #{id}
        </foreach>
        )
    </delete>
    <delete id="deleteByIds3">
        DELETE FROM product
        WHERE id in(
        <foreach collection="array" item="id" separator=",">
            #{id}
        </foreach>
        )
    </delete>

<!--批量插入数据-->
    <insert id="insertProducts">
        INSERT INTO product
        VALUES
        <foreach collection="list" item="p" separator=",">
            (
             NULL ,#{p.title},#{p.price},#{p.num}
            )
        </foreach>
    </insert>

<!--动态插入数据 suffixOverrides去掉多余的,-->
<!--自动识别对象属性是否有值,用if判断-->
    <insert id="dynamicInsert">
        INSERT INTO product
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="title!=null">title,</if>
            <if test="price!=null">price,</if>
            <if test="num!=null">num</if>
        </trim>
        VALUES
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="title!=null">#{title},</if>
            <if test="price!=null">#{price},</if>
            <if test="num!=null">#{num}</if>
        </trim>
    </insert>

<!--动态修改数据 set标签会自动去掉后面的逗号-->
    <update id="dynamicUpdate">
        UPDATE product
        <set>
            <if test="title!=null">title=#{title},</if>
            <if test="price!=null">price=#{price},</if>
            <if test="num!=null">num=#{num}</if>
        </set>
        WHERE id=#{id}
    </update>

</mapper>

5:在application.properties中,配置Mybatis书写sql语句的xml文件位置

spring.datasource.url=jdbc:mysql://localhost:3306/bbsdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root

spring.web.resources.static-locations=file:d:/files,classpath:static

spring.servlet.multipart.max-file-size=10MB

#在application.properties中,配置Mybatis书写sql语句的xml文件位置
mybatis.mapper-locations=classpath:mappers/*xml

6:测试内容放在test中,Boot08ApplicationTests用来测试数据是否操作成功

package cn.tedu.boot08;

import cn.tedu.boot08.entity.MyProduct;
import cn.tedu.boot08.entity.Product;
import cn.tedu.boot08.mapper.MyProductMapper;
import cn.tedu.boot08.mapper.ProductMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.ArrayList;

@SpringBootTest
class Boot08ApplicationTests {
    @Autowired(required = false)
    ProductMapper mapper;
    @Test
    void contextLoads() {
        Product p = new Product();
        p.setTitle("xml标题");
        p.setPrice(111.0);
        p.setNum(222);
        mapper.insert(p);
    }

    @Test
    void t1(){
        mapper.deleteById(1);
    }
    @Test
    void t2(){
        Product p = new Product();
        p.setId(6);
        p.setTitle("麦当劳");
        p.setPrice(10.0);
        p.setNum(50);
        mapper.update(p);
    }
    @Test
    void t3(){
        System.out.println(mapper.selectById(6));
        System.out.println(mapper.select());
    }
    @Test
    void t4(){
        System.out.println(mapper.count());
    }

    @Test
    void t5(){
//        ArrayList<Integer> list = new ArrayList<>();
//        list.add(5);
//        list.add(6);
//        System.out.println(mapper.deleteByIds1(list));


//        Integer[] ids = {7,8};
//        System.out.println(mapper.deleteByIds2(ids));
        System.out.println(mapper.deleteByIds3(9,10));
    }
    @Test
    void t6(){
        Product p1 = new Product(null,"a",1.0,1);
        Product p2 = new Product(null,"b",2.0,2);
        Product p3 = new Product(null,"c",3.0,3);
        ArrayList<Product> list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        System.out.println(mapper.insertProducts(list));
    }

    @Test
    void t7(){
        Product p = new Product();
        p.setTitle("手机");
        mapper.dynamicInsert(p);
    }
    @Test
    void t8(){
        Product p = new Product();
        p.setId(14);
        p.setPrice(100.0);
        mapper.dynamicUpdate(p);
    }
    @Autowired(required = false)
    MyProductMapper myMapper;

    @Test
    void t9(){
        MyProduct mp = new MyProduct();
        mp.setTitle("豆浆");
        mp.setSaleCount(5);
        mp.setViewCount(1000);
        myMapper.insert(mp);
    }
    @Test
    void t10(){
        System.out.println(myMapper.selectById(1));
    }
    @Test
    void t11(){
        System.out.println(myMapper.select());
    }
}

例子二、在查询产品中,当查询字段和属性名不一致时,使用映射查询

实体类entity.MyProduct

package cn.tedu.boot08.entity;

public class MyProduct {
    private Integer id;
    private String title;
    private Integer saleCount;
    private Integer viewCount;

    @Override
    public String toString() {
        return "MyProduct{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", saleCount=" + saleCount +
                ", viewCount=" + viewCount +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Integer getSaleCount() {
        return saleCount;
    }

    public void setSaleCount(Integer saleCount) {
        this.saleCount = saleCount;
    }

    public Integer getViewCount() {
        return viewCount;
    }

    public void setViewCount(Integer viewCount) {
        this.viewCount = viewCount;
    }
}

数据库中的字段是:sale_count,view_Count 

java中使用驼峰命名,命名为以下:

private Integer saleCount;
private Integer viewCount;

所以会产生不对应关系,需要添加手动映射

手动映射:resultMap标签

<resultMap id="起个名字"  type="封装类型">

<result column="sale_count" property="saleCount"></result>

</resultMap>

column="sale_count"是数据库中字段,property="saleCount"是java中的属性名,映射之后就会对应

复用sql语句:sql标签

<!--定义复用的SQL语句-->
    <sql id="query">
        要复用的sql语句
    </sql>

<!--引用复用的sql语句-->
    <include refid="query"></include>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.boot08.mapper.MyProductMapper">
   <insert id="insert">
       INSERT INTO my_product
        VALUES (
                null,#{title},#{saleCount},#{viewCount}
               )
   </insert>

<!--手动映射resultMap-->
<!--column="sale_count"是数据库中字段,property="saleCount"是java中的属性名,映射之后就会对应-->
    <select id="selectById" resultMap="productRM">
<!--引用复用的sql语句-->
        <include refid="query"></include>
        WHERE id=#{id}
    </select>
    <resultMap id="productRM" type="cn.tedu.boot08.entity.MyProduct">
        <result column="sale_count" property="saleCount"></result>
        <result column="view_count" property="viewCount"></result>
    </resultMap>

    <select id="select" resultMap="productRM">
        <include refid="query"></include>
    </select>
    <!--定义复用的SQL语句-->
    <sql id="query">
        SELECT id,title,sale_count,view_count FROM my_product
    </sql>
</mapper>

POJO :指简单的Java对象 ,是实体类Entity和值对象VO,还有DTO数据传输对象的统称

Entity实体类(和数据库中表字段一致的属性):通常和对应的表字段的数量是一致的。

DTO数据传输对象(前端请求的参数的属性):当客户端给服务器传递参数时,参数的数量可能比实体类中的数量要少。比如实体类中有10个参数,但是客户端只传递过来的3个参数,此时通过DTO接收传递过来的参数,如果使用实体类接收也可以但是会存在很多的null值,使用DTO好处是只要发现null值就能判断出传输出错了。

VO值对象(从数据库中查找出来的属性):从数据库中的某个表查询数据,有多种场景,有的需要查全部,而有的查询只需要查一部分数据。如果只查一部分数据查询回来的数据直接用Entity接收封装的话,则Entity中会存在大量的null值, 这些null值传输给客户端也会占用流量,浪费资源,使用VO则可以解决此问题。

例子一、使用Pojo,关联查询:

准备两张表:

create table team(id int primary key auto_increment,name varchar(20),loc varchar(20));

create table player(id int primary key auto_increment,name varchar(20),team_id int);

insert into team values(null,'公牛队','芝加哥'),(null,'火箭队','休斯顿');

insert into player values(null,'乔丹',1),(null,'皮蓬',1),(null,'姚明',2),(null,'麦迪',2);

1:创建实体类(和数据库中表字段一致的属性):entity.Player,entity.Team

package cn.tedu.boot10.pojo.entity;

public class Player {
    private Integer id;
    private String name;
    private Integer teamId;

    @Override
    public String toString() {
        return "Player{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", teamId=" + teamId +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getTeamId() {
        return teamId;
    }

    public void setTeamId(Integer teamId) {
        this.teamId = teamId;
    }
}
package cn.tedu.boot10.pojo.entity;

public class Team {
    private Integer id;
    private String name;
    private String loc;

    @Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", loc='" + loc + '\'' +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }
}

创建VO值对象(从数据库中查找出来的属性):vo.PlayerVo,vo.TeamVo

package cn.tedu.boot10.pojo.vo;

import cn.tedu.boot10.pojo.entity.Team;

public class PlayerVO {
    private Integer id;
    private String name;
//查运动员信息时,还要查询队伍信息
    private Team team;

    @Override
    public String toString() {
        return "PlayerVO{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", team=" + team +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Team getTeam() {
        return team;
    }

    public void setTeam(Team team) {
        this.team = team;
    }
}
package cn.tedu.boot10.pojo.vo;

import cn.tedu.boot10.pojo.entity.Player;

import java.util.List;

public class TeamVO {
    private Integer id;
    private String name;
    private String loc;
//在查询队伍信息时,还要查询队员信息
    private List<Player> playerList;

    @Override
    public String toString() {
        return "TeamVO{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", loc='" + loc + '\'' +
                ", playerList=" + playerList +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }

    public List<Player> getPlayerList() {
        return playerList;
    }

    public void setPlayerList(List<Player> playerList) {
        this.playerList = playerList;
    }
}

创建接口:mapper.PlayMapper,mapper.TeamMapper

通过id查数据

package cn.tedu.boot10.mapper;

import cn.tedu.boot10.pojo.vo.PlayerVO;

public interface PlayerMapper {

    PlayerVO selectById(int id);
}
package cn.tedu.boot10.mapper;

import cn.tedu.boot10.pojo.vo.TeamVO;

public interface TeamMapper {

    TeamVO selectById(int id);
}

创建mappers:PlayerMapper.xml,TeamMapper.xml

关联对象类型时:

在PlayerMapper.xml中,还要查询封装在Team对象中的信息

所以使用了association标签

<association property="team" javaType="cn.tedu.boot10.pojo.entity.Team">
            <id column="tid" property="id"></id>
            <result column="tname" property="name"></result>
            <result column="loc" property="loc"></result>
</association>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.boot10.mapper.PlayerMapper">
    <select id="selectById" resultMap="playerRM">
        SELECT p.id pid,p.name pname,t.id tid,t.name tname,loc
        FROM player p join team t
        ON p.team_id=t.id
        WHERE p.id=#{id}
    </select>
    <resultMap id="playerRM" type="cn.tedu.boot10.pojo.vo.PlayerVO">
<!--id特殊,使用id标签;其他仍用result标签-->
        <id column="pid" property="id"></id>
        <result column="pname" property="name"></result>
        <association property="team" javaType="cn.tedu.boot10.pojo.entity.Team">
            <id column="tid" property="id"></id>
            <result column="tname" property="name"></result>
            <result column="loc" property="loc"></result>
        </association>
    </resultMap>
</mapper>

关联类型对象时:

在TeamMapper.xml中,还要查询封装在集合中的信息

所以使用collection标签,ofType:指定playerList中的类型

 <collection property="playerList"
                    ofType="cn.tedu.boot10.pojo.entity.Player">
            <id column="pid" property="id"></id>
            <result column="pname" property="name"></result>
</collection>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.boot10.mapper.TeamMapper">
    <select id="selectById" resultMap="deptRM">
        SELECT t.id tid,t.name tname,loc,p.id pid,p.name pname
        FROM team t join player p
        ON t.id = p.team_id
        WHERE t.id=#{id}
    </select>
    <resultMap id="deptRM" type="cn.tedu.boot10.pojo.vo.TeamVO">
        <id column="tid" property="id"></id>
        <result column="tname" property="name"></result>
        <result column="loc" property="loc"></result>
        <collection property="playerList"
                    ofType="cn.tedu.boot10.pojo.entity.Player">
            <id column="pid" property="id"></id>
            <result column="pname" property="name"></result>
        </collection>
    </resultMap>
</mapper>


 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot是一个用于简化Spring应用程序开发的框架。它并没有官方实现Mybatis的启动器,但是Mybatis官方自己实现了一个启动器,可以在pom.xml文件中引入依赖来使用。\[1\]为了开发web工程,需要在pom.xml中引入spring-boot-starter-web依赖,这个依赖包含了Spring WebMVC和Tomcat等web开发的特性。\[2\]在使用SpringBoot快速入门时,需要进行以下步骤:添加依赖spring-boot-starter-web和spring-boot-starter-parent,创建控制器Controller和DispatcherServlet前端控制器,然后启动SpringBoot项目。\[3\]在控制器类上使用注解来标识该类是一个业务控制器,比如使用@SpringBootApplication注解来标识启动类,@Controller注解来标识控制器类。\[3\]至于整合SpringBoot、SpringMVC和Mybatis框架,可以通过配置文件和注解来实现。具体的整合方式可以根据项目需求和实际情况进行选择和配置。 #### 引用[.reference_title] - *1* *3* [springboot整合mybatis框架](https://blog.csdn.net/qq_42652006/article/details/126833620)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [springboot整合mybatis,springmvc](https://blog.csdn.net/sunhongbing1024/article/details/83186783)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值