Skip to content

代码生成器

在 framework-generator util 文件夹下有个CodeGenerator类,部分代码如下:

java
public static void main(String[] args) {
    FastAutoGenerator.create(url, username, password)
            .globalConfig(builder -> {
                builder.author(author)
                        .commentDate(DatePattern.NORM_DATETIME_PATTERN)
                        .enableSwagger()
                        .disableOpenDir()
                        .outputDir(outputDir);
            })
            .dataSourceConfig(builder -> builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                if (typeCode == Types.SMALLINT) {
                    // 自定义类型转换
                    return DbColumnType.INTEGER;
                }
                return typeRegistry.getColumnType(metaInfo);
            }).keyWordsHandler(new MySqlKeyWordsHandler()))
            .packageConfig(builder -> {
                builder.parent(parentPackageName) // 设置父包名
                        .moduleName(moduleName) // 设置父包模块名
                        .entity("core.entity")
                        .mapper("dao.mapper")
                        .pathInfo(Collections.singletonMap(OutputFile.xml, Paths.get(
                                outputDir,
                                parentPackageName.replace(".", "//"),
                                moduleName,
                                "dao").toString())); // 设置mapperXml生成路径
            })
            .injectionConfig(consumer -> {
                Map<String, Object> customMap = new HashMap<>();
                customMap.put("Dto", "service.dto");
                customMap.put("Core", "core");
                consumer.customMap(customMap);

                List<CustomFile> customFileList = new ArrayList<>();
                customFileList.add(new CustomFile.Builder()
                        .fileName("AddDto")
                        .templatePath("/templates/addDto.java.ftl")
                        .enableFileOverride()
                        .packageName((String) customMap.get("Dto"))
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName("UpdateDto")
                        .templatePath("/templates/updateDto.java.ftl")
                        .enableFileOverride()
                        .packageName((String) customMap.get("Dto"))
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName("Dto")
                        .templatePath("/templates/outputDto.java.ftl")
                        .enableFileOverride()
                        .packageName((String) customMap.get("Dto"))
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName("Query")
                        .templatePath("/templates/query.java.ftl")
                        .enableFileOverride()
                        .packageName(customMap.get("Core") + ".query")
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName(StrUtil.EMPTY)
                        .templatePath("/templates/core.java.ftl")
                        .enableFileOverride()
                        .packageName(customMap.get("Core") + ".core")
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName("Repository")
                        .templatePath("/templates/repository.java.ftl")
                        .enableFileOverride()
                        .packageName(customMap.get("Core") + ".repository")
                        .build());
                customFileList.add(new CustomFile.Builder()
                        .fileName("RepositoryImpl")
                        .templatePath("/templates/repositoryImpl.java.ftl")
                        .enableFileOverride()
                        .packageName("dao.repository")
                        .build());
                consumer.customFile(customFileList);
            })
            .strategyConfig(builder -> {
                builder.entityBuilder()
                        .addIgnoreColumns(
                                "id",
                                "create_user",
                                "gmt_created",
                                "gmt_modified",
                                "modify_user",
                                "version",
                                "deleted"
                        )
                        .enableFileOverride()
                        .enableTableFieldAnnotation()
                        .formatFileName("%sPO")
                        .build();
                builder.controllerBuilder()
                        .superClass("com.wmeimob.infra.common.web.BaseController")
                        .enableRestStyle()
                        .enableHyphenStyle()
                        .enableFileOverride()
                        .build();
                builder.serviceBuilder()
                        .superServiceImplClass("com.wmeimob.infra.common.context.ApplicationService")
                        .formatServiceFileName("%sService")
                        .enableFileOverride()
                        .build();
                builder.mapperBuilder()
                        .superClass("com.wmeimob.spring.boot.mybatis.core.mapper.tk.CrudMapper")
                        .enableFileOverride()
                        .build();
                builder.addInclude(tableNames);
            })
            .templateConfig(builder -> {
                builder
                        .service(basicCurdWithPage ? "/templates/service-page.java" : "/templates/service-crud.java")
                        .serviceImpl("/templates/serviceImpl.java")
                        .controller(basicCurdWithPage ? "/templates/controller-page.java" : "/templates/controller-crud.java")
                        .entity("/templates/entity.java")
                        .mapper("/templates/mapper.java")
                        .build();
            })
            .templateEngine(new EnhanceFreemarkerTemplateEngine())
            .execute();
}

