Spring Boot使用Mybatis-plus和它的程式碼生成器

playboy5566發表於2022-01-13

Spring Boot使用Mybatis-plus和它的程式碼生成器

這篇文章第一部分講解Mybatis-plus的使用。點下面的連結可前往官網。

但要注意的是。使用它僅是為了快速開發,因為sql優化的第一點就是sql語句裡的select 不應直接寫 * 也就是查詢全部,而是應該寫上每一個要用的欄位。

第二部分寫Mybatis-plus裡的程式碼生成器,首先程式碼生成的程式碼實際上直接用Mybatis-plus官網裡的範例就可以了,但要把生成的程式碼變成自己想要的樣子,還是需要自己修改模板程式碼,所以這篇文章會展示出我現在使用的模板。

文章目錄:

  1. Mybatis-Plus 使用
  2. 程式碼生成器

Mybatis-Plus使用

pom.xml 中所需新增的依賴

// Mybatis-Plus的包
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.1.tmp</version>
    </dependency>
    // 程式碼構造器的包
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-generator</artifactId>
        <version>3.3.1.tmp</version>
    </dependency>
    // 使用的頁面模板是freemarker
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.30</version>
    </dependency>
    // lombok的包,建議下載外掛,不下載外掛程式碼會帶紅,但可以執行
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    // 使用pagehelper來分頁,Mybatis-plus有分頁的Api,使用與否看自己
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.2.10</version>
    </dependency>
    // 如果打算使用swagger新增下面兩個註解
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>

下面是專案結構和程式碼 其中exception,config,until不是涉及這篇教程

在這裡插入圖片描述

Application.java

@EnableCaching
// 掃描mapper資料夾
@MapperScan("com.generator.mapper")
@SpringBootApplication
public class GeneratorApplication {

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

}

實體類entity

@Data
// 這個如果是true的話在equal時要考慮其父類,因為這個類是沒父類的所以為false
// 我建議這個地方大家去了解以下,和equals()這個方法有關,涉及到父類與子類的.equals()
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
//下面這個註解是swagger的
@ApiModel(value="UserInfo物件", description="")
public class UserInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    // 下面這個是Mybatis-Plus的註解,主鍵宣告,自動增長
    @TableId(value = "user_id", type = IdType.AUTO)
    private Integer userId;

    private String pwd;

    private String userName;

    private String userRealName;

    private String telephone;
    // swagger註解
    @ApiModelProperty(value = "使用者職業")
    private String userPro;


}

service包下的

// 此處需要繼承IService<Entity>,來獲得Mybatis-plus裡的方法。
// 這裡其實是可以不用寫下面這些,因為Mybatis-plus內部就有相應的select這些方法,相關請自己看官方文件
// 但我還是建議用自己設計的方法,可呼叫性更高
public interface IUserInfoService extends IService<UserInfo> {

    /**
     * 查詢 userInfo
     * @param userInfo
     * @param pageStart
     * @param pageSize
     * @return
     */
    List<UserInfo> findUserInfo(UserInfo userInfo, Integer pageStart, Integer pageSize);

    /**
     * 新增 userInfo
     * @param userInfo
     * @return
     */
    int insertUserInfo(UserInfo userInfo);

    /**
     * 修改 userInfo
     * @param userInfo
     * @return
     */
    int updateUserInfo(UserInfo userInfo);

    /**
     * 刪除 userInfo
     * @param id
     * @return
     */
    int deleteUserInfo(int id);

}

service包裡的impl資料夾下

// 宣告是一個Service服務類,繼承ServiceImpl<Entity>使用Mybatis-plus裡的方法
// 實現IUserInfoService裡宣告的介面
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements IUserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public List<UserInfo> findUserInfo(UserInfo userInfo, Integer pageStart, Integer pageSize) {
        /*
        這個是呼叫QueryWrapper裡的 eq 這類的方法來自己構建一個sql語句
        QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("userName",userInfo.getUserName());
        */
        // 使用QueryWrapper條件構造器,此處是將物件直接存入,還有別的使用方法,裡面直接根據情況呼叫eq這些api命令
        QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>(userInfo);
        // 使用pagehelper來分頁
        PageHelper.startPage(pageStart,pageSize);
        // 呼叫ServiceImpl裡的selectList方法
        return userInfoMapper.selectList(queryWrapper);
    }

    @Override
    public int insertUserInfo(UserInfo userInfo) {
        return userInfoMapper.insert(userInfo);
    }

    @Override
    public int updateUserInfo(UserInfo userInfo) {
        return userInfoMapper.updateById(userInfo);
    }

    @Override
    public int deleteUserInfo(int id) {
        return userInfoMapper.deleteById(id);
    }


}

mapper資料夾下

