SpringBoot+TKmybatis+mysql实现简单后台管理demo

本文详细介绍了如何使用SpringBoot结合TKmybatis和mysql实现后台管理的简单demo,包括TKmybatis的概念、与mybatis-plus的区别、底层原理以及具体的操作步骤,如实体类配置、Mapper接口定义、DAO实现、Controller控制层的编写和测试。

使用SpringBoot+TKmybatis+mysql实现简单demo(后台管理增删改查)

一、概念

1.TKmybatis 是什么?

TKmybatis 是基于 Mybatis 框架开发的一个工具,通过调用它提供的方法实现对单表的数据操作,不需要写任何 sql 语句,这极大地提高了项目开发效率。

2.TKmybatis 与 mybatis-plus

可参考https://www.codeleading.com/article/98311983977/

3.TKmybatis的底层原理

TKmybatis 的封装依赖一个 @SelectProvider 注解来完成,如果你使用过 @Select 注解,那么 @SelectProvider 与它没有质的区别,只是在定义注解的方式上有所不同, 一个是直接定义 sql, 一个是在外部定义好 sql 直接引用。

增删改查依赖注解:@InsertProvider 注解、@DeleteProvider 注解、@UpdateProvider 注解、@SelectProvider 注解

public interface Mapper {

 @Select("select user_id,user_name from t_user ")
 List<Map<String, String>> getUserInfo();
}
public interface SelectAllMapper<T> {
    @SelectProvider(type = BaseSelectProvider.class,method ="dynamicSQL"
    )
    List<T> selectAll();
}

@SelectProvider 引用的各种 *Provider.class 实现类,就是依赖反射、注解等手段拼接 SQL 语句的过程。

/**
 * 查看全部
 */
public String selectAll(MappedStatement ms) {
    Class<?> entityClass = this.getEntityClass(ms);
    this.setResultType(ms, entityClass);
    StringBuilder sql = new StringBuilder();
    sql.append(SqlHelper.selectAllColumns(entityClass));
    sql.append(SqlHelper.fromTable(entityClass, this.tableName(entityClass)));
    sql.append(SqlHelper.orderByDefault(entityClass));
    return sql.toString();
}

TKmybatis 底层源码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、TKmybatis的使用

springBoot整合tkMybatis实现步骤:

1: 引入依赖
2: 实体类配置注解(@Id @Table)
3: Mapper继承tk的接口
4:启动类定义扫描Mapper接口的路径(@MapperScan)
5:配置文件定义扫描mapper.xml文件的路径(yml 或者 properties文件)
6:调用tk提供的接口和数据库交互

1.Springboot项目中加入tk.mybatis依赖

在pom.xml中引入tk.mybatis的引用:

<!--tk.mybatis依赖-->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>1.2.4</version>
</dependency>

<!--web依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

配置 application.yml:

# 服务端口
server:
  port: 8083

# 数据源配置
spring:
  datasource:
    name: test
    url: jdbc:mysql://localhost:3306/db_user?&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSl=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource

    ## 配置连接池信息
    ## 初始化大小,最小,最大
    initialSize: 5
    minIdle: 5
    maxActive: 30
    ## 配置获取连接等待超时的时间
    maxWait: 60000
    # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    timeBetweenEvictionRunsMillis: 60000
    # 配置一个连接在池中最小生存的时间,单位是毫秒
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxPoolPreparedStatementPerConnectionSize: 20
    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall
    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

    # 超过时间限制是否回收
    removeAbandoned: true
    # 超时时间;单位为秒。180=3分钟
    removeAbandonedTimeout: 180
    # 关闭abanded连接时输出错误日志
    logAbandoned: true

##配置打印sql
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.创建实体类

package com.example.tkmybatisdemo.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.util.Date;

/**
 * 用户实体
 *
 * 其中@Table即数据表表名,@Column即列名,@Id作为主键,需要注意,@Id注解不可有多个,@Transient即冗余字段,不与数据库任何字段对应。
 * 注意多数据源的情况:则@Table注解中可以写成“{数据库名}.{架构名}.{表名}”,如:@Table(name=“db.dbo.tableName”)
 *
 * GenerationType的参数说明:
 *    TABLE:使用一个特定的数据库表格来保存主键。(用的比较少)
 *    SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。(mysql不支持,其实和auto一样)
 *    IDENTITY:主键由数据库自动生成(主要是自动增长型,这个用的比较多)
 *    AUTO:主键由程序控制。(不是自增)
 * @author qzz
 */
@Data
@Table(name="t_user")
public class User {

    /**
     * IDENTITY:主键由数据库自动生成(主要是自动增长型,这个用的比较多)
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

    @Column
    private Integer age;

    @Column
    private String remarks;

    @Column
    private String phone;

    /**
     * 性别 0 男 1 女
     */
    @Column
    private Integer sex;

    /**
     * 状态 0启用 1禁用
     */
    @Column
    private Integer status;

    /**
     * @JsonFormat:由后端传递给前端
     * @DateTimeFormat:由前端传递给后端
     */
    @Column
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    @Column
    private String createUser;