这几个模板文件可以很轻松的修改定制

先看下效果,生成的代码文件长什么样:

java
/**
* 横幅 前端控制器
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
@Api(tags = "banner 管理接口")
@RestController
@RequestMapping("/v1/api/banner")
public class BannerController extends CrudPageController<BannerQuery, BannerAddDto, BannerUpdateDto> {

    private final BannerService bannerService;

    public BannerController(BannerService bannerService) {
        super(bannerService);
        this.bannerService = bannerService;
    }
}
java
/**
*
* 横幅 服务类
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
public interface BannerService extends CrudPageService<BannerQuery, BannerAddDto, BannerUpdateDto> {
}
java
/**
*
* 横幅 服务实现类
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
@Service
@RequiredArgsConstructor
public class BannerServiceImpl extends ApplicationService {

    private final BannerRepository bannerRepository;

    @Override
    public Long add(BannerAddDto dto) {
        Banner banner = new Banner(
            // 业务字段初始化
        );
        this.bannerRepository.saveChanges(banner);
        return banner.getId();
    }

    @Override
    public void update(BannerUpdateDto dto) {
        Banner banner = this.bannerRepository.get(dto.getId());
        // 业务字段变更
        banner.setXXX(dto.getTitle());
        this.bannerRepository.saveChanges(banner);
    }

    @Override
    public BannerDto get(Long id) {
        Banner banner = this.bannerRepository.get(id);
        return BeanCopierUtil.copy(banner.getBannerPO(), BannerDto.class);
    }

    @Override
    public void delete(Long id) {
        Banner banner = this.bannerRepository.get(id);
        banner.setDeleted();
        this.bannerRepository.saveChanges(banner);
    }

    @Override
    public List<BannerDto> list(BannerQuery query) {
        List<Banner> list = this.bannerRepository.list(query);
        return list
                .stream()
                .map(x -> BeanCopierUtil.copy(x.getBannerPO(), BannerDto.class))
                .collect(Collectors.toList());
    }
}
java
/**
 *
 * 横幅 请求添加对象
 *
 * @author xxx
 * @date 2024-05-07 14:47:19
 */
@Getter
@Setter
@ApiModel(value = "BannerAddDto", description = "横幅 请求添加对象")
public class BannerAddDto implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 名称
    */
    @ApiModelProperty("名称", required = true)
    @NotBlank(message = "名称不能为空")
    @Length(max = 32, message = "名称不能超过32个字符")
    private String name;

    /**
     * 图片链接
    */
    @ApiModelProperty("图片链接", required = true)
    @NotBlank(message = "图片链接不能为空")
    @Length(max = 255, message = "图片链接不能超过255个字符")
    private String imgUrl;

}


/**
 *
 * 横幅 请求响应对象
 *
 * @author xxx
 * @date 2024-05-07 14:47:19
*/
@Getter
@Setter
@ApiModel(value = "BannerDto", description = "横幅 请求响应对象")
public class BannerDto extends BannerAddDto implements Serializable, Id {

    private static final long serialVersionUID = 1L;

    /**
    * id
    */
    @ApiModelProperty(value = "id")
    private Long id;
}

/**
*
* 横幅 请求修改对象
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
@Getter
@Setter
@ApiModel(value = "BannerUpdateDto", description = "横幅 请求修改对象")
public class BannerUpdateDto extends BannerAddDto implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
    * id
    */
    @ApiModelProperty(value = "id", hidden = true)
    private Long id;
}
java
/**
 * 横幅 Mapper 接口
 *
 * @author xxx
 * @since 2024-05-07 14:47:19
 */
