【Java】基于SpringBoot+Mybatis-plus的封装基础代码骨架,解决增删改查重复编码

前言

在我们平时的web项目中,都会用到增删改查接口。如果不去进行封装,那么controller、service、dao这几层就要对应的去进行重复编写。再考虑到全局的请求日志管理、数据权限过滤、异常处理等等,还是需要在基于自己业务基础上,进行一些必要的封装工作。同时要注意,封装的同时要留足够的自由度去应对不同业务可能会出现的的特殊需求。

1、统一分页请求参数

一个业务系统最多的可能是查询功能。首先我们对于分页请求的请求体进行封装。统一分页请求参数,同时也利于前端的代码封装。例如可以基于vue的Mixins混入机制,封装公共列表页基础功能,增删改查等。在各个页面在引入时,只需要定义具体的请求URL即可实现增删改查功能。前端代码在此文档中不作表述。废话少说,上代码:

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 接收前台参数辅助类 统一分页查询
 *
 * @author dzx
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageDataVo<T> {
    private Page<T> page;
    private T data;

    @Override
    public String toString() {
        return "PageDataVo{" +
                "page=Page(" + "records=" + page.getRecords() +
                "total=" + page.getTotal() +
                "size=" + page.getSize() +
                "current=" + page.getCurrent() +
                "orders=" + page.getOrders() +
                ", data=" + data +
                '}';
    }
}

2、dao封装

虽然在我们集成了mybatis-plus之后,在我们自己的dao实现其提供的BaseMapper,不用写XML就可以获得CRUD功能,但是如果遇到非单表查询、查询条件需要范围查询、模糊查询时,不写XML同时使用BaseMapper提供的方法就满足不了。如下面的IBaseMapper代码,首先定义一个接口实现mybatis-plus的BaseMapper。使其具有BaseMapper的功能之外,我们将自己定义的一些方法加入其中。比如分页。在这里定义并不意味着我们的xml中必须要写对应的sql语句。可以在serviceImpl中看到具体代码。

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * <p>
 * 封装的公共IBaseMapper,将一些公共方法提出来 ,如分页、列表等
 * <p/>
 *
 * @author dzx
 */
public interface IBaseMapper<T> extends BaseMapper<T> {
    /**
     * 自定义分页查询
     *
     * @param page   分页
     * @param entity 查询参数
     * @return List
     */
    List<T> queryPageByCond(IPage page, @Param("params") T entity);
}

3、service封装

首先是IBaseService的定义。同样的继承mybatis-plus提供的IService的同时,加入基于我们业务的自定义方法。
我这里是做了一个查询之后进行数据字典项的转换,我们在前端展示时,很多字段对应的是数据字典项的值,而不是对应的label。比如,0男1女。存到数据库肯定是0,但是前端需要展示的是1。当然,这种处理放到前端去处理也不是不可以。要么就是写死,要么就再进行一次后台查询,获得字典项列表。在获取列表后,再循环遍历,展示其对应的label。第一种写死,会造成如果数据字典进行变更,那在前后端分离部署的情况下,前端代码就需要重新部署。第二种方法,可以采用。但是会造成更多的请求。我这里选择的是放到后台进行处理。同时,包括一些数据权限过滤,对于一些插入和更新操作,如果需要获取当前登录人信息一并插入到表中。例如create_time、create_user、update_time等等。我们都可以将其放到这个接口中。

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.nari.ztdz.lockset.mainview.base.vo.PageDataVo;

import java.util.List;

/**
 * <p>
 * 封装的公共IBaseService,将一些公共方法提出来 ,如分页、列表等
 * 以后的fillInsertInfo fillUpdateInfo都可以放到这里
 * <p/>
 *
 * @author dzx
 */
public interface IBaseService<T> extends IService<T> {
    /**
     * <p>
     * 分页查询
     * <p/>
     *
     * @param pageDataVo
     * @return Page<T>
     */
    Page<T> queryPageByCond(PageDataVo<T> pageDataVo);


    /**
     * <p>
     * 分页查询之后将list进行数据转换的方法
     * <p/>
     *
     * @param list
     * @return List<T>
     */
    List<T> beforeList(List<T> list);
}

serviceImpl代码如下,M为我们实现了IBaseMapper的Mapper。T为当前对应的实体类泛型。刚才说道,IBaseMapper中自定义了queryPageByCond方法,但是我们并不一定要在xml中进行sql编写,因为我们在serviceImpl中进行了一个try catch的处理。如果我们的mapper.xml中没有queryPageByCond,那么就会抛出BindingException异常,我们在catch中走mybatis-plus自带的查询。这样做的好处是,如果不需要模糊查询、范围查询这种查询时,我们就不需要进行sql的编写。减少代码量。

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nari.ztdz.lockset.mainview.base.mapper.IBaseMapper;
import com.nari.ztdz.lockset.mainview.base.vo.PageDataVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.binding.BindingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 封装的公共IBaseService,将一些公共的、代码或功能具有重复性的方法提出来,减少重复代码。如分页、列表等。
 * 以后的fillInsertInfo fillUpdateInfo 以及查询前的数据权限过滤 都可以放到这里
 * <p/>
 *
 * @author dzx
 */
