Spring Boot项目通用功能之《通用Mapper》

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/aiyaya_/article/details/79146763

前言

接下来这几篇文章中我们主要说说,在我们的项目中会使用哪些通用的功能,例如:通用Mapper(mybatis框架的)、通用service和分页功能等等,这些通用功能的使用会大大降低我们的开发时间,也会让我们的代码变得更加有规范更加合理,今天这篇文章我们说说怎么使用通用mapper。

通用mapper简介

通用mapper是一个国人编写的工具jar,它可以极其方便的做单表增删改查(使用Mybatis框架),目前不支持通用的多表联合查询,在使用mybatis时,就不需要重复的维护功能类似单表操作mapper.xml文件和mapper接口的定义,下面给出它的码云和github地址。

使用前疑问

  1. 这个东西使用后,会不会降低我们的代码执行效率呢?
    答:其实他的原理就是利用反射机制拼出的 XML形式的动态SQL然后去执行,所以你说代码时间消耗肯定也会有一些,但是这是很小很小的,再者在现在项目中,对于提供给前端的接口,通常都会利用些组件进行访问加速(毕竟直接从数据中检索不如在内存中来的快些),比如:redis、memcache、elastic search、solr等,所以执行效率问题是可以避免或忽略的。
  2. 如果有些方法不想使用,例如:用户的接口服务不能使用删除方法也不想暴漏出来,该怎么办呢?
    答:我们通常会定义增、删、改、查四个基础Mapper接口,你可以按需要引入进行使用,其实即使你使用了公共的CrudMapper(代表增删改查都在一起的类)也没有问题,只要你在你的service层不要放出删除方法也是可以的。

使用心得

详细使用方式其实在码云上和Github上说的也算是详细,至少基础入门是没有问题,下面我们说说在spring boot项目中的配置和使用方法。

1 首先引入包
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>3.4.0</version><!--这里使用时去看看最新版本哈-->
        </dependency>

如果是spring boot项目直接引入:

        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
2 增加配置类
package com.zhuma.demo.config.mybatis;

import com.zhuma.demo.comm.mapper.CrudMapper;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import java.util.Properties;

@Configuration
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class MyBatisConfig {

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.zhuma.demo.mapper");

        Properties properties = new Properties();
        properties.setProperty("mappers", CrudMapper.class.getName());
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        properties.setProperty("ORDER","BEFORE");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }

}

备注

  • 这里需要注意的是MapperScannerConfigurer 类是tk.mybatis.spring.mapper这个包下的
  • mapperScannerConfigurer.setBasePackage(“com.zhuma.demo.mapper”),这里去配置你自己数据库对应Mapper类的包路径,如果有多个用英文逗号分隔
  • 上面配置类中引入了一个CrudMapper类,这个是我们自己定义的它是提供增删改查的基础接口,下面会给出详细代码。(注意不要跟自定义功能mapper放到这个下面)
3 常规方法接口整合到自己的自定义Mapper接口上

备注:因为我们使用的是mysql数据库,所以在使用通用功能的时候就选择性引入一些经常使用的方法,下面是自己定义的常用mapper类的整合(这里会抛弃一些不常用的类或不是mysql的方法类)。
① 提供新增功能Mapper类:

package com.zhuma.demo.comm.mapper;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.MySqlMapper;
import tk.mybatis.mapper.common.base.insert.InsertSelectiveMapper;

/**
 * @desc 基础插入功能mapper
 * 
 * @author zhumaer
 * @since 10/18/2017 18:31 PM
 */
public interface InsertMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.insert.InsertMapper<T>,
                                                InsertSelectiveMapper<T>,
                                                MySqlMapper<T>{
}

② 提供删除功能的Mapper类

package com.zhuma.demo.comm.mapper;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.delete.DeleteByPrimaryKeyMapper;
import tk.mybatis.mapper.common.condition.DeleteByConditionMapper;
import tk.mybatis.mapper.common.ids.DeleteByIdsMapper;

/**
 * @desc 基础删除功能mapper
 * 
 * @author zhumaer
 * @since 10/18/2017 18:31 PM
 */