public interface BannerMapper extends CrudMapper<BannerPO, Long> {

}
java
/**
*
* 横幅
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
@Getter
@Setter
@ToString(callSuper = true)
@Table(name ="banner")
public class BannerPO extends CreationAuditedAggregateRoot implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
    * 名称
    */
    @Column(name = "`name`")
    private String name;

    /**
    * 图片链接
    */
    @Column(name = "img_url")
    private String imgUrl;

    /**
    * 外链类型
    */
    @Column(name = "url_type")
    private Integer urlType;

    /**
    * 外链地址
    */
    @Column(name = "url")
    private String url;

    /**
    * 位置
    */
    @Column(name = "position")
    private String position;

    /**
    * 排序
    */
    @Column(name = "sort")
    private Integer sort;

    /**
    * 显示状态
    */
    @Column(name = "`show`")
    private Boolean show;

}
java
/**
 *
 * 横幅 仓储接口类
 *
 * @author xxx
 * @date 2024-05-07 14:47:19
*/
public interface BannerRepository {

    /**
     * 分页查询
     *
     * @param query query
     * @return List<Banner>
    */
    List<Banner> list(BannerQuery query);

    /**
     * 详情
     *
     * @param id id
    */
    Banner get(Long id);

    /**
     * 数据变更
     *
     * @param banner banner
    */
    void saveChanges(Banner banner);
}
java
/**
*
* 横幅 仓储接口实现类
*
* @author xxx
* @date 2024-05-07 14:47:19
*/
@Repository
@RequiredArgsConstructor
public class BannerRepositoryImpl implements BannerRepository {

    private final BannerMapper bannerMapper;

    /**
    * 分页查询
    *
    * @param query query
    * @return List<Banner>
    */
    @Override
    public List<Banner> list(BannerQuery query) {
        ExampleLambda<BannerPO> exampleLambda = new ExampleLambda<>(BannerPO.class);
        exampleLambda
            // xxx 你的业务条件
            .orderByDesc(BannerPO::getId);
        return this.bannerMapper.selectByExample(exampleLambda.end())
                                            .stream()
                                            .map(Banner::new)
                                            .collect(Collectors.toList());
    }

    /**
    * 详情
    *
    * @param id id
    */
    @Override
    public Banner get(Long id) {
        BannerPO entity = this.bannerMapper.selectByPrimaryKey(id);
        Assert.notNull(entity, "找不到对应的数据");
        return new Banner(entity);
    }

    /**
    * 数据变更
    *
    * @param banner banner
    */
    @Override
    public void saveChanges(Banner banner) {
        if (banner.getBannerPO().isTransient()) {
            bannerMapper.insertSelective(banner.getBannerPO());
        } else if (banner.getBannerPO().getDeleted()) {
            bannerMapper.deleteByPrimaryKey(banner.getId());
        } else if (banner.getBannerPO().isModified()) {
            bannerMapper.updateByPrimaryKeySelective(banner.getBannerPO());
        }
    }
}

这里没有全部列出来,只罗列了部分

其中核心的模板类有:

java
package com.wmeimob.fastboot.util.web;

/**
 * 基础抽象 crud 接口
 *
 * @author mjyang
 * @date 2023/8/1 13:51
 */
public interface CrudService<TAddDto, TUpdateDto extends Id> {

    /**
     * 详情
     *
     * @param id id
     * @return dto
     */
    default Object get(Long id) {
        return null;
    }

    /**
     * 新增
     *
     * @param dto dto
     * @return long
     */
    Object add(TAddDto dto);

    /**
     * 编辑
     *
     * @param dto dto
     */
    void update(TUpdateDto dto);

    /**
     * 删除
     *
     * @param id id
     */
    void delete(Long id);
}
java
package com.wmeimob.fastboot.util.web;

import com.wmeimob.fastboot.util.pager.BaseDTO;

import java.util.List;

