为什么不尝试自己做代码生成(基于plus版)

代码生成效果:

image-20220517205419278

说明:

本文均以velocity模板演示,其余模板只是语法不同

参考博客 Mybatis-plus最新代码生成器(3.5.1+)的使用时你需要改为使用velocity模板

1.准备工作和目标效果

如果你了解过velocity模板引擎(不了解也没关系),这篇博文不错 Velocity模板引擎

请先阅读此博客(2分钟): Mybatis-plus最新代码生成器(3.5.1+)的使用

构建好操作环境

1.1 首先找到plus的模板在哪

外部包-----找到plus的generator包-----templates下vm后缀的模板就是velocity的模板了

image-20220517110125960

##1.2 以controller.java.vm为例

首先复制一份到你的resource/templates目录下,打开如下:

image-20220517111300070

1.2.1先看下它现在这个controller模板生成的controller大致是啥样的

这是我生成的用户controller

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author 向培
 * @since 2022-04-05
 */
@Controller
@RequestMapping("/sysUser")
public class SysUserController {

}

很简陋对吧,我们肯定是想要把增删改查接口都写上对吧。

先拿我想要的结果来看:

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author 向培
 * @since 2022-04-07
 */
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping("/sys-menu")
@Api(value = "菜单", tags = "菜单")
public class SysMenuController {

    private final SysMenuService menuService;

    @PostMapping("/")
    @ApiOperation(value = "添加菜单", notes = "添加菜单")
    public ResponseData addMenu(@RequestBody @Validated SysMenuForm form) {
        return menuService.addMenu(form);
    }

    @PutMapping("/")
    @ApiOperation(value = "修改菜单", notes = "修改菜单")
    public ResponseData editMenu(@RequestBody @Validated SysMenuForm form) {
        return menuService.editMenu(form);
    }

    @DeleteMapping("/{menu_id}")
    @ApiOperation(value = "删除菜单", notes = "删除菜单")
    public ResponseData deleteMenu(@PathVariable("menu_id") String menuId) {
        return menuService.deleteMenu(menuId);
    }

    @GetMapping("/page")
    @ApiOperation(value = "菜单分页", notes = "菜单分页")
    public ResponseData menuPage(SysMenuForm form) {
        return menuService.selectMenuByPage(form);
    }

    @GetMapping("/{menu_id}")
    @ApiOperation(value = "id查找", notes = "id查找")
    public ResponseData menuPage(@PathVariable("menu_id") String menuId) {
        return menuService.selectMenuById(menuId);
    }
}

下面我们就把plus默认的模板改造成我们想要的吧!不了解velocity的语法也是没关系的!

2.入手点

如果你点进我前面推荐的关于velocity的文章,那么你应该知道了最后生成的代码是通过模板与数据合并实现的。

ok,原理就是这个,那么plus肯定也只能这样做。

所以,一定有一个类的某个方法会执行这个合并操作。

2.1查看引入的包

经过我的查看,一个叫VelocityTemplateEngine的类就是搞这个的。

包目录----plus的generator包-----engine下面的VelocityTemplateEngine

image-20220517112637631

其中的write方法为关键:

@Override
public void writer(@NotNull Map<String, Object> objectMap, @NotNull String templatePath, @NotNull File outputFile) throws Exception {
    Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8);
    try (FileOutputStream fos = new FileOutputStream(outputFile);
         OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8);
         BufferedWriter writer = new BufferedWriter(ow)) {
        template.merge(new VelocityContext(objectMap), writer);
    }
}

参数objectMap即为数据模型

参数templatePath即为模板所在路径

怎么样?恍然大悟吧,它两执行merge操作就可以生成代码文件了

2.2了解objectMap

为了能更好的帮助我们修改模板,我们需要知道objectMap里面都有哪些数据可供我们使用。

打个断点,

image-20220517113340153

debug运行代码生成工具,如果你没有代码生成工具类,可以看看我的这篇文章,代码在最后,复制即用(表和数据库需要自己弄):

Mybatis-plus最新代码生成器(3.5.1+)的使用