@Slf4j
@Transactional
public class IBaseServiceImpl<M extends IBaseMapper<T>, T> extends ServiceImpl<M, T> implements IBaseService<T> {
    @Autowired
    protected M mapper;

    /**
     * <p>
     * 如果说在分页的时候,查询结果中有某些字段需要在代码层进行处理,例如取某个字段对应的数据字典的label等
     * 可以在自己的serviceImpl中重写beforeList,取进行具体的业务逻辑操作
     * <p/>
     *
     * @param pageDataVo
     * @return
     */
    @Override
    public Page<T> queryPageByCond(PageDataVo<T> pageDataVo) {
        Page<T> page = pageDataVo.getPage();
        List<T> tList = new ArrayList<T>();
        try {
            tList = this.mapper.queryPageByCond(page, pageDataVo.getData());
            page.setRecords(tList);
        } catch (BindingException var3) {
            //当发现mapper.xml中没有queryPageByCond时,那就会走mybatis-plus自带的查询
            //这样做的目的是为了有的分页不需要模糊查询或者时间范围这种需要重写xml或者重新构造QueryWrapper时,使用此方法亦可正常返回
            log.debug("mapper.xml没有相应list映射");
            IPage<T> iPage = this.mapper.selectPage(page, new QueryWrapper<T>(pageDataVo.getData()));
            page.setRecords(iPage.getRecords());
        }
        if (!CollectionUtil.isEmpty(page.getRecords())) {
            List<T> list = this.beforeList(page.getRecords());
        }
        return page;
    }

    /**
     * <p>
     * 这个方法是为了查询结果中有某些字段需要在代码层进行处理,例如取某个字段对应的数据字典的label等
     * <p/>
     *
     * @param list
     * @return List<T>
     */
    @Override
    public List<T> beforeList(List<T> list) {
        return list;
    }
}

4、controller封装

controller的封装一定涉及到统一请求参数、统一返回消息体。统一请求参数在一开始我们就已经介绍。包括统一返回消息体,都是自有封装,针对自己业务需要即可。代码就不贴出来了。controller接口、接口实现类代码如下。
需要注意的是@Log、 @ApiOperation两个注解,@Log是我定义的基于spring aspectJ来做的全局log管理。@ApiOperation是swagger注解。如果不需要,直接去掉就好。

import com.nari.ztdz.lockset.mainview.base.vo.PageDataVo;
import com.nari.ztdz.web.WebResponse;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * @author dzx
 */
public interface BaseController<T> {
    /**
     * 根据ID列表删除对象,如果idList 为空或者空列表则直接返回
     *
     * @param ids 要删除对象的ID列表
     * @return WebResponse
     */
    public WebResponse deleteList(Collection<? extends Serializable> ids);

    /**
     * 删除一条记录
     *
     * @param id
     * @return WebResponse
     */
    public WebResponse deleteOne(String id);

    /**
     * 添加一条实体,实体不能为null
     *
     * @param entity 要添加的实体
     * @return WebResponse
     */
    public WebResponse addOne(T entity);

    /**
     * 批量添加
     *
     * @param list 要添加的实体集合
     * @return WebResponse
     */
    public WebResponse addBatch(List<T> list);

    /**
     * 查询对象列表
     *
     * @param pageDataVo 查询对象
     * @return WebResponse
     */
    public WebResponse selectListByPage(PageDataVo<T> pageDataVo);

    /**
     * 查询所有
     *
     * @param entity 查询对象
     * @return WebResponse
     */
    public WebResponse selectList(T entity);

    /**
     * 根据ID查询一个对象
     *
     * @param id 不能为null
     * @return WebResponse
     */
    public WebResponse viewOne(String id);

    /**
     * @param entity 要更新的实体
     * @return WebResponse
     */
    public WebResponse editOne(T entity);


}

import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nari.ztdz.lockset.annotation.Log;
import com.nari.ztdz.lockset.mainview.base.service.IBaseService;
import com.nari.ztdz.lockset.mainview.base.vo.PageDataVo;
import com.nari.ztdz.web.WebResponse;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * <p>
 * 封装的公共controller,如果需要重写。可以有两种方式:
 * 一、在controllerl类中直接重写baseController的方法
 * 二、重写当前继承了IBaseService的service代码
 * <p/>
 *
 * @param <T> 当前业务对象的实体类泛型;
 * @param <B> 当前业务对象的service;
 * @author dzx
 */
