diff --git a/pom.xml b/pom.xml index 0a6845e9..1c0389c4 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,11 @@ + + com.squareup + javapoet + 1.13.0 + org.apache.groovy @@ -122,6 +127,11 @@ org.springframework.boot spring-boot-starter-actuator + + com.google.guava + guava + 32.1.1-jre + org.springframework.boot spring-boot-starter-aop diff --git a/src/main/java/cn/lihongjie/coal/Codegen.java b/src/main/java/cn/lihongjie/coal/Codegen.java new file mode 100644 index 00000000..2f871b47 --- /dev/null +++ b/src/main/java/cn/lihongjie/coal/Codegen.java @@ -0,0 +1,341 @@ +package cn.lihongjie.coal; + +import cn.lihongjie.coal.annotation.OrgScope; +import cn.lihongjie.coal.annotation.SysLog; +import cn.lihongjie.coal.base.dao.BaseRepository; +import cn.lihongjie.coal.base.dto.CommonDto; +import cn.lihongjie.coal.base.dto.CommonQuery; +import cn.lihongjie.coal.base.dto.IdRequest; +import cn.lihongjie.coal.base.dto.OrgCommonDto; +import cn.lihongjie.coal.base.entity.CommonEntity; +import cn.lihongjie.coal.base.entity.OrgCommonEntity; +import cn.lihongjie.coal.base.mapper.BaseMapper; +import cn.lihongjie.coal.base.mapper.CommonMapper; +import cn.lihongjie.coal.base.service.BaseService; +import com.google.common.base.CaseFormat; +import com.squareup.javapoet.*; +import jakarta.persistence.Entity; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.mapstruct.Mapper; +import org.mapstruct.control.DeepClone; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.lang.model.element.Modifier; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Scanner; + +public class Codegen { + + public static final Path DIRECTORY = Path.of("src/main/java/"); + + @SneakyThrows + public static void main(String[] args) { + System.out.print("请输入模块名:"); + String moduleName = new Scanner(System.in).nextLine(); + + System.out.print("请输入模块中文名:"); + String moduleCNName = new Scanner(System.in).nextLine(); + + + System.out.print("机构数据[Y]:"); + boolean orgMode = Objects.equals(StringUtils.defaultIfBlank(new Scanner(System.in).nextLine(), "Y"), "Y"); + + + String lModuleName = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, moduleName); + String prefix = Codegen.class.getPackage().getName() + "." + lModuleName; + String entityPackage = prefix + ".entity"; + String dtoPackage = prefix + ".dto"; + String repoPackage = prefix + ".repository"; + String mapperPackage = prefix + ".mapper"; + String servicePackage = prefix + ".service"; + String controllerPackage = prefix + ".controller"; + + // 生成entity + + + TypeSpec entity = TypeSpec.classBuilder(StringUtils.capitalize(moduleName) + "Entity") + .addModifiers(Modifier.PUBLIC) + .superclass(orgMode ? OrgCommonEntity.class: CommonEntity.class) + .addAnnotation(Data.class) + .addAnnotation(Entity.class) + + .build(); + + JavaFile.builder(entityPackage, entity) + .build() + .writeTo(DIRECTORY); + + + // 生成dto + TypeSpec dto = TypeSpec.classBuilder(StringUtils.capitalize(moduleName) + "Dto") + .addModifiers(Modifier.PUBLIC) + .superclass(orgMode ? OrgCommonDto.class:CommonDto.class) + .addAnnotation(Data.class) + + .build(); + + JavaFile.builder(dtoPackage, dto) + .build() + .writeTo(DIRECTORY); + + + // 生成createDto + TypeSpec createDto = TypeSpec.classBuilder("Create" + StringUtils.capitalize(moduleName) + "Dto") + .addModifiers(Modifier.PUBLIC) + .superclass(orgMode ? OrgCommonDto.class:CommonDto.class) + .addAnnotation(Data.class) + + .build(); + + JavaFile.builder(dtoPackage, createDto) + .build() + .writeTo(DIRECTORY); + + + // 生成updateDto + TypeSpec updateDto = TypeSpec.classBuilder("Update" + StringUtils.capitalize(moduleName) + "Dto") + .addModifiers(Modifier.PUBLIC) + .superclass(orgMode ? OrgCommonDto.class:CommonDto.class) + .addAnnotation(Data.class) + + .build(); + + JavaFile.builder(dtoPackage, updateDto) + .build() + .writeTo(DIRECTORY); + + + // 生成repository + TypeSpec repository = TypeSpec.interfaceBuilder(StringUtils.capitalize(moduleName) + "Repository") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Repository.class) + .addSuperinterface(ParameterizedTypeName.get(ClassName.get(BaseRepository.class), ClassName.get(entityPackage, entity.name))) + .build(); + + + JavaFile.builder(repoPackage, repository) + .build() + .writeTo(DIRECTORY); + + + // 生成mapper + TypeSpec mapper = TypeSpec.interfaceBuilder(StringUtils.capitalize(moduleName) + "Mapper") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(AnnotationSpec.builder(Mapper.class) + .addMember("componentModel", "org.mapstruct.MappingConstants.ComponentModel.SPRING", "") + .addMember("uses", "{$T.class}", CommonMapper.class) + .addMember("mappingControl", "$T.class", DeepClone.class) + + .build()) + .addSuperinterface(ParameterizedTypeName.get( + ClassName.get(BaseMapper.class), + ClassName.get(entityPackage, entity.name), + ClassName.get(dtoPackage, dto.name), + ClassName.get(dtoPackage, createDto.name), + ClassName.get(dtoPackage, updateDto.name) + + + ) + + + ) + .build(); + + + JavaFile.builder(mapperPackage, mapper) + .build() + .writeTo(DIRECTORY); + + + // 生成service + TypeSpec service = TypeSpec.classBuilder(StringUtils.capitalize(moduleName) + "Service") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(Service.class) + .addAnnotation(Slf4j.class) + .superclass(ParameterizedTypeName.get( + ClassName.get(BaseService.class), + ClassName.get(entityPackage, entity.name), + ClassName.get(repoPackage, repository.name) + + + ) + + + ) + .addField(FieldSpec.builder(ClassName.get(repoPackage, repository.name), "repository", Modifier.PRIVATE).addAnnotation(Autowired.class).build()) + .addField(FieldSpec.builder(ClassName.get(mapperPackage, mapper.name), "mapper", Modifier.PRIVATE).addAnnotation(Autowired.class).build()) + .addField(FieldSpec.builder(ClassName.get(ConversionService.class), "conversionService", Modifier.PRIVATE).addAnnotation(Autowired.class).build()) + .addMethod(MethodSpec.methodBuilder("create") + .addModifiers(Modifier.PUBLIC) + .returns(ClassName.get(dtoPackage, dto.name)) + .addParameter(ClassName.get(dtoPackage, createDto.name), "request") + .addStatement(""" + $T entity = mapper.toEntity(request); + + + this.repository.save(entity); + return getById(entity.getId()) + """, ClassName.get(entityPackage, entity.name)) + + .build() + ) + .addMethod(MethodSpec.methodBuilder("update") + .addModifiers(Modifier.PUBLIC) + + .returns(ClassName.get(dtoPackage, dto.name)) + .addParameter(ClassName.get(dtoPackage, updateDto.name), "request") + .addStatement(""" + $T entity = this.repository.get(request.getId()); + this.mapper.updateEntity(entity, request); + + this.repository.save(entity); + + return getById(entity.getId()) + """, ClassName.get(entityPackage, entity.name)) + .build() + ) + + .addMethod(MethodSpec.methodBuilder("delete") + .addModifiers(Modifier.PUBLIC) + + .returns(void.class) + .addParameter(ClassName.get(IdRequest.class), "request") + .addStatement(""" + this.repository.deleteAllById(request.getIds()) + """) + .build() + ) + .addMethod(MethodSpec.methodBuilder("getById") + .addModifiers(Modifier.PUBLIC) + + .returns(ClassName.get(dtoPackage, dto.name)) + .addParameter(ClassName.get(String.class), "id") + .addStatement(""" + $T entity = repository.get(id); + + + return mapper.toDto(entity) + """, ClassName.get(entityPackage, entity.name)) + .build() + ) + .addMethod(MethodSpec.methodBuilder("list") + .addModifiers(Modifier.PUBLIC) + + .returns(ParameterizedTypeName.get(ClassName.get(Page.class), ClassName.get(dtoPackage, dto.name))) + .addParameter(ClassName.get(CommonQuery.class), "query") + .addStatement( + """ + $T<$T> page = repository.findAll(query.specification(conversionService), $T.of(query.getPageNo(), query.getPageSize(), $T.by(query.getOrders()))); + + + return page.map(this.mapper::toDto) + """, ClassName.get(Page.class),ClassName.get(entityPackage, entity.name), ClassName.get(PageRequest.class), ClassName.get(Sort.class)) + .build() + ) + .build(); + + + JavaFile.builder(servicePackage, service) + .build() + .writeTo(DIRECTORY); + + + + + + + + // 生成controller + TypeSpec controller = TypeSpec.classBuilder(StringUtils.capitalize(moduleName) + "Controller") + .addModifiers(Modifier.PUBLIC) + .addAnnotation(RestController.class) + .addAnnotation(AnnotationSpec.builder(RequestMapping.class).addMember("value", "$S", "/" + lModuleName).build()) + .addAnnotation(AnnotationSpec.builder(SysLog.class).addMember("module", "$S", StringUtils.defaultIfBlank(moduleCNName, "")).build()) + .addAnnotation(Slf4j.class) + .addAnnotation(orgMode ? OrgScope.class : Slf4j.class) + + .addField(FieldSpec.builder(ClassName.get(servicePackage, service.name), "service", Modifier.PRIVATE).addAnnotation(Autowired.class).build()) + .addMethod(MethodSpec.methodBuilder("create") + .addModifiers(Modifier.PUBLIC) + .returns(ClassName.get(dtoPackage, dto.name)) + .addAnnotation(AnnotationSpec.builder(PostMapping.class).addMember("value", "$S", "/create").build()) + + .addParameter(ParameterSpec.builder(ClassName.get(dtoPackage, createDto.name), "request").addAnnotation(RequestBody.class).build()) + .addStatement(""" + return this.service.create(request) + """) + + .build() + ) + .addMethod(MethodSpec.methodBuilder("update") + .addModifiers(Modifier.PUBLIC) + + .returns(ClassName.get(dtoPackage, dto.name)) + .addAnnotation(AnnotationSpec.builder(PostMapping.class).addMember("value", "$S", "/update").build()) + + .addParameter(ParameterSpec.builder(ClassName.get(dtoPackage, updateDto.name), "request").addAnnotation(RequestBody.class).build()) + .addStatement(""" + return this.service.update(request) + """) + .build() + ) + + .addMethod(MethodSpec.methodBuilder("delete") + .addModifiers(Modifier.PUBLIC) + + .returns(Object.class) + .addAnnotation(AnnotationSpec.builder(PostMapping.class).addMember("value", "$S", "/delete").build()) + + .addParameter(ParameterSpec.builder(ClassName.get(IdRequest.class), "request").addAnnotation(RequestBody.class).build()) + .addStatement(""" + this.service.delete(request); + return true + """) + .build() + ) + .addMethod(MethodSpec.methodBuilder("getById") + .addModifiers(Modifier.PUBLIC) + + .returns(ClassName.get(dtoPackage, dto.name)) + .addParameter(ParameterSpec.builder(ClassName.get(String.class), "request").addAnnotation(RequestBody.class).build()) + .addStatement(""" + return this.service.getById(request) + """) + .build() + ) + .addMethod(MethodSpec.methodBuilder("list") + .addModifiers(Modifier.PUBLIC) + + .returns(ParameterizedTypeName.get(ClassName.get(Page.class), ClassName.get(dtoPackage, dto.name))) + .addParameter( ParameterSpec.builder(ClassName.get(CommonQuery.class), "request").addAnnotation(RequestBody.class).build() ) + .addStatement( + """ + return this.service.list(request) + """, ClassName.get(Page.class), ClassName.get(entityPackage, entity.name), ClassName.get(PageRequest.class), ClassName.get(Sort.class)) + .build() + ) + .build(); + + + JavaFile.builder(controllerPackage, controller) + .build() + .writeTo(DIRECTORY); + + + + } +} diff --git a/src/main/java/cn/lihongjie/coal/supplier/mapper/SupplierMapper.java b/src/main/java/cn/lihongjie/coal/supplier/mapper/SupplierMapper.java index dd476d26..9a029af0 100644 --- a/src/main/java/cn/lihongjie/coal/supplier/mapper/SupplierMapper.java +++ b/src/main/java/cn/lihongjie/coal/supplier/mapper/SupplierMapper.java @@ -8,12 +8,12 @@ import cn.lihongjie.coal.supplier.dto.SupplierDto; import cn.lihongjie.coal.supplier.dto.UpdateSupplierDto; import cn.lihongjie.coal.supplier.entity.SupplierEntity; import org.mapstruct.Mapper; -import org.mapstruct.MappingConstants; -import org.mapstruct.MappingTarget; import org.mapstruct.control.DeepClone; +import static org.mapstruct.MappingConstants.ComponentModel.SPRING; + @Mapper( - componentModel = MappingConstants.ComponentModel.SPRING, + componentModel = SPRING, uses = {CommonMapper.class}, mappingControl = DeepClone.class