    @Column
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

    @Column
    private String updateUser;



}


在实体类中常用注解和说明:
@Table:描述数据表信息,主要属性有name(表名)、schema、catalog、uniqueConstraints等;

@Id:指定表主键字段,无属性值。作为主键,需要注意,@Id注解不可有多个

@Column:描述数据库字段信息,主要属性有name(字段名)、columnDefinition、inserttable、length、nullable(是否为空)、precision、scale、table、unique、updatable等;

@ColumnType:描述数据库字段类型,可对一些特殊类型作配置,进行特殊处理,主要属性jdbcType、column、typeHandler

@Transient即冗余字段,不与数据库任何字段对应。

3.base类

首先自定义一个公共的MyMapper继承一些tkmybatis的现有的mapper,注意这个类不能被spring扫描到,否则会出现java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseSelectProvider.异常.

package com.example.tkmybatisdemo.config.mybatis;

import tk.mybatis.mapper.common.*;

/**
 * 自定义一个公共的MyMapper继承一些tkmybatis的现有的mapper
 * 注意这个类不能被spring扫描到,否则会出现java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseSelectProvider.异常.
 * @author qzz
 */
public interface MyMapper<T> extends MySqlMapper<T>, Mapper<T>, ConditionMapper<T>, IdsMapper<T> {

    /**
     * MySqlMapper:mysql独有的一些通用的方法
     * Mapper:主要的方法来源,包含BaseMapper<T>, ExampleMapper<T>, RowBoundsMapper<T>, Marker
     * ConditionMapper:按照自定义的条件查询
     * IdsMapper:按照ids查询,比较鸡肋,要求id是自增的.
     */
}

4.定义dao

package com.example.tkmybatisdemo.mapper;

import com.example.tkmybatisdemo.config.mybatis.MyMapper;
import com.example.tkmybatisdemo.entity.User;

/**
 * @author qzz
 */
public interface UserDao extends MyMapper<User> {
}

5.定义Controller

实现基本的增删改查

@RestController
@RequestMapping("/user")
public class UserController {
}

5.1 新增 insertSelective

核心代码:

@Autowired
private UserDao userDao;

/**
 * 新增
 * @param user
 * @return
 */
@PostMapping("/add")
public Result add(@RequestBody User user){
    user.setCreateUser("admin");
    user.setCreateTime(new Date());
    //insertSelective 保存一个实体,null的属性不会保存,会使用数据库默认值
   int i= userDao.insertSelective(user);
   if(i>0){
       return new Result().ok("新增成功");
   }else{
       return new Result().error("新增失败");
   }
}

5.2 编辑updateByPrimaryKeySelective

    /**
     * 编辑
     * @param user
     * @return
     */
    @PostMapping("/update")
    public Result update(@RequestBody User user){
        user.setUpdateUser("admin");
        user.setUpdateTime(new Date());
        //根据主键id更新用户信息  updateByPrimaryKeySelective:根据主键更新属性不为null的值
       int i= userDao.updateByPrimaryKeySelective(user);
       if(i>0){
           return new Result().ok("更新成功");
       }else{
           return new Result().error("更新失败");
       }
    }

5.3 查看详情 selectByPrimaryKey

     /**
     * 查看用户详情
     * @return
     */
    @GetMapping("/userInfo")
    public Result getUserById(@RequestParam("userId") Integer id){
        User userInfo = userDao.selectByPrimaryKey(id);
        return new Result().ok(userInfo);
    }

5.4 查看单条记录 selectOne

    /**
     * 查看单条记录
     * @return
     */
    @GetMapping("/single")
    public Result getSingle(@RequestParam("userId") Integer id){
        User user = new User();
        user.setId(id);
        User userInfo = userDao.selectOne(user);
        return new Result().ok(userInfo);
    }

5.5 查看所有 selectAll

    /**
     * 查看所有
     * @return
     */
    @GetMapping("/list")
    public Result getList(){
        List<User> list = userDao.selectAll();
        return new Result().ok(list);
    }

5.6 根据条件(and) 查看列表 selectByExample

    /**
     * 根据条件查看符合条件的列表
     * @return
     */
    @GetMapping("/getListByCondition")
    public Result getListByCondition(@RequestParam("name") String name,@RequestParam("age") Integer age){
        //根据名称获取用户信息

        //通用的Example查询对象
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andLike("name","%"+name+"%");
        criteria.andEqualTo("age",age);

        List<User> list = userDao.selectByExample(example);
        return new Result().ok(list);
    }

5.7 根据条件(or) 查看列表 selectByExample

    /**
     * 根据条件查看符合条件的列表   条件或 or
     * @return
     */
    @GetMapping("/getListByOrCondition")
    public Result getListByOrCondition(@RequestParam("name") String name,@RequestParam("age") Integer age){
        //根据名称获取用户信息

        //通用的Example查询对象
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andLike("name","%"+name+"%");
        criteria.orEqualTo("age",age);
        List<User> list = userDao.selectByExample(example);
        return new Result().ok(list);
    }

