首页 > 技术文章 > 通用Mapper简单使用介绍

qianyi525 2020-11-10 16:48 原文

通用Mapper使用介绍

  通用Mapper是简化mybatis操作的一个框架,使用它就不需要再建立xml映射文件了,也不用在dao接口(注解开发)写sql语句,只需要将pojp用注解跟数据库的表和字段建立映射关系,然后在dao接口继承Mapp类并指定泛型(你要对哪个pojo操作就指定哪个pojo),在service实现类中,直接调用相关方法,就可以执行简单的CRUD,这样dao接口中也不需要再写方法了。但是这个也只能在简单的CRUD中可以使用。

  通用Mapper其实也可以当作一种编程思维,不仅仅是dao接口可以用它抽取,service、controller也一样可以用这种思想抽取出来,直接调用抽取出来的代码就可以了,而不需要重复的写一些代码,这篇随笔里面只说使用方式,这种思想会另起随笔解释。

1、添加起步依赖:

<!--通用mapper起步依赖,它内部集成了mybatis、数据源的依赖,所以加了它就可以了-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>
        <!--MySQL数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>

2、将pojo类跟数据库用注解建立映射关系

/****
 * @Author:admin
 * @Description:Brand构建
 * 
 *****/
@Table(name="tb_brand")//指定要映射的数据库中的哪个表
public class Brand implements Serializable{

    
    @Id//表示该成员变量是主键id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//标识该主键的策略,自增
    @Column(name = "id")
    private Integer id;//品牌id
    
    @Column(name = "name")//标识该成员变量跟数据库中的name字段映射
    private String name;//品牌名称
    
    @Column(name = "image")
    private String image;//品牌图片地址
    
    @Column(name = "letter")
    private String letter;//品牌的首字母
    
    @Column(name = "seq")
    private Integer seq;//排序


    //get方法
    public Integer getId() {
        return id;
    }

    //set方法
    public void setId(Integer id) {
        this.id = id;
    }
    //get方法
    public String getName() {
        return name;
    }

    //set方法
    public void setName(String name) {
        this.name = name;
    }
    //get方法
    public String getImage() {
        return image;
    }

    //set方法
    public void setImage(String image) {
        this.image = image;
    }
    //get方法
    public String getLetter() {
        return letter;
    }

    //set方法
    public void setLetter(String letter) {
        this.letter = letter;
    }
    //get方法
    public Integer getSeq() {
        return seq;
    }

    //set方法
    public void setSeq(Integer seq) {
        this.seq = seq;
    }


}

3、但是想要使用上面这个pojo中的注解,还需要加该系列注解的依赖才能使用:

<!--(该依赖是通用mapper的注解依赖,跟数据库的表产生映射关系)-->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>

4、创建controller、service、serviceImpl、dao,我按顺序挂一遍:

controller:

@RestController
@RequestMapping("/brand")
public class BrandController {
    @Autowired
    private BrandService brandService;

    @GetMapping("findAll")
    public Result findBrandAll(){
        List<Brand> brandAll = brandService.findBrandAll();
        return new Result(true, StatusCode.OK,"操作成功!",brandAll);
    }
}

service:

public interface BrandService {
    List<Brand> findBrandAll();
}

serviceImpl:

@Service
public class BrandServiceImpl implements BrandService {
    @Autowired
    private BrandDao brandDao;

    @Override
    public List<Brand> findBrandAll() {
        return brandDao.selectAll();

    }
}

dao:关键的地方到了,这个dao需要继承Mapper类,并指定泛型(泛型指定你要操作的pojo):继承它就行了,不需要写方法,当它继承了Mapper之后,调用这个dao接口的serviceImpl类中就可以调用mapper中定义好的方法,这些方法内部会拼接sql语句

public interface BrandDao extends Mapper<Brand> {

}

 

还有最关键的一点,就是跟mybatis使用一样,它需要扫描dao接口:这里要要注意,使用扫描的组件必须是tk,而不能用mybatis原本的:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
//tk!!tk!!tk!!  重要的事情说三遍,这里必须使用这个包里面的MapperScan!!
import tk.mybatis.spring.annotation.MapperScan;