public interface DeleteMapper<T> extends Marker,
        tk.mybatis.mapper.common.base.delete.DeleteMapper<T>,
                                                DeleteByPrimaryKeyMapper<T>,
                                                DeleteByConditionMapper<T>,
                                                DeleteByIdsMapper<T> {
}

③ 提供修改功能的Mapper类

package com.zhuma.demo.comm.mapper;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeyMapper;
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeySelectiveMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionMapper;
import tk.mybatis.mapper.common.condition.UpdateByConditionSelectiveMapper;
import tk.mybatis.mapper.common.example.UpdateByExampleSelectiveMapper;

/**
 * @desc 基础更新功能mapper
 *
 * @author zhumaer
 * @since 10/18/2017 18:31 PM
 */
public interface UpdateMapper<T> extends Marker,
        UpdateByPrimaryKeyMapper<T>,
        UpdateByPrimaryKeySelectiveMapper<T>,
        UpdateByConditionMapper<T>,
        UpdateByConditionSelectiveMapper<T>,
        UpdateByExampleSelectiveMapper<T> {
}

④ 提供查询功能的Mapper

package com.zhuma.demo.comm.mapper;

import tk.mybatis.mapper.common.Marker;
import tk.mybatis.mapper.common.base.select.*;
import tk.mybatis.mapper.common.condition.SelectByConditionMapper;
import tk.mybatis.mapper.common.condition.SelectCountByConditionMapper;
import tk.mybatis.mapper.common.example.SelectByExampleMapper;
import tk.mybatis.mapper.common.ids.SelectByIdsMapper;

/**
 * @desc 基础查询功能mapper
 *
 * @author zhumaer
 * @since 10/18/2017 18:31 PM
 */
public interface SelectMapper<T> extends Marker,
        SelectOneMapper<T>,
        tk.mybatis.mapper.common.base.select.SelectMapper<T>,
        SelectAllMapper<T>,
        SelectCountMapper<T>,
        SelectByPrimaryKeyMapper<T>,
        ExistsWithPrimaryKeyMapper<T>,
        SelectByIdsMapper<T>,
        SelectByConditionMapper<T>,
        SelectCountByConditionMapper<T>,
        SelectByExampleMapper<T> {
}

⑤ 提供增删改查功能Mapper(上面配置是直接引入的这个)

package com.zhuma.demo.comm.mapper;

/**
 * @desc 基础增删改查功能mapper
 * 
 * @author zhumaer
 * @since 10/18/2017 18:31 PM
 */
public interface CrudMapper<T> extends
        InsertMapper<T>,
        DeleteMapper<T>,
        UpdateMapper<T>,
        SelectMapper<T> {
}
3 以用为例我们进行创建并查询用户

① 用户PO类

package com.zhuma.demo.model.po;

import com.zhuma.demo.annotation.EnumValue;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
import java.util.Date;