// 宣告是一個介面,繼承BaseMapper<Entity>
@Repository
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    // 此處加自定義的mapper
}

resources下的mapper資料夾

<?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.generator.mapper.UserInfoMapper">

</mapper>

controller資料夾下

// swagger註解
@Api(tags = "UserInfoController", description = "使用者管理")
@RestController
@RequestMapping("/user-info")
public class UserInfoController {

    //這裡我是以介面來宣告一個變數,可直接使用service來宣告
    @Autowired
    private IUserInfoService userInfoService;
    
    // swagger註解
    @ApiOperation("查詢使用者")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public RespBody findUserInfo(UserInfo userInfo,
                                 @RequestParam(value = "pageStart",defaultValue = "1")Integer pageStart,
                                 @RequestParam(value = "pageSize", defaultValue = "10")Integer pageSize){
        List<UserInfo> userInfoList = userInfoService.findUserInfo(userInfo, pageStart, pageSize);
        // pagehelper的返回類
        PageInfo<UserInfo> pageInfo = new PageInfo<>(userInfoList);
        return RespBody.ok(pageInfo);
    }

    @ApiOperation("新增使用者")
    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    public RespBody insertUserInfo(UserInfo userInfo) {
        int result = userInfoService.insertUserInfo(userInfo);
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

    @ApiOperation("修改使用者")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public RespBody updateUserInfo(UserInfo userInfo) {
        int result = userInfoService.updateUserInfo(userInfo);
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

    @ApiOperation("刪除使用者")
    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public RespBody updateUserInfo(@RequestParam("id")int id) {
        int result = userInfoService.deleteUserInfo(id);
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

}

到此,上面就是使用我設計模板生成的相應程式碼了

我的Mybatis-plus程式碼生成器

程式碼

// 做出了一些修改,但總體上與官網裡的程式碼相同
public class CodeGenerator {

    /**
     * <p>
     * 讀取控制檯內容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        //輸入模組名
        help.append("請輸入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("請輸入正確的" + tip + "!");
    }

    public static void main(String[] args) {
        // 程式碼生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全域性配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        // 輸出的路徑
        gc.setOutputDir(projectPath + "/src/main/java");
        // 作者
        gc.setAuthor("dell");
        gc.setOpen(false);
        //  是否使用實體屬性 Swagger2 註解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // mysql資料來源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/mall?serverTimezone=GMT%2B8&characterEncoding=UTF-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("*****");
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        // pc.setModuleName(scanner("模組名")); 示例中有一個輸入模組名的步驟,我捨去了
        // 設定字首名
        pc.setParent("com.generator");
        mpg.setPackageInfo(pc);

        String myName = scanner("資料名:例(userInfo)");
        String myTitle = scanner("模組名:例(使用者)"); 
        // 自定義配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // 可看作設定了幾個全域性量,用於將自己模板生成的描述更好,在模板中的使用方法${cfg.myName}
                Map<String, Object> map = new HashMap<>();
                map.put("myName", myName);
                map.put("myTitle", myTitle);
                this.setMap(map);
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 自定義輸出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定義配置會被優先輸出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 這裡是resources裡的mapper.xml
                return projectPath + "/src/main/resources/mapper/"
                        + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });

        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        // 配置自定義輸出模板,不寫下面的程式碼就是使用預設的模板輸出。
        // 模板位置找到mybatis-plus-generator包開啟templates,下面還會有一張圖
        templateConfig.setService("templates/service2.java");
        templateConfig.setController("templates/controller2.java");
        templateConfig.setServiceImpl("templates/serviceImpl2.java");
        templateConfig.setMapper("templates/mapper2.java");
        
        // 如果向生成的xml裡也有程式碼設定路徑,我沒有設定
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置,駱峰這類的設定
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);

        //選擇是否有父類實體
        String ipt = scanner("請輸入是否選擇父類實體,1為沒有,否則請輸入父類");
        if (!("1".equals(ipt))) {
            //設定父類實體
            strategy.setSuperEntityClass(ipt);
        }

        // 是否使用Lombok的方式
        strategy.setEntityLombokModel(true);
        // 是否使用RestController
        strategy.setRestControllerStyle(true);
        //公共父類strategy.setSuperControllerClass("你自己的父類控制器,沒有就不用設定!");
        //寫於父類中的公共欄位
        strategy.setSuperEntityColumns("id");
        
        // 輸入相關的名稱
        strategy.setInclude(scanner("表名,多個英文逗號分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

預設模板位置

在這裡插入圖片描述

執行示例

在這裡插入圖片描述

最後放上模板程式碼

將模板放入resources下的templates裡
controller2.java.ftl

package ${package.Controller};
// 這個地方請自己改動,改成自己的路徑
import com.generator.entity.RespBody;

import com.generator.entity.${entity};
import com.generator.service.${table.serviceName};

import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>

/**
 * <p>
    * ${table.comment!} 前端控制器
    * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Api(tags = "${table.controllerName}", description = "${cfg.myTitle}管理")
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
@RequestMapping("<#if package.ModuleName??>/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle??>${controllerMappingHyphen}<#else>${table.entityPath}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
    <#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
    <#else>
public class ${table.controllerName} {
    </#if>

    @Autowired
    private ${table.serviceName} ${cfg.myName}Service;

    @ApiOperation("查詢${cfg.myTitle}")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public RespBody find${entity}(${entity} ${cfg.myName},
                                 @RequestParam(value = "pageStart",defaultValue = "1")Integer pageStart,
                                 @RequestParam(value = "pageSize", defaultValue = "10")Integer pageSize){
        List<${entity}> ${cfg.myName}List = ${cfg.myName}Service.find${entity}(${cfg.myName}, pageStart, pageSize);
        PageInfo<${entity}> pageInfo = new PageInfo<>(${cfg.myName}List);
        return RespBody.ok(pageInfo);
    }

    @ApiOperation("新增${cfg.myTitle}")
    @RequestMapping(value = "/insert", method = RequestMethod.POST)
    public RespBody insert${entity}(${entity} ${cfg.myName}) {
        int result = ${cfg.myName}Service.insert${entity}(${cfg.myName});
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

    @ApiOperation("修改${cfg.myTitle}")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public RespBody update${entity}(${entity} ${cfg.myName}) {
        int result = ${cfg.myName}Service.update${entity}(${cfg.myName});
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

    @ApiOperation("刪除${cfg.myTitle}")
    @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
    public RespBody update${entity}(@RequestParam("id")int id) {
        int result = ${cfg.myName}Service.delete${entity}(id);
        if (result == 1) {
            return RespBody.ok();
        }
        return RespBody.error();
    }

}
</#if>

service2.java.ftl

package ${package.Service};

import ${package.Entity}.${entity};
import ${superServiceClassPackage};

import java.util.List;

/**
 * <p>
    * ${table.comment!} 服務類
    * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if kotlin>
interface ${table.serviceName} : ${superServiceClass}<${entity}>
<#else>
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {

    /**
     * 查詢 ${cfg.myName}
     * @param ${cfg.myName}
     * @param pageStart
     * @param pageSize
     * @return
     */
    List<${entity}> find${entity}(${entity} ${cfg.myName}, Integer pageStart, Integer pageSize);

    /**
     * 新增 ${cfg.myName}
     * @param ${cfg.myName}
     * @return
     */
    int insert${entity}(${entity} ${cfg.myName});

    /**
     * 修改 ${cfg.myName}
     * @param ${cfg.myName}
     * @return
     */
    int update${entity}(${entity} ${cfg.myName});

    /**
     * 刪除 ${cfg.myName}
     * @param id
     * @return
     */
    int delete${entity}(int id);

}
</#if>

serviceImpl2.java.ftl

package ${package.ServiceImpl};

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service}.${table.serviceName};
import ${superServiceImplClassPackage};
import org.springframework.stereotype.Service;

/**
 * <p>
    * ${table.comment!} 服務實現類
    * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Service
<#if kotlin>
open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {

}
<#else>
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {

    @Autowired
    private ${table.mapperName} ${cfg.myName}Mapper;

    @Override
    public List<${entity}> find${entity}(${entity} ${cfg.myName}, Integer pageStart, Integer pageSize) {
        //這裡根據具體的條件進行擴充
        QueryWrapper<${entity}> queryWrapper=new QueryWrapper<>(${cfg.myName});
        PageHelper.startPage(pageStart,pageSize);
        return ${cfg.myName}Mapper.selectList(queryWrapper);
    }

    @Override
    public int insert${entity}(${entity} ${cfg.myName}) {
        return ${cfg.myName}Mapper.insert(${cfg.myName});
    }

    @Override
    public int update${entity}(${entity} ${cfg.myName}) {
        return ${cfg.myName}Mapper.updateById(${cfg.myName});
    }

    @Override
    public int delete${entity}(int id) {
        return ${cfg.myName}Mapper.deleteById(id);
    }

}
</#if>

mapper2.java.ftl

package ${package.Mapper};

import ${package.Entity}.${entity};
import ${superMapperClassPackage};
import org.springframework.stereotype.Repository;

/**
 * <p>
    * ${table.comment!} Mapper 介面
    * </p>
 *
 * @author ${author}
 * @since ${date}
 */
<#if kotlin>
interface ${table.mapperName} : ${superMapperClass}<${entity}>
<#else>
@Repository
public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {

}
</#if>

更近一步,相關api的使用還是要看官方文件Mybatis-plus才可以。

相關文章