@SpringBootApplication//spring boot自动配置注解
@EnableEurekaClient//这是spring cloud中的eureka客户端注解
@MapperScan(basePackages = "com.changgou.goods.dao")//指定要扫描的dao接口的包
public class GoodsServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(GoodsServiceApplication.class,args);
    }
}

 

再附加一些Mapper中的常用api介绍:

查询所有:里面代码就有体现,用继承了Mapper的dao接口(以下都是这样,不重复写了).select()

根据主键id查询:selectByPrimaryKey(id);

添加数据:有两个api

      .insertSelective(brand);   添加数据,如果添加的数据中有为null的字段,则不进行更改  一般都用这种方式比较好,如果有特需,则用下面方式

      .insert(brand);     添加数据,不管要添加的数据是否为null,都进行更改,如果为null则将数据库中的该字段修改为null

根据id更新数据:跟添加数据一样,只不过把snsert换成update就行了,同样有两个api,解释同上,这里唯一要注意的就是根据id更新数据,那么传入的pojo对象中的id字段一定要有值,否则它不知道修改哪条数据

根据id删除数据:.deleteByPrimaryKey(id);

根据条件查询数据:这个就要复杂一些了,这个根据条件查询和分页查询放一起单独挂:

 

根据条件查询数据:(这里是根据两个条件,第一个条件是name的模糊查询,第二个是letter的条件查询,两个条件可能没有,也可能只有一个,或者两个都有)

    /**
     * 根据搜索条件查询
     * */
    @Override
    public List<Brand> searchBrand(Brand brand) {
        //第二步:NEW出这个对象,指定存放条件内容的pojo,自动生成代码它是object接收的,所以要转换成Example
        Example example = new Example(Brand.class);
        //第三步,用刚刚NEW出的类创建条件对象,给这个条件对象设置条件就好了
        Example.Criteria criteria = example.createCriteria();
        //第四步,要进行非空判断,这里用的是StringUtils做的非空判断,
        //并且是SpringBoot的StringUtils,只要参数为null就会进入判断,所以下面取非就是只要不为null就进入判断执行代码
        if (!StringUtils.isEmpty(brand)){
            //这里做判断是因为两个条件,如果有其中一个没有值,说明客户端只传来一个,另一个条件就不添加
            if (!StringUtils.isEmpty(brand.getName())){
                //相当于sql语句:select * from t_brand <where> and name like '%'#{"name"}'%'</where>
                criteria.andLike("name","%"+brand.getName()+"%");
            }
            //这里做判断是因为两个条件,如果有其中一个没有值,说明客户端只传来一个,另一个条件就不添加
            if (!StringUtils.isEmpty(brand.getLetter())){
                //相当于sql语句:select * from t_brand <where> and letter = #{"name"}</where>
                criteria.andEqualTo("letter",brand.getLetter());
            }
        }
        //如果以上判断都没有进入,说明没有条件,那么查询的就是所有数据

        //第一步:用dao接口调用Mapper的selectByExample方法,它需要一个类作为参数,所以第二步就new出这个对象
        List<Brand> brandList = brandDao.selectByExample(example);
        return brandList;
    }

它基本的步骤就是代码里面的第一步到第三步,自己设置一下条件对象,然后手动进行是否有条件的判断就好了。

 

然后就是分页查询,也比较简单:只不过需要添加PageHelper的依赖,它也被spring boot集成了,所以可以添加starter的PageHelper依赖,就可以用了,不需要自己配置

    /**
     * 分页查询所有数据
     * */
    @Override
    public PageInfo<Brand> findPage(Integer page, Integer size) {
        //调用PageHelper的startPage方法,设置当前页、每页条数
        PageHelper.startPage(page,size);
        //调用dao接口继承的Mapper方法,查询所有的数据
        List<Brand> brandList = brandDao.selectAll();
        //把查到的数据封装到PageInfo中,然后返回,PageInFo中包含了所有的数据,总条数等等
        PageInfo<Brand> brandPageInfo = new PageInfo<>(brandList);
        //返回即可
        return brandPageInfo;
    }

 

最后,在很多场景下,根据条件查询的数据也需要进行分页,不仅仅前端需要传当前页和每页条数的参数,还需要传条件过来,所以跟上面不一样的是,前端要发送post请求为好,上面发get请求就可以:

这个就是将分页查询和根据条件查询结合起来就可以了,代码示范如下:(只要上面两个看明白了,这个就会无师自通)

    /**
     * 根据条件分页查询
     * */
    @Override
    public PageInfo<Brand> cearchPageByTerm(Integer page, Integer size,Brand brand) {
        //0、如果前端没有传入当前页和每页条数,则给它赋值
        if (page==null){
            page=1;
        }
        if (size==null){
            size=10;
        }
        //1、设置当前页、每页条数
        PageHelper.startPage(page,size);
        //2、查询数据
        Example example = new Example(Brand.class);
        Example.Criteria criteria = example.createCriteria();
        if (!StringUtils.isEmpty(brand)){
            if (!StringUtils.isEmpty(brand.getName())){
                criteria.andLike("name","%"+brand.getName()+"%");
            }
            if (!StringUtils.isEmpty(brand.getLetter())){
                criteria.andEqualTo("letter",brand.getLetter());
            }
        }
        List<Brand> brandList = brandDao.selectByExample(example);
        //将查询到的数据封装到pageinfo中
        PageInfo<Brand> listPageInfo = new PageInfo<>(brandList);
        return listPageInfo;
    }

 

 最后附加一个全局处理异常的方法

 这里面用的注解都是spring里面的,所以也并不需要添加其它的依赖,只要你有spring 或者 spring boot的依赖就可以了

//添加注解,交给spring容器,这个注解还标识这是一个全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 写一个方法,表示只要出现指定的某种异常,就进入到这个方法中进行处理
     * @ResponseBody: 因为前端只能接收JSON数据,不能直接返回Result对象,所以需要添加这个注解
     * @ExceptionHandler(value = Exception.class): 表示这个方法是全局处理异常的方法
     *                    这里面value值,要指定出现什么异常进入下面的方法,如果不指定默认就是Exception
     * */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Result globalExceptionHandler(Exception ex){
        //捕获异常并封装到result中返回
        return new Result(false, StatusCode.ERROR,ex.getMessage());
    }

}

 

然后,发送请求,就可以获取到数据了。这里比较简单,就是熟练度的问题了,当然,看关键部位就可以了,不要尝试直接复制搭建,这是我从微服务项目中拷贝了一部分代码,还有很多环境配置这里没有复制上来。

 


 

当然,除了通用mapper(也就是dao)之外,service、controller的CRUD也基本上代码一致,所以我们也可以抽取出来,在微服务架构中,一般是单独抽取到一个微服务,然后在各个模块的controller、service中就可以不用写那些重复代码,直接继承一个抽象类(该抽象类实现了一个核心接口,该核心接口继承了CRUDP等五个增删改查分页查询功能的接口),这样就省下了很多重复代码的编写。

 

通用service代码抽取

 

 

 上图大概的思路就是:在core微服务中编写五个接口,分别实现增、删、查、改、分页五个功能,其中又分为查询所有、根据条件查询、根据主键id查询等等

          然后用一个核心接口,继承这5个接口

          再就是编写一个抽象类,实现这个核心接口的方法

          最后,在真正功能模块中的service接口继承核心接口,并指定泛型为要操作的实体类

             然后在真正功能模块中的serviceImpl(service接口的实现类)先继承core微服务中实现了接口的抽象类,并指定泛型(要操作的实体类),然后再实现真正模块中的service接口(这个不是core工程中的核心接口),并在下面用super的方式给父类成员变量赋值

 

 

代码实现:

1、先创造一个微服务core,打包方式为pom,再在这个微服务中创建子工程core-service,打包方式jar,并添加相关依赖(通用Mapper、mysql、pagehandler、微服务的话pojo所在工程的依赖,这些依赖一定要有,其它的视情况定,这里偷个懒,直接从项目中拷贝了依赖)

<dependencies>
        <!--对changgou-common的依赖-->
        <dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!--通用mapper起步依赖-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.4</version>
        </dependency>
        <!--MySQL数据库驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--mybatis分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.3</version>
        </dependency>
<!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--redis 使用-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!--spring-cloud-feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--微信支付-->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
        <!--httpclient支持-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
    </dependencies>

 

2、在core工程中创建包:com.xxx.core.service,在包内创建五个CRDUP接口,根据需求实现相关功能:

/***
 * 描述
 */
public interface UpdateService<T> {

    /**
     * 根据对象进行更新
     *
     * @param record
     * @return
     */
    int updateByPrimaryKey(T record);
}
/**
 * 描述
 *
 */
public interface SelectService<T> {

    /**
     * 查询所有
     *
     * @return
     */
    public List<T> selectAll();

    /**
     * 查询一个对象
     *
     * @param id
     * @return
     */
    public T selectByPrimaryKey(Object id);

    /**
     * 根据条件查询
     *
     * @param record
     * @return
     */
    public List<T> select(T record);


}

 

/**
 * 描述
 */
public interface PagingService<T> {

    /**
     * 查询所有并分页
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    PageInfo<T> findByPage(Integer pageNo, Integer pageSize);


    /**
     * 根据查询条件 record 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @param record
     * @return
     */
    PageInfo<T> findByPage(Integer pageNo, Integer pageSize, T record);


    /**
     * 根据查询条件exmaple来分页查询
     *
     * @param pageNo
     * @param pageSize
     * @param example
     * @return
     */
    PageInfo<T> findByPageExample(Integer pageNo, Integer pageSize, Object example);


}
/***
 * 描述
 */
public interface InsertService<T> {
    /**
     * 添加记录
     * @param record
     * @return
     */
    int insert(T record);

}
/**
 * 删除相关
 */
public interface DeleteService<T> {

    /**
     * 根据条件删除
     *
     * @param record
     * @return
     */
    int delete(T record);

    /**
     * 根据ID 删除
     *
     * @param id
     * @return
     */
    int deleteById(Object id);


}

 

然后再创建一个核心接口并继承以上五个接口:

/***
 * 描述:继承了CRUDP五个接口的核心接口,它被一个抽象类所实现
 */
public interface CoreService<T> extends
        DeleteService<T>,
        InsertService<T>,
        PagingService<T>,
        SelectService<T>,
        UpdateService<T> {
}

 

再创建一个impl包,在包内创建一个抽象类,实现上面这个核心接口

/***
 * 描述
 * 抽象类,实现了CoreService核心接口的CRUDP功能,谁继承这个抽象类实现谁就要提供操作的实体类,这样这个抽象类才能知道操作哪个对象
 * 继承这个类,需要给通用mapper和操作的实体类赋值,通过super方式
 */
public abstract class CoreServiceImpl<T> implements CoreService<T> {
    //通用mapepr
    protected Mapper<T> baseMapper;
    //操作的实体类
    protected Class<T> clazz;

    //提供构造方法,方便它的子类给通用mapper和操作的实体类赋值
    public CoreServiceImpl(Mapper<T> baseMapper, Class<T> clazz) {
        this.baseMapper = baseMapper;
        this.clazz = clazz;
    }