5.8 分页查看用户列表 PageHelper、selectByExample

    /**
     * 条件分页查看用户列表
     */
    @GetMapping("/page1")
    public PageInfo<UserInfo> page(@RequestParam("page") Integer page, @RequestParam("pageSize") Integer pageSize,@RequestParam("age") Integer age){
        PageHelper.startPage(page,pageSize);
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andGreaterThan("age",age);
        example.setOrderByClause("id desc");
        //selectByExample几乎可以解决所有的查询
        List<User> list = userDao.selectByExample(example);
        //把结果集赋值给另一个结果集,分页的参数属性不起作用(如:total 等)
        List<UserInfo> list1 =new ListUtils<UserInfo>().copyProperties(list,UserInfo.class);
        return new PageInfo<>(list1);
    }

5.9 限制条数查询 selectByExampleAndRowBounds

   /**
     * 限制条数查询
     * @param limit
     * @return
     */
    public List<UserInfo> getUserListByLimit(@RequestParam("limit") Integer limit,@RequestParam("age") Integer age){
        Example example = new Example(User.class);
        //创建查询标准
        Example.Criteria criteria = example.createCriteria();
        //查询条件
        criteria.andGreaterThan("age",age);
        //排序条件
        example.setOrderByClause("id desc");
        //查询后可以根据selectByExampleAndRowBounds指定获取几条特定的查询语句,类似 select中的limit。
        List<User> list = userDao.selectByExampleAndRowBounds(example,new PageRowBounds(0,limit));
        //把结果集赋值给另一个结果集,分页的参数属性不起作用(如:total 等)
        List<UserInfo> list1 =new ListUtils<UserInfo>().copyProperties(list,UserInfo.class);
        return list1;
    }

5.10(条件1 and 条件2) or ( 条件3 and 条件4) 查看

  
    /**
     * 根据(条件1 and 条件2) or ( 条件3 and 条件4)查看符合条件的列表
     * @return
     */
    @GetMapping("/getListByCondition2")
    public Result getListByCondition2(@RequestParam("name") String name,@RequestParam("age") Integer age){
        //根据名称获取用户信息

        //通用的Example查询对象
        Example example = new Example(User.class);
        //条件1 and 条件2
        Example.Criteria criteria1 = example.createCriteria();
        criteria1.andLike("name","%"+name+"%");
        criteria1.andEqualTo("age",age);

        //条件3 and 条件4
        Example.Criteria criteria2 = example.createCriteria();
        criteria2.andLike("phone","%"+name+"%");
        criteria2.andEqualTo("sex",0);

        //把上面的两个组合条件 进行or
        example.or(criteria2);

        List<User> list = userDao.selectByExample(example);
        return new Result().ok(list);
    }

5.11(条件1 or 条件2) and 条件3查看

思路 :分拆 : (条件1 or 条件2)and 条件3 ==> ( 条件1 and 条件3) or ( 条件2 and 条件3 )

  
  /**
     * 根据(条件1 or 条件2) and 条件3 查看符合条件的列表
     * 思路 : 分拆 : (条件1 or 条件2)and 条件3 ==> ( 条件1 and 条件3) or ( 条件2 and 条件3 )
     * @return
     */
    @GetMapping("/getListByCondition3")
    public Result getListByCondition3(@RequestParam("name") String name){
        //根据名称获取用户信息

        //通用的Example查询对象
        Example example = new Example(User.class);
        //条件1 and 条件3
        Example.Criteria criteria1 = example.createCriteria();
        criteria1.andLike("name","%"+name+"%");
        criteria1.andEqualTo("status",0);

        //条件2 and 条件3
        Example.Criteria criteria2 = example.createCriteria();
        criteria2.andLike("phone","%"+name+"%");
        criteria2.andEqualTo("status",0);

        //把上面的两个组合条件 进行or
        example.or(criteria2);

        List<User> list = userDao.selectByExample(example);
        return new Result().ok(list);
    }

6.启动类中配置

在启动类中配置@MapperScan扫描

/**
 * 注意使用org.mybatis.spring.annotation.MapperScan包下的此注解会连带扫描自定义的MyMapper,会出现
 * java.lang.NoSuchMethodException: tk.mybatis.mapper.provider.base.BaseSelectProvider.异常
 *
 */
@SpringBootApplication
@MapperScan("com.example.tkmybatisdemo.mapper")
public class TkMybatisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(TkMybatisDemoApplication.class, args);
    }

    /*
     * 以上的解决方案:
     * 一、使用import tk.mybatis.spring.annotation.MapperScan包下的@MapperScan注解
     * 二、或者不使用@MapperScan注解,改为在dao层的UserDao上添加@Mapper注解来单独标注mapper接口
     * */
}

7.进行测试

7.1 测试 (条件1 and 条件2) or ( 条件3 and 条件4) 查看

在这里插入图片描述
控制台:

在这里插入图片描述

7.2 测试 (条件1 or条件2) and 条件3 查看

在这里插入图片描述
控制台:
在这里插入图片描述

8.完整代码

可点击此处下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值