进入断点:可以看到东西还是很多的

image-20220517113832024

这里我们不必太关心truefalse这些键值对,它们大都用于模板中的if判断。

你需要的时候看看就知道了,这不是我们关注的重点。

哪些是重点?

比如table、package这些value为对象的key:

image-20220517114355094

了解了这些东西之后,我们才能知道通过哪些对象可以点出哪些属性供我们使用!!!

objectMap中的所有键值对都能在模板中使用!!!

3.修改模板

3.1梳理一下需求

image-20220517115103387

3.2打开你复制的模板做修改

这里作者有一个小建议,那就是断点不要放行,以便于修改模板的同时能查看objectMap有哪些可用数据


之前生成的代码需要删除掉,不然不会进入断点

首先把效果图中的代码复制到模板中,然后再根据需求改动:

减少篇幅,展示部分代码

public class ${table.controllerName} {
#end

    private final SysMenuService menuService;

    @PostMapping("/")
    @ApiOperation(value = "添加菜单", notes = "添加菜单")
    public ResponseData addMenu(@RequestBody @Validated SysMenuForm form) {
        return menuService.addMenu(form);
    }

    @PutMapping("/")
    @ApiOperation(value = "修改菜单", notes = "修改菜单")
    public ResponseData editMenu(@RequestBody @Validated SysMenuForm form) {
        return menuService.editMenu(form);
    }

    @DeleteMapping("/{menu_id}")
    @ApiOperation(value = "删除菜单", notes = "删除菜单")
    public ResponseData deleteMenu(@PathVariable("menu_id") String menuId) {
        return menuService.deleteMenu(menuId);
    }

    @GetMapping("/page")
    @ApiOperation(value = "菜单分页", notes = "菜单分页")
    public ResponseData menuPage(SysMenuForm form) {
        return menuService.selectMenuByPage(form);
    }

    @GetMapping("/{menu_id}")
    @ApiOperation(value = "id查找", notes = "id查找")
    public ResponseData menuPage(@PathVariable("menu_id") String menuId) {
        return menuService.selectMenuById(menuId);
    }
}
#end

3.2.1添加注解

1.@Validated 数据校验

2.@RequiredArgsConstructor 构造器

3.@Api(value = “菜单”, tags = “菜单”) 、 @ApiOperation(value = “修改菜单”, notes = “修改菜单”) swagger

这些是死代码,直接把import语句复制进来,注解加上就行了

image-20220517153642852

需要注意的是,因为是死代码,添加的时候不要放到if语句中,不然可能失效。

需要处理的地方就是@Api(value = "菜单")这个菜单是动态内容,需要改

看看,objectMap的数据呢:这个我们可以直接定位到在table里面

image-20220517154534631

好像没有这样的中文,但是我们可以使用这个comment属性,就是数据库表的注释,现在没有,那就去加一个

image-20220517154749591

放行断点、删除生成的文件,重新debug

image-20220517154910714

可以了,修改模板:

@Api(value = "${table.comment}", tags = "${table.comment}")

ok,生成代码看看效果:

image-20220517155434998

没有问题!


下面就该修改service注入了:

private final SysMenuService menuService;

很明显啊,我们看controller的名字:

image-20220517155911934

那么Service的名字也肯定在table里面:都在这里面了

image-20220517160018398

private final ${table.serviceName} menuService;

那么问题来了,这个小写开头的menuService我们改怎么处理呢?

在模板中是无法调用String这些api的,所以我们需要写一个类继承VelocityTemplateEngine,重写write方法,然后做自定义操作:

public class MyVelocityTemplateEngine extends VelocityTemplateEngine {

    @Override
    public void writer(Map<String, Object> objectMap, String templatePath, File outputFile) throws Exception {
        // 取出Service接口的名字,进行首字母小写处理
        TableInfo tableInfo = (TableInfo) objectMap.get("table");
        String first = tableInfo.getServiceName().substring(0,1).toLowerCase();
        String firstToLower = first + tableInfo.getServiceName().substring(1);
        objectMap.put("firstToLowerService", firstToLower);
        
        super.writer(objectMap, templatePath, outputFile);
    }
}