    //删除数据
    @Override
    public int delete(T record) {
        return baseMapper.delete(record);
    }
    //根据id删除数据
    @Override
    public int deleteById(Object id) {
        return baseMapper.deleteByPrimaryKey(id);
    }
    //添加数据
    @Override
    public int insert(T record) {
        return baseMapper.insertSelective(record);
    }
    //查询所有数据
    @Override
    public List<T> selectAll() {
        return baseMapper.selectAll();
    }
    //根据主键id查询数据
    @Override
    public T selectByPrimaryKey(Object id) {
        return baseMapper.selectByPrimaryKey(id);
    }
    //根据条件查询数据,条件只能是where = ,不能是where like之类的
    @Override
    public List<T> select(T record) {
        return baseMapper.select(record);
    }
    //根据主键id修改数据
    @Override
    public int updateByPrimaryKey(T record) {
        return baseMapper.updateByPrimaryKeySelective(record);
    }
    //分页查询数据
    @Override
    public PageInfo<T> findByPage(Integer pageNo, Integer pageSize) {
        PageHelper.startPage(pageNo, pageSize);
        List<T> list = baseMapper.selectAll();
        PageInfo<T> pageInfo = new PageInfo<T>(list);
        return pageInfo;
    }
    //根据条件模糊分页查询数据
    @Override
    public PageInfo<T> findByPage(Integer pageNo, Integer pageSize, T record) {
        Example example = new Example(clazz);
        Example.Criteria criteria = example.createCriteria();
        Field[] declaredFields = record.getClass().getDeclaredFields();

        for (Field declaredField : declaredFields) {
            try {
                //遇到 id注解 和 transient注解 不需要进行值的设置 直接跳过。
                if (declaredField.isAnnotationPresent(Transient.class) || declaredField.isAnnotationPresent(Id.class)) {
                    //遇到
                    continue;
                }
                //属性描述器  record.getClass()
                PropertyDescriptor propDesc = new PropertyDescriptor(declaredField.getName(), record.getClass());
                //获取这个值  先获取读方法的方法对象,并调用获取里面的值
                Object value = propDesc.getReadMethod().invoke(record);
                //Object value = propDesc.getValue(declaredField.getName());
                //如果是字符串
                if (value != null && value.getClass().getName().equals("java.lang.String")) {
                    Column columnAnnotation = declaredField.getAnnotation(Column.class);
                    //判断如果是长度为1 则 执行=号
                    int length = columnAnnotation.length();
                    if (length == 1) {
                        criteria.andEqualTo(declaredField.getName(), value);
                    } else {
                        criteria.andLike(declaredField.getName(), "%" + value + "%");
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        PageHelper.startPage(pageNo, pageSize);
        List<T> ts = baseMapper.selectByExample(example);
        PageInfo<T> info = new PageInfo<T>(ts);
        return info;
    }
    //根据条件分页查询数据
    @Override
    public PageInfo<T> findByPageExample(Integer pageNo, Integer pageSize, Object example) {
        PageHelper.startPage(pageNo, pageSize);
        List<T> list = baseMapper.selectByExample(example);
        PageInfo<T> info = new PageInfo<T>(list);
        return info;
    }


}

 

这样,通用的service就已经写完了,只需要在使用的时候指定泛型、给父类成员变量赋值就可以了,最后在controller就可以使用这个通用service的方法完成CRUDP

功能模块中的service接口代码如下:

/**
 * 品牌模块service
 * core工程抽取了service的通用代码,所以这里继承这个通用service接口,指定要操作的实体类即可
 * */
public interface BrandService extends CoreService<Brand> {

}

 

功能模块中的serviceImpl实现类代码如下:

/**
 * 品牌模块service实现类
 * 继承core工程中抽取的通用service的抽象实现类,并指定要操作的实体类,这个实现类实现了基本的CRUDP的方法,所以继承它也就相当于实现了CRUDP
 * 实现本工程编写的BrandService
 * 因为本工程dao接口中也是操作的通用mapper,所以需要将dao接口赋值给父类,完成实现
 * 还需要给父类需要操作的实体类赋值(当前所在的类为子类,它继承的类为父类)
 * */
@Service
public class BrandServiceImpl extends CoreServiceImpl<Brand> implements BrandService{
    private BrandDao brandDao;

    @Autowired
    public BrandServiceImpl(Mapper brandDao) {
        super(brandDao, Brand.class);
    }
}

 

做到这里,开启功能模块就可以接收到请求并处理请求了,以后相关的单表的CRUDP操作中业务层层不再需要写这些代码,只需要继承通用service即可


 

既然service可以抽取通用代码,那么controller中的代码也都是差不多的,所以也可以用相同思路实现,这里挂一下代码:依赖没挂了,它需要上面写的core-service工作作为依赖就可以了

1、相同的在core工程中创建子工程core-controller,建好包创建5个接口:

/***
 * 描述
 */
public interface IUpdateController<T> {

    /**
     * 根据对象进行更新 根据ID
     *
     * @param record
     * @return
     */
    Result updateByPrimaryKey(T record);
}
/***
 * 描述
 */
public interface ISelectController<T> {
    //根据ID 获取信息
    public Result<T> findById(Object id);


    //根据ID 获取信息列表
    public Result<List<T>> findAll();
}
/**
 * 描述
 */
public interface IPagingController<T> {

    /**
     * 查询所有并分页
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    Result<PageInfo<T>> findByPage(Integer pageNo, Integer pageSize);


    /**
     * 根据查询条件 record 分页查询
     *
     * @param pageNo
     * @param pageSize
     * @param record
     * @return
     */
    Result<PageInfo<T>> findByPage(Integer pageNo, Integer pageSize, T record);


}
/***
 * 描述
 */
public interface IInsertController<T> {
    /**
     * 添加记录
     * @param record
     * @return
     */
    Result insert(T record);

}
/***
 * 描述
 */
public interface IDeleteController<T> {
    /**
     * 根据ID 删除
     *
     * @param id
     * @return
     */
    Result deleteById(Object id);
}

 

2、一样是编写核心接口继承上面5个接口

/***
 * 描述
 * 继承了CRUDP五个接口的核心接口
 */
public interface ICoreController<T> extends
        ISelectController<T>,
        IInsertController<T>,
        IPagingController<T>,
        IDeleteController<T>,
        IUpdateController<T> {
}

 

3、编写抽象类:

/***
 * 描述
 * 抽象类,该抽象类实现了有CRUDP功能的service接口,继承它即可使用这些功能,但要给抽取的通用service对象和调用方类型赋值
 * 这里方法上用mapping做第二个请求路径,加载类上的第一个请求路径不放在这,由继承它的类加,或者在方法上写两级请求路径
 */

public abstract class AbstractCoreController<T> implements ICoreController<T> {

    //调用方的service
    protected CoreService<T> coreService;
    //调用方的类型
    protected Class<T> clazz;

    //通过构造方法给通用service和操作实体类赋值
    public AbstractCoreController(CoreService<T> coreService, Class<T> clazz) {
        this.coreService = coreService;
        this.clazz = clazz;
    }

    /**
     * 删除记录
     *
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    @Override
    public Result deleteById(@PathVariable(name = "id") Object id) {
        coreService.deleteById(id);
        return new Result(true, StatusCode.OK, "删除成功");
    }

    /**
     * 添加记录
     *
     * @param record
     * @return
     */
    @PostMapping
    @Override
    public Result insert(@RequestBody T record) {
        coreService.insert(record);
        return new Result(true, StatusCode.OK, "添加成功");
    }

    /**
     * 分页查询记录
     *
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping(value = "/search/{page}/{size}")
    @Override
    public Result<PageInfo<T>> findByPage(@PathVariable(name = "page") Integer pageNo,
                                          @PathVariable(name = "size") Integer pageSize) {
        PageInfo<T> pageInfo = coreService.findByPage(pageNo, pageSize);
        return new Result<PageInfo<T>>(true, StatusCode.OK, "分页查询成功", pageInfo);
    }

    @PostMapping(value = "/search/{page}/{size}")
    @Override
    public Result<PageInfo<T>> findByPage(@PathVariable(name = "page") Integer pageNo,
                                          @PathVariable(name = "size") Integer pageSize,
                                          @RequestBody T record) {
        PageInfo<T> pageInfo = coreService.findByPage(pageNo, pageSize, record);
        return new Result<PageInfo<T>>(true, StatusCode.OK, "条件分页查询成功", pageInfo);
    }

    @Override
    @GetMapping("/{id}")
    public Result<T> findById(@PathVariable(name = "id") Object id) {
        T t = coreService.selectByPrimaryKey(id);
        return new Result<T>(true, StatusCode.OK, "查询单个数据成功", t);
    }

    @Override
    @GetMapping
    public Result<List<T>> findAll() {
        List<T> list = coreService.selectAll();
        return new Result<List<T>>(true, StatusCode.OK, "查询所有数据成功", list);
    }

    //更新数据
    @Override
    @PutMapping
    public Result updateByPrimaryKey(@RequestBody T record) {
        coreService.updateByPrimaryKey(record);
        return new Result(true, StatusCode.OK, "更新成功");
    }
}

 

4、然后就是使用这个通用controller,在真正的功能模块的controller类中继承这个抽象类,因为controller就没有本身的接口需要实现了,所以直接继承抽象类指定泛型即可,这里唯一不同的就是请求的映射路径,第一个路径在真正功能模块的类上,第二个路径在通用controller的抽象类上。

/**
 * 品牌模块
 * */
@RestController
@RequestMapping("/brand")
public class BrandController extends AbstractCoreController<Brand> {

    private CoreService coreService;
    @Autowired
    public BrandController(CoreService<Brand> coreService) {
        super(coreService, Brand.class);
    }
}

 

然后就可以发送请求实验了。

 

推荐阅读