@Slf4j
@RestController
public abstract class BaseControllerImpl<T, B extends IBaseService<T>> implements BaseController<T> {

    /**
     * 获取基础的服务
     */
    @Autowired
    protected B baseService;

    @Log("批量删除")
    @RequestMapping(value = "/deleteByIds", method = RequestMethod.POST)
    @Override
    @ApiOperation(value = "批量删除")
    public WebResponse deleteList(Collection<? extends Serializable> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            log.error("要删除的ID号为null或空字符串!对象:{}", this.getClass().getName());
            return WebResponse.FAILED;
        }
        boolean flag = baseService.removeByIds(ids);
        if (flag) {
            return new WebResponse();
        }
        log.error("删除失败!对象:{}", this.getClass().getName());
        return WebResponse.FAILED;
    }

    @Log("主键删除")
    @Override
    @PostMapping(value = "/deleteById")
    @ApiOperation(value = "主键删除")
    public WebResponse deleteOne(String id) {
        if (StringUtils.isEmpty(id)) {
            log.error("要删除的ID号为null或空字符串!对象:{}", this.getClass().getName());
            return WebResponse.FAILED;
        }
        boolean flag = baseService.removeById(id);
        if (flag) {
            return new WebResponse();
        }
        log.error("删除失败!对象:{}", this.getClass().getName());
        return WebResponse.FAILED;
    }

    @Log("新增")
    @PostMapping(value = "/add")
    @Override
    @ApiOperation(value = "新增")
    public WebResponse addOne(@RequestBody T entity) {
        boolean flag = baseService.save(entity);
        if (flag) {
            return new WebResponse("新增成功!");
        }
        return WebResponse.FAILED;
    }

    @Log("批量新增")
    @PostMapping(value = "/addBatch")
    @Override
    @ApiOperation(value = "批量新增")
    public WebResponse addBatch(@RequestBody List<T> list) {
        boolean flag = baseService.saveBatch(list);
        if (flag) {
            return new WebResponse("新增成功!");
        }
        return WebResponse.FAILED;
    }

    @Log("分页查询")
    @PostMapping("/list")
    @Override
    @ApiOperation(value = "分页查询")
    public WebResponse selectListByPage(@RequestBody PageDataVo<T> pageDataVo) {
        Page<T> page = baseService.queryPageByCond(pageDataVo);
        return WebResponse.data(page);
    }

    @Log("查询所有")
    @PostMapping("/getAll")
    @Override
    @ApiOperation(value = "查询所有")
    public WebResponse selectList(@RequestBody T entity) {
        Class<? extends BaseControllerImpl> aClass = this.getClass();
        List<T> list = baseService.list(new QueryWrapper<T>(entity));
        return WebResponse.data(list);
    }

    @Log("详情")
    @PostMapping("/info")
    @Override
    @ApiOperation(value = "详情")
    public WebResponse viewOne(String id) {
        return WebResponse.data(baseService.getById(id));
    }

    @Log("修改")
    @PostMapping("/update")
    @Override
    @ApiOperation(value = "修改")
    public WebResponse editOne(@RequestBody T entity) {
        boolean flag = baseService.updateById(entity);
        if (flag) {
            return new WebResponse("更新成功!");
        }
        return WebResponse.FAILED;
    }

}

5、具体使用demo

dao
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 *
 * </p>
 *
 * @author czx
 * @since 2020-11-12
 */
@Data
@EqualsAndHashCode(callSuper = true)
@KeySequence(value = "SEQ_SYS_DICT_ID", clazz = Integer.class)
@Accessors(chain = true)
@TableName("SYS_DICT")
@ApiModel(value = "SysDict对象")
public class SysDict extends Model<SysDict> {

    private static final long serialVersionUID = 1L;

    @TableField("ID")
    private String id;

    @TableField("SORT")
    private Integer sort;

    @TableField("LABEL")
    private String label;

    @TableField("VALUE")
    private String value;

    @TableField("TYPE_ID")
    private String typeId;


}

import com.nari.ztdz.lockset.mainview.base.mapper.IBaseMapper;
import com.nari.ztdz.lockset.mainview.sys.po.SysDict;

/**
 * <p>
 * Mapper 接口
 * </p>
 *
 * @author czx
 * @since 2020-11-12
 */
public interface SysDictMapper extends IBaseMapper<SysDict> {

}

service

import com.nari.ztdz.lockset.mainview.base.service.IBaseService;
import com.nari.ztdz.lockset.mainview.sys.po.SysDict;

import java.util.List;

/**
 * <p>
 * 服务类
 * </p>
 *
 * @author czx
 * @since 2020-11-12
 */