需要注意的是这个TableInfo是来自这个包下:

import com.baomidou.mybatisplus.generator.config.po.TableInfo;

然后将代码生成工具类的最后位置改一下:改成自定义的类

image-20220517170750014

再次debug运行,看看:

image-20220517170904452

没问题了,再改改模板:

import ${package.Service}.${table.ServiceName};

private final ${table.serviceName} ${firstToLowerService};

顺势而为,把@ApiOperation和方法名改了:

@PostMapping("/")
@ApiOperation(value = "添加${table.comment}", notes = "添加${table.comment}")
public ResponseData add${table.entityName}(@RequestBody @Validated SysMenuForm form) {
    return menuService.add${table.entityName}(form);
}

@PutMapping("/")
@ApiOperation(value = "修改${table.comment}", notes = "修改${table.comment}")
public ResponseData edit${table.entityName}(@RequestBody @Validated SysMenuForm form) {
    return menuService.edit${table.entityName}(form);
}

@DeleteMapping("/{menu_id}")
@ApiOperation(value = "删除${table.comment}", notes = "删除${table.comment}")
public ResponseData delete${table.entityName}(@PathVariable("menu_id") String menuId) {
    return menuService.delete${table.entityName}(menuId);
}

@GetMapping("/page")
@ApiOperation(value = "${table.comment}分页", notes = "${table.comment}分页")
public ResponseData ${table.entityName}Page(SysMenuForm form) {
    return menuService.select${table.entityName}ByPage(form);
}

@GetMapping("/{menu_id}")
@ApiOperation(value = "id查找", notes = "id查找")
public ResponseData ${table.entityName}Page(@PathVariable("menu_id") String menuId) {
    return menuService.select${table.entityName}ById(menuId);
}

生成效果:

@PostMapping("/")
@ApiOperation(value = "添加系统菜单", notes = "添加系统菜单")
public ResponseData addSysMenu(@RequestBody @Validated SysMenuForm form) {
    return menuService.addSysMenu(form);
}

@PutMapping("/")
@ApiOperation(value = "修改系统菜单", notes = "修改系统菜单")
public ResponseData editSysMenu(@RequestBody @Validated SysMenuForm form) {
    return menuService.editSysMenu(form);
}

@DeleteMapping("/{menu_id}")
@ApiOperation(value = "删除系统菜单", notes = "删除系统菜单")
public ResponseData deleteSysMenu(@PathVariable("menu_id") String menuId) {
    return menuService.deleteSysMenu(menuId);
}

@GetMapping("/page")
@ApiOperation(value = "系统菜单分页", notes = "系统菜单分页")
public ResponseData SysMenuPage(SysMenuForm form) {
    return menuService.selectSysMenuByPage(form);
}

@GetMapping("/{menu_id}")
@ApiOperation(value = "id查找", notes = "id查找")
public ResponseData SysMenuPage(@PathVariable("menu_id") String menuId) {
    return menuService.selectSysMenuById(menuId);
}

小结

由于篇幅原因,打算分开来说。

以上演示还有较多的”小毛病“,比如分页的方法名是大写开头(当然,你完全可以通过修改${table.entityName}Page来避免,比如改为page${table.entityName}

还有@DeleteMapping("/{menu_id}")这个menu_id你完全可以使用id替换,直接写死,省事。我就先不改了

还有,@RequestBody @Validated SysMenuForm form这个对象SysMenuForm 你也需要写一个模板生成它,然后在controller中引用它,(在自定义MyVelocityTemplateEngine可以办到)

总结经验

1.你想在模板中使用的属性,先去objectMap中找找(推荐方式:打个断点不放行,可以边修改模板边看objectMap的内容有哪些)

2.objectMap中没有的、你想自己加一些东西的,可以通过继承VelocityTemplateEngine,重写write方法。往objectMap中put数据

虽然本文只讲述了如何生成controller,但是其思路是通用的!

我也会持续更新至controller、service、mapper等模板修改。前端vue可能也会哦~~

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了我的架构师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值