/**
 * @desc 用户PO

 * @author zhumaer
 * @since 6/15/2017 2:48 PM
 */
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User implements Serializable {

    private static final long serialVersionUID = -7491215402569546437L;

    /**
     * 用户ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "select uuid()")
    @Length(min=1, max=64)
    private String id;

    /**
     * 昵称
     */
    @NotBlank
    @Length(min=1, max=64)
    private String nickname;

    /**
     * 性别
     */
    @NotBlank
    @EnumValue(enumClass=UserGenderEnum.class, enumMethod="isValidName")
    private String gender;

    /**
     * 头像
     */
    @Length(max=256)
    private String avatar;

    /**
     * 状态
     */
    @NotBlank
    @EnumValue(enumClass=UserTypeEnum.class, enumMethod="isValidName")
    private String type;

    /**
     * 账号状态
     */
    @EnumValue(enumClass=UserStatusEnum.class, enumMethod="isValidName")
    private String status;

    private Date createTime;

    private Date updateTime;

    /**
     * 用户性别枚举
     */
    public enum UserGenderEnum {
        /**男*/
        MALE,
        /**女*/
        FEMALE,
        /**未知*/
        UNKNOWN;

        public static boolean isValidName(String name) {
            for (UserGenderEnum userGenderEnum : UserGenderEnum.values()) {
                if (userGenderEnum.name().equals(name)) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * 用户类型枚举
     */
    public enum UserTypeEnum {
        /**普通*/
        NORMAL,
        /**管理员*/
        ADMIN;

        public static boolean isValidName(String name) {
            for (UserTypeEnum userTypeEnum : UserTypeEnum.values()) {
                if (userTypeEnum.name().equals(name)) {
                    return true;
                }
            }
            return false;
        }
    }

    /**
     * 用户状态枚举
     */
    public enum UserStatusEnum {
        /**启用*/
        ENABLED,
        /**禁用*/
        DISABLED;

        public static boolean isValidName(String name) {
            for (UserStatusEnum userStatusEnum : UserStatusEnum.values()) {
                if (userStatusEnum.name().equals(name)) {
                    return true;
                }
            }
            return false;
        }
    }
}

备注

  • 这里注意我们的用户ID通常都是使用UUID作为主键的,所以我们也一样,如果是主键自增就加@GeneratedValue(strategy = GenerationType.IDENTITY)注解。
  • 这个对象中是没有getter、setter方法的,其实是使用了lombok的缘故(如果你不太会使用,可以学一学,还是很简化代码的,lombok入门教程

② 用户Mpper类

package com.zhuma.demo.mapper;

import com.zhuma.demo.comm.mapper.CrudMapper;
import com.zhuma.demo.model.po.User;
import org.springframework.stereotype.Repository;

/**
 * @desc 用户Mapper
 *
 * @author zhumaer
 * @since 25/1/2018 22:39 PM
 */
@Repository
public interface UserMapper extends CrudMapper<User> {
}

③ 用户控制器(我们还是以保存用户为例)

package com.zhuma.demo.web.user;

import java.util.Date;

import com.zhuma.demo.annotation.ResponseResult;
import com.zhuma.demo.comm.result.DefaultErrorResult;
import com.zhuma.demo.comm.result.PlatformResult;
import com.zhuma.demo.comm.result.Result;
import com.zhuma.demo.exception.BusinessException;
import com.zhuma.demo.exception.DataNotFoundException;
import com.zhuma.demo.exception.UserNotLoginException;
import com.zhuma.demo.mapper.UserMapper;
import com.zhuma.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import com.zhuma.demo.model.po.User;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @desc 用户管理控制器
 * 
 * @author zhumaer
 * @since 6/20/2017 16:37 PM
 */
@ResponseResult
@RestController
@RequestMapping("/users")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public User addUser(@Validated @RequestBody User user) {
        Date currentDate = new Date();
        user.setCreateTime(currentDate);
        user.setUpdateTime(currentDate);
        userMapper.insert(user);
        return userMapper.selectByPrimaryKey(user.getId());
    }

}

备注
这里省略了service层,真实开发中还是需要的哈。

④ 响应结果
这里写图片描述
数据中记录
这里写图片描述
备注

  • 这里注意我们建议在正常创建信息时,需返回201状态码
  • 你可能不清楚为什么我在Controller方法中返回了User对象但是却有code、msg、data这种包装呢,如果你感兴趣可以看一下我的这篇文章就会清楚《接口响应体格式统一封装》

最后

好啦,这篇文章我们主要就是讲解下使用通用Mapper的一个完整实例,如果你还是感觉不太会使用,下两篇文章会介绍在项目中如果实现《通用分页功能》和通用Service(这两篇文章也会有对通用mapper的使用),对于通用mapper的使用,不知道你还有什么疑惑呢,可以关注我的微信号或留言,很愿意和你一起讨论学习O(∩_∩)O~

最后附上github地址:https://github.com/zhumaer/zhuma/tree/master/zhuma-demo

欢迎关注我们的公众号或加群,等你哦!

猜你喜欢

转载自blog.csdn.net/aiyaya_/article/details/79146763
今日推荐