public interface ISysDictService extends IBaseService<SysDict> {

}

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nari.ztdz.lockset.mainview.base.service.IBaseServiceImpl;
import com.nari.ztdz.lockset.mainview.sys.mapper.SysDictMapper;
import com.nari.ztdz.lockset.mainview.sys.mapper.SysDictTypeMapper;
import com.nari.ztdz.lockset.mainview.sys.po.SysDict;
import com.nari.ztdz.lockset.mainview.sys.po.SysDictType;
import com.nari.ztdz.lockset.mainview.sys.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author czx
 * @since 2020-11-12
 */
@Service
public class SysDictServiceImpl extends IBaseServiceImpl<SysDictMapper, SysDict> implements ISysDictService {
   
}
controller
import cn.hutool.core.util.StrUtil;
import com.nari.ztdz.lockset.mainview.base.controller.BaseControllerImpl;
import com.nari.ztdz.lockset.mainview.sys.po.SysDict;
import com.nari.ztdz.lockset.mainview.sys.service.ISysDictService;
import com.nari.ztdz.web.WebResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author czx
 * @since 2020-11-12
 */
@Api(tags = "数组字典")
@RestController
@RequestMapping("/dict")
public class SysDictController extends BaseControllerImpl<SysDict, ISysDictService> {
    
}

总结

其实这个后台封装,如果配合代码生成,以及前端封装,几乎可以实现简单业务逻辑不用任何代码。可以高效提升开发效率。使我们有足够的精力去面向业务。目前因为时间问题,说白了就是懒。。也因为个人技术水平有限,希望大家指正文中纰漏或不合理的地方。

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是基于Spring BootMyBatis Plus框架搭建的MySQL前后端增删改查的完整示例代码: 1. 在pom.xml文件中添加相关依赖: ```xml <dependencies> <!-- Spring Boot Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MyBatis Plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency> <!-- MySQL Connector --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.26</version> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> </dependencies> ``` 2. 创建数据库表和相关实体类 ```sql CREATE DATABASE IF NOT EXISTS `test`; USE `test`; CREATE TABLE IF NOT EXISTS `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `name` varchar(30) NOT NULL COMMENT '姓名', `age` int(3) NOT NULL COMMENT '年龄', `email` varchar(50) NOT NULL COMMENT '邮箱', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; INSERT INTO `user` (`name`, `age`, `email`) VALUES ('Tom', 18, 'tom@example.com'); INSERT INTO `user` (`name`, `age`, `email`) VALUES ('Jerry', 20, 'jerry@example.com'); ``` 创建实体类User.java: ```java @Data @TableName(value = "user") public class User { @TableId(value = "id", type = IdType.AUTO) private Integer id; private String name; private Integer age; private String email; } ``` 3. 创建Mapper接口和对应的Mapper.xml文件 创建UserMapper.java: ```java @Mapper public interface UserMapper extends BaseMapper<User> { } ``` 创建userMapper.xml: ```xml <?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="com.example.demo.mapper.UserMapper"> <resultMap id="BaseResultMap" type="com.example.demo.entity.User"> <id column="id" property="id"/> <result column="name" property="name"/> <result column="age" property="age"/> <result column="email" property="email"/> </resultMap> <sql id="Base_Column_List"> id, name, age, email </sql> <select id="selectById" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from user where id = #{id} </select> <select id="selectAll" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from user </select> <insert id="insert" parameterType="com.example.demo.entity.User"> insert into user(name, age, email) values(#{name}, #{age}, #{email}) </insert> <update id="updateById" parameterType="com.example.demo.entity.User"> update user set name = #{name}, age = #{age}, email = #{email} where id = #{id} </update> <delete id="deleteById" parameterType="java.lang.Integer"> delete from user where id = #{id} </delete> </mapper> ``` 4. 创建Service接口和实现类 创建UserService.java: ```java public interface UserService { User selectById(int id); List<User> selectAll(); boolean insert(User user); boolean updateById(User user); boolean deleteById(int id); } ``` 创建UserServiceImpl.java: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public User selectById(int id) { return userMapper.selectById(id); } @Override public List<User> selectAll() { return userMapper.selectList(null); } @Override public boolean insert(User user) { return userMapper.insert(user) > 0; } @Override public boolean updateById(User user) { return userMapper.updateById(user) > 0; } @Override public boolean deleteById(int id) { return userMapper.deleteById(id) > 0; } } ``` 5. 创建Controller类和接口 创建UserController.java: ```java @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/select") public User selectById(@RequestParam("id") Integer id) { return userService.selectById(id); } @GetMapping("/list") public List<User> selectAll() { return userService.selectAll(); } @PostMapping("/insert") public boolean insert(User user) { return userService.insert(user); } @PostMapping("/update") public boolean updateById(User user) { return userService.updateById(user); } @PostMapping("/delete") public boolean deleteById(@RequestParam("id") Integer id) { return userService.deleteById(id); } } ``` 至此,一个基于Spring BootMyBatis Plus框架的MySQL前后端增删改查的完整示例代码就完成了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值