/**
 * 基础抽象 crud page 接口
 *
 * @author mjyang
 * @date 2023/8/1 13:51
 */
public interface CrudPageService<TQuery extends BaseDTO, TAddDto, TUpdateDto extends Id>
        extends CrudService<TAddDto, TUpdateDto> {
    /**
     * 分页查询
     *
     * @param query query
     * @return list dto
     */
    default List<?> list(TQuery query) {
        throw new UnsupportedOperationException("不支持该方式");
    }

    /**
     * 滚动分页查询
     *
     * @param query query
     * @return list dto
     */
    default <T extends NextToken> List<T> scrollList(TQuery query) {
        throw new UnsupportedOperationException("不支持该方式");
    }
}
java
/**
 * 基础抽象 crud 控制器
 *
 * @author mjyang
 * @date 2023/8/1 13:47
 */
@RequiredArgsConstructor
public abstract class CrudController<TAddDto, TUpdateDto extends Id> {
    private final CrudService<TAddDto, TUpdateDto> service;

    @GetMapping("/get/{id}")
    @ApiOperation("详情")
    public JsonResult<?> get(@PathVariable("id") Long id) {
        return JsonResult.ok(this.service.get(id));
    }

    @PostMapping
    @ApiOperation("添加")
    public JsonResult<?> add(@RequestBody @Validated TAddDto dto) {
        return JsonResult.ok(this.service.add(dto));
    }

    @PutMapping("/update/{id}")
    @ApiOperation("编辑")
    public JsonResult<Void> update(@PathVariable("id") Long id, @RequestBody @Validated TUpdateDto dto) {
        dto.setId(id);
        this.service.update(dto);
        return JsonResult.ok();
    }

    @DeleteMapping("/delete/{id}")
    @ApiOperation("删除")
    public JsonResult<Void> delete(@PathVariable("id") Long id) {
        this.service.delete(id);
        return JsonResult.ok();
    }
}
java

/**
 * 基础抽象 crud page 控制器
 *
 * @author mjyang
 * @date 2023/8/1 13:47
 */
public abstract class CrudPageController<TQuery extends BaseDTO, TAddDto, TUpdateDto extends Id>
        extends CrudController<TAddDto, TUpdateDto> {
    private final CrudPageService<TQuery, TAddDto, TUpdateDto> service;

    protected CrudPageController(CrudPageService<TQuery, TAddDto, TUpdateDto> service) {
        super(service);
        this.service = service;
    }

    @GetMapping
    @ApiOperation("分页查询")
    public JsonResult<PagedResult<?>> list(TQuery query) {
        try (Page<?> page = PagedResult.startPage(query)) {
            List<?> list = this.service.list(query);
            return JsonResult.ok(PagedResult.of(page.getTotal(), list));
        }
    }
}
java
/**
 * 基础抽象 crud scroll page 控制器
 *
 * @author mjyang
 * @date 2023/8/1 13:47
 */
public abstract class CrudScrollPageController<TQuery extends BaseDTO, TAddDto, TUpdateDto extends Id>
        extends CrudController<TAddDto, TUpdateDto> {
    private final CrudPageService<TQuery, TAddDto, TUpdateDto> service;

    protected CrudScrollPageController(CrudPageService<TQuery, TAddDto, TUpdateDto> service) {
        super(service);
        this.service = service;
    }

    @GetMapping
    @ApiOperation("滚动分页查询")
    public <T extends NextToken> JsonResult<PagedScrollResult<T>> list(TQuery query) {
        try (Page<T> page = PagedScrollResult.startPage(query)) {
            List<T> list = this.service.scrollList(query);
            return JsonResult.ok(PagedScrollResult.of(list));
        }
    }
}

这个模板生成的是伪 DDD 代码,代码书写上并不强制要求符合 DDD 习惯。

该生成器生成的代码包含基础的增删改查业务,更多的细节可以查阅代码。同时希望提供一种模板化标准,以减少前后端沟通成本,并带来开发效率的提升。