# backend_liangang_mes2.0 **Repository Path**: yinginx/backend_liangang_mes2.0 ## Basic Information - **Project Name**: backend_liangang_mes2.0 - **Description**: MES系统后端接口工程 - **Primary Language**: Java - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-08-30 - **Last Updated**: 2025-10-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 欢迎使用上海应星 Java 后端脚手架 1.0 (idea 里需要设置 maven3.8,settings.xml 需要更改为本地 localRepository 路径,并替换 repository com 包) 1、开始使用 1.1 项目创建 使用 IntelliJ IDEA 创建项目(按新版 UI 编写,旧 UI 自行尝试或改用命令行方式) Step 1:File -> New -> Project -> Maven archetype。 Step 2:Archetype -> Add。 Step 3:填写 GroupId=com.yinginx,ArtifactId=archetype-archetype,Version:1.0.0-SNAPSHOT。 Step 4:选择 com.yinginx.archetype-archetype,点击 Next。 Step 5:输入项目 GroupId,ArtifactId,Version、Package 即可。 无论使用的是哪个创建方式,GroupId 均需要以 com.yinginx.开头! 2、项目构成 2.1 概览 本脚手架使用 Maven3.8 打包,基于 Java11。包含 SpringBoot2.5.1 与 SpringCloud Alibaba2021 版本。将模块分为三大部分 common:项目中所有静态资源且需要与使用者共享的,如所有 Pojo,枚举,公共接口、公共工具包等 feign:项目对外开放的接口,即 controller 层的映射 server:项目自身的 boot 项目,包括所有的逻辑、交互 对于开发者,common 和 feign 中的 Maven 依赖不允许私自修改。 对于外部调用者,其 server 的 pom.xml 中永远只调用 common 和 feign,不允许调用这个服务与服务的 server 部分。 2.2 依赖表 主依赖 org.jetbrains annotations 24.0.1 common 包依赖 com.yinginx yinginx-common-base feign 包依赖 com.yinginx archetype-common 1.0.0-SNAPSHOT com.yinginx yinginx-common-web io.github.openfeign feign-okhttp org.springframework.cloud spring-cloud-starter-openfeign server 包依赖 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test junit junit test org.springframework.boot spring-boot-configuration-processor org.springframework.cloud spring-cloud-starter-bootstrap org.springframework.cloud spring-cloud-dependencies 2020.0.3 pom com.alibaba.nacos nacos-client com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery com.alibaba.cloud spring-cloud-starter-alibaba-nacos-config com.alibaba.cloud spring-cloud-alibaba-dependencies 2021.1 pom import org.springframework.cloud spring-cloud-starter-loadbalancer com.yinginx yinginx-common-base com.yinginx yinginx-common-web com.yinginx yinginx-common-util mysql mysql-connector-java 8.0.28 org.mybatis mybatis-typehandlers-jsr310 1.0.1 com.baomidou mybatis-plus 3.5.3.1 com.baomidou mybatis-plus-boot-starter 3.5.3.1 org.springframework.amqp spring-amqp org.springframework.integration spring-integration-mqtt 5.5.16 org.springframework.data spring-data-redis org.springframework.boot spring-boot-starter-data-redis org.springframework spring-websocket io.swagger swagger-models 1.6.2 io.springfox springfox-swagger2 3.0.0 io.springfox springfox-swagger-ui 3.0.0 com.github.xiaoymin knife4j-spring-boot-starter 3.0.3 io.springfox springfox-boot-starter 3.0.0 com.alibaba fastjson 1.2.83 org.apache.commons commons-collections4 4.4 org.apache.commons commons-lang3 org.apache.commons commons-pool2 com.yinginx archetype-common 1.0.0-SNAPSHOT 2.3 目录树 ├─archetype-common │ └─src │ └─main │ └─java │ └─com.yinginx.liangang │ ├─constant (所有对外共享的常量,枚举,数字、字符串、接口等) │ ├─dto (所有 Data Transport Object,包括入参、中间参数) │ ├─query (所有查询条件) │ └─vo (所有视图返回体) ├─demo-feign │ └─src │ └─main │ └─java │ └─com.yinginx.liangang │ ├─client (所有对外开放的 feign 接口) │ └─fallback (每个 feign 接口对应的降级实现类) └─demo-server └─src ├─main │ ├─java │ │ └─com.yinginx.liangang │ │ ├─aspect (切面层) │ │ ├─config (所有配置项) │ │ ├─controller (视图层) │ │ ├─entity (实体层) │ │ ├─mapper (数据库层) │ │ ├─job (定时任务) │ │ ├─service (服务层) │ │ │ └─impl │ │ ├─utils (工具包) │ │ ├─DatabaseOutput.java (数据库表结构导出工具) │ │ └─ServerApplication.java (主服务启动类) │ └─resources │ ├─mapper (数据映射层) │ ├─bootstrap.yml (启动配置项) │ └─logback-spring.xml (日志管理) └─test └─java └─com.yinginx.liangang 3. 开发规范 3.1 constant constant 包中应包含所有的对外共享的常量、枚举、接口等。用以申明固定不变的内容。 常量 常量通常包含: 项目中需要对外共享的 Redis-Key,此处建议能在编写时明确告知此 key 的 redis 类型。 项目中需要用到、且不适合枚举表示的,如电气交互点位编码等。 规范: 常量类中只允许申明常量!不能有类方法、公共构造函数等。 常量类应按功能进行区分,设置多个常量类。不能只写一个类申明所有常量。 枚举 枚举必须继承自 BaseEnum 类,并按要求实现 getDescription 方法。 此方法表示此枚举对应的中文含义。 规范: 在系统中,所有的枚举均需要以枚举本身进行传递,不允许使用 description。此值仅在最终呈现到用户时(包括接口正常显示和异常消息提示)需要转义为中 文。 在枚举值等值判断时,不允许使用 equals()方法,而是==。前者可能存在 NullPointerException。 public enum FrontendType implements BaseEnum { SELECT("下拉菜单"), INPUT("输入框"), TEXT_AREA("文本域"), INPUT_NUMBER("数字输入框"), SWITCH("开关") ; public final String description; FrontendType(String description) { this.description = description; } @Override public String getDescription() { return description; } } 接口 当服务需要对外暴露一些接口,使其他服务中的某些类也能适配此服务的一些约定,从而能实现更广泛的兼容。 规范: 不允许以抽象类的形式申明,只能申明接口! 原则上,这些接口只是一个约定,不应参与其他模块的业务。 3.2 dto dto 包中包含所有的数据传输对象,包括服务中的所有入参和中间参数。此处的入参也包含调用第三方接口时的入参。 规范: 所有需要录入数据库的 DTO 都需要继承自 BaseDTO。其中包含了部分必须字段,如 id、createTime、updateTime、createUser、 updateUser,但这些 字段都是自动注入的,业务层无需关注。 在 dto 中,除了字段本身的 get set 方法、equals hashCode toString、实现的接口方法外,不允许有其他额外的方法;至少要提供一个无参构造函 数,有参构造函数自己决定。 在 dto 中,所有的非静态字段均需要使用包装类型,不允许使用原始类型。 在 dto 中,类名上需要带有@ApiModel 注解,并填入参数,以表示此类的作用对象;每个非静态字段需要带有@ApiModelProperty 注解,并填入参数,以 表示此字段的含义,同时需要在必填字段上申明 required 为 true。 在 dto 中,默认值的实现应通过改写其 get 方法进行判空,而不是直接在类申明时就进行赋值。部分框架如果参数中写了 null 也会进行赋值,导致默认值丢失。 在 dto 中,最好对入参进行校验使用 javax.validation 相关的注解,实现对接口入参的校验。 扩展: common 包中还提供了一个扩展版本 LogicalDeletableDTO,添加了对 code、name、activate 和 deleted 的支持。如果业务字段确有需求,请继承 此版本,以保持统一。 @Data @EqualsAndHashCode(callSuper = true) @ApiModel("工装") public class ContainerBaseDTO extends LogicalDeletableDTO implements Serializable { private static final long serialVersionUID = 5487478798652024128L; @ApiModelProperty(value = "工装主类型ID", required = true) @NotBlank(message = "工装主类型不得为空") private String containerId; @ApiModelProperty(value = "是否为虚拟工装", required = true) @NotNull(message = "是否为虚拟工装不得为空") private Boolean isVirtual; } @EqualsAndHashCode(callSuper = true) @Data @ApiModel("绑定关系") public class RelationshipDTO extends BaseDTO implements Serializable { private static final long serialVersionUID = -3423399419564781643L; @ApiModelProperty("位置ID") @NotBlank(message = "位置不得为空") private String positionId; @ApiModelProperty("位置类型,storagePosition:储位,containerPosition:工装储位") @NotBlank(message = "位置类型不得为空") private String positionType; @ApiModelProperty("存放的类型,container:工装,material:物料,tool:刀具...") @NotBlank(message = "目标类型不得为空") private String targetType; @ApiModelProperty("绑定ID") @NotBlank(message = "目标不得为空") private String targetId; } 3.3 query query 包中包含所有的查询条件。所有查询条件默认均是分页查询所用。 规范: 所有需要录入数据库的 DTO 都需要继承自 BaseQuery。绝大部分性质与 dto 相同。 LogicalDeletableQuery 中明确了,不支持 deleted 字段的条件查询 扩展: BaseQuery 中提供了 columns 的字段,以表示此次查询所需返回的字段。不包含在内的将返回 null。如果不传则默认全量查询。注意,此功能将直接影 响生成的 SQL 语句,因此错误的传参会导致查询失败! BaseQuery 中提供了 orders 的字段,以表示此次查询的排序方案。如果不传则默认是 createTime 倒序。 BaseQuery 中提供了@QueryWrapper,添加在字段上可改写其查询方案与字段映射。具体查询方案对字段的数据类型会有要求。当使用默认的分页查询时, 此处的逻辑将会触发。详细见分页查询。 @Data @EqualsAndHashCode(callSuper = true) @ApiModel("储位") public class StoragePositionQuery extends LogicalDeletableQuery implements Serializable { private static final long serialVersionUID = -6721672746626602583L; @ApiModelProperty("仓位ID") private String storageBaseId; @ApiModelProperty("仓位编码") private String storageBaseCode; @ApiModelProperty("储位组ID") private String storagePositionGroupId; @ApiModelProperty(value = "是否为虚拟储位", required = true) private Boolean isVirtual; @ApiModelProperty(value = "可放置的目标类型", required = true) @QueryWeapper(SqlConditions.IN) private List availableTargetType; @ApiModelProperty(value = "可放置的目标类型ID列表", required = true) @QueryWeapper(SqlConditions.IN) private List availableTargetIds; @ApiModelProperty(value = "电气代号", required = true) private Integer electricalCode; @ApiModelProperty("绑定设备ID") private String equipmentId; @ApiModelProperty("产线ID") private String factoryModelId; } 3.4 vo vo 包中包含所有的视图层返回体。所有的 vo 禁止使用在参数输入!此处的返回体也包含调用第三方接口时的返回体。 规范: 所有需要录入数据库的 VO 都需要继承自 BaseVO。绝大部分性质与 dto 相同。 BaseVO 中提供了@ExcelWrapper,添加在字段上可改写其在导出为 excel 时的字段标题映射。当使用 excel 导出时,此处的逻辑将会触发。 扩展: BaseVO 默认实现了 BasePOJO,并在返回时可以附带类型信息,此举可以解决远程调用后的类型丢失问题,保证 feign 调用后依然能保持原类型与字段。原则上 所有的 vo 都需要带有。如果第三方接口无法提供此功能,或提供的字段无法在项目中进行反序列化,请不要继承 BaseVO,强行继承将导致报错。 @Data @EqualsAndHashCode(callSuper = true) @ApiModel("工装储位") public class ContainerPositionVO extends LogicalDeletableVO implements PositionVO, Serializable { private static final long serialVersionUID = 93441404971685544L; @ApiModelProperty("位置类型") private String positionType; @ApiModelProperty("所属工装ID") @ExcelWrapper(included = ExcelFieldInclude.IGNORED) private String containerBaseId; @ApiModelProperty("所属工装编码") private String containerBaseCode; @ApiModelProperty("所属工装名称") private String containerBaseName; @ApiModelProperty(value = "可存放的目标类型", required = true) @ExcelWrapper(parser = "new com.smartstate.common.base.excel.ExcelFieldCollectionHandler()") private List availableTargetType; @ApiModelProperty(value = "可存放的目标类型ID列表", required = true) @ExcelWrapper(included = ExcelFieldInclude.IGNORED) private List availableTargetIds; @ApiModelProperty(value = "电气代号", required = true) private Integer electricalCode; } 3.5 client client 包中包含了所有本服务对外暴露的 API。 规范: 由于 controller 层的返回值会自动包装一层 ResultVO,因此在写 client 时需要为返回值手动包装一次。 扩展: 与 common 一样,client 也拥有 BaseClient 与 LogicalDeletableClient 两个版本,对标 controller。 @FeignClient(name = "yinginx-logistics", path = "/containerBase", fallbackFactory = ContainerBaseFallback.class) public interface ContainerBaseClient extends LogicalDeletableClient { } 3.6 fallback fallback 包中包含了所有 client 对应的服务降级处理。 规范: fallback 需要继承自 BaseFallback。与旧版的不同,新版本不再需要实现方法。 @Component public class ContainerBaseFallback extends BaseFallbackFactory { } 3.7 controller 视图层,所有对外开放的接口需要在此定义。 规范: 与 common 一样,controller 也拥有 BaseController 与 LogicalDeletableController 两个版本,对标 dto、vo、query。 在 BaseController 中提供了如下的接口: getPage:标准分页查询,支持使用@QueryWrapper 进行自定义查询条件,支持 columns 进行返回字段限制,支持 orders 进行排序方式定制。 getById:根据 ID 单个查询。 getAll:全量查询。 getByIds:根据 ID 批量查询。 save:新增,并返回新增后的数据。 update:更新。 delete:根据 ID 批量删除。 exportExcel:导出为 excel,支持使用@ExcelWrapper 进行自定义字段名映射。详情见 excel 导出。 在定义接口时,请利用好@Validation,完成对入参的校验,减少在业务中校验入参。 @RestController @RequestMapping("/api//containerBase") @Api(tags = "工装") public class ContainerBaseController extends LogicalDeletableController { private final ContainerBaseService containerBaseService; public ContainerBaseController(ContainerBaseService containerBaseService) { this.containerBaseService = containerBaseService; } @Override public @NotNull ContainerBaseService getService() { return containerBaseService; } } 在接口上,共有两个注解可以使用。 @ApiResultWrapper 用于对返回值进行包装。在默认情况下,无需注解,就会对正常返回值进行一次 ResultVO 包装,并放入 data 字段中。如果抛出了 异常,则会将异常信息放入 message 字段中。如果添加了注解,则可以自定义成功状态下的 messae(不加的话就是没有);或可以使用 ignore 直接取消此 接口的自动包装。 @ApiBodyWrapper 用于对接口的响应参数进行处理展示。在默认情况下,无需注解,就会对接口的入参、出参进行打印。如果添加了注解,则可以改写此方案 ,从而自定义处理方案(包括什么也不做的)。当然,也可以通过配置项 server.api-body-interceptor = false,直接禁用此套逻辑。 3.8 entity 实体层,所有数据映射对象需要在此定义。 规范: 所有 Entity 都需要继承自 BaseEntity。绝大部分性质与 dto 相同。 此版本中默认不再包含 JPA 组件,因此请手动建表、维护。 BaseEntity 本身的字段无需在业务层关心。 由于动态扩展列的加入,所有的实体均需要添加@TableName(autoResultMap = true)。 @Data @EqualsAndHashCode(callSuper = true) @TableName(autoResultMap = true) public class ContainerBase extends LogicalDeletableEntity implements Serializable { private static final long serialVersionUID = 3428868220977156789L; private String containerId; private Boolean isVirtual; } 3.9 mapper 数据库映射层,所有与数据库之间的交互在此编写。 我们仍推荐简单的增删改查使用默认的方法完成,此处只推荐使用复杂查询时的场景。 3.10 service 服务层,所有正式的业务逻辑在此编写。原则上,应保证每个服务尤其独立的接口与实现,且其他类遵循面向接口开发的原则,不得依赖具体的实现类。 服务层中,对 controller 层相关接口进行了实现,提供了数据层的增删改查。 规范: 与 common 一样,service 也拥有 BaseService 与 LogicalDeletableService 两个版本。 对外开放的接口,应确认好出参入参的空与非空,并通过注解@NotNull、@Nullable 进行明确表示。默认情况下,入参没有@NotNull 表示可以传 null,出参可能是 null 时必须有@Nullable。 异常抛出见异常处理。 public interface ContainerBaseService extends LogicalDeletableService { List queryContainerBaseByParentIds(@NotNull Collection parentIds); } @Service @Transactional(rollbackFor = Exception.class) public class ContainerBaseServiceImpl extends LogicalDeletableServiceImpl implements ContainerBaseService { } getPage 输入分页查询参数后,会根据其字段有无与查询条件,自动拼装查询 SQL,并根据 columns 和 orders 进行排序和字段过滤。 如果实际字段与数据库字段不同的,就需要@QueryWrapper 进行转义,如果字段上没有此注解则表示使用默认字段名。 此后统一对所有字段进行处理,将大驼峰格式改为下划线格式。 对于查询字段,如果不传则为全量,否则按字段返回。 对于排序字段,如果不传则为 createTime 倒序,否则按传入的顺序与方式进行排序。 最近进行统一查询。 exportExcel 在分页的基础上,会把返回体输出至 excel 中。 如果实际字段与原本的字段名不一样的,就需要@ExcelWrapper 进行转义,如果字段上没有此注解则表示使用默认字段名。 按此方法对所有对象进行递归,获取所有字段后按行输出结果。(首行是标题) 3.11 其他改进 异常 在 common 包中,提供了新的 BaseException 以及 4 个默认实现,以替代旧版的 CommonException,可以满足基本场景下的异常抛出需求。在业务编写过程中, 可以使用其静态构造函数完成异常的创建与抛出。脚手架中集成了完整的全局异常处理,涵盖了接口部分和定时任务部分。 由于 BaseException 是 RuntimeException,因此使用者需要自己注意所调用的代码是否抛出业务异常,是否需要捕获。 在新的异常体系中,异常支持动态参数拼接,与 log 的用法一致。 class ExceptionDemo { public static void main(String[] args) { throw OperationFailedException.of("工件 {} 出线异常: {}", materialCode, exceptionMessage); } } redis 在新版本的 redisTemplate,会类型记录机制,对所有的数据类型进行记录,从而实现了抽象类型的类型保持。由于类型记录需要其根本对象继承自 BasePOJO ,因 此在实际存入读取的过程中,如果对象不是 BasePOJO 的子类,则会在存入时自动包装一个 PojoReference,取出时自动拆除。 typehandler 在新版本中,统一对数据库层面的 json 格式提供了支持,即支持 Mysql 的 JSON 字段类型。但由于 JSON 不被 Mybatis 支持,因此,当使用这种字段时需要额外配置 typehandler。 在 common 包中,提供了 ListToStringTypeHandler,用来处理 JSON 中存放简单的数组的情况。即 List、List、 List等列表中只含有基础类型的情况。提供了 MapToStringTypeHandler,用来处理 JSON 中存放简单对象的情况。其余情况建议重新建表进行存 储。 如何使用: Mybatis-Plus 版本(即在实体上需要) import java.util.List; class Entity extends BaseEntity { @TableField(typehandler = ListToStringTypeHandler.class) private List jsonField; } Mybatis 版本(如果查询的时候是走 xml 配置的,那么需要在 resultMap 中进行改写) serialUtil 在新版本中,对流水号的生成器做了很大的改动。支持与 log 一样的模板填参方式,进行序列号的自定义生成。 @Component @SuppressWarnings("unused") public class SerialUtil { @Resource private RedisTemplate redisTemplate; /** * 前缀+8位时间+4位流水号 * * @param prefix 前缀 * @return 生成的流水号 */ public final String prefixTimestampSerialNumber(String prefix) { return getSerial( "{}{}{}", new StringSerial(prefix), new DateTimeSerial(new SimpleDateFormat("yyyyMMdd")), new RedisSerialNumberSerial(redisTemplate, prefix, 4, RedisSerialNumberSerial.EXPIRE_EVERY_DAY) ); } /** * 前缀+4位流水号 * * @param prefix 前缀 * @return 生成的流水号 */ public final String prefixSerialNumber(String prefix) { return getSerial( "{}{}", new StringSerial(prefix), new RedisSerialNumberSerial(redisTemplate, prefix, 4, RedisSerialNumberSerial.NEVER_EXPIRE) ); } /** * 自定义流水号生成器。 * * @param template 模板 * @param args 生成方法 * @return 生成的流水号 */ public final String getSerial(String template, SerialSupplier... args) { return LogParameterHelper.logParameterHelper(template, args); } } 接口优化 在新版本中,延续了之前的 ResultVO 自动封装,并修复了对于 String 的问题,同时提供了一个新的方法,以自动判断接口调用是否成功。 public final class ResultVO implements BasePOJO, Serializable { @JSONField(serialize = false, deserialize = false) @JsonIgnore public T getDataOrException() { if (isSuccess()) { return data; } throw FeignException.of(message, serviceName); } } 此外,还添加了对于接口出参入参的打印。由于 spring mvc 的限制,此功能无法正常打印非 json 格式的内容,如数据流等。 Websocket 在新版本中,对 websocket 提供了支持。实现 BaseWebsocket 抽象类,并在类上申明 Websocket 即可申明一个 ws 路径,将其注册为一个 bean,即可。 @Component @Websocket("/ws") public final class Ws extends BaseWebsocket { @Override public @Nullable CloseStatus onOpen(WebSocketSession session, Map attributes) { log.info("someone entered"); return null; } @Override public CloseStatus onMessage(WebSocketSession session, WsDTO inputData) { log.info("received message {}", inputData.getData()); return null; } @Override public CloseStatus onError(WebSocketSession session, Throwable exception) { log.warn("received error", exception); return null; } @Override public void onClose(WebSocketSession session, CloseStatus closeStatus) { log.info("someone left"); } } ProjectSchedule 在新版本中,提供了注解@ProjectScheduled,用于表示这是一个项目级定时任务。 即项目级定时任务。通过获取配置文件中的 global.projectName,获取此时所处的位置,并与直接上的 projectName 进行匹配,如果任意一项符合,则启动 此定时任务。如果 projectName 为空数组,则表示不匹配,永远启动。 注解使用方法与普通的@Scheduled 一致,且都是在项目启动时自动注入。仅多了上述一个字段的区别。 Redis Lock 在新版本中,提供了一个注解@Distributed,当注释在方法上,表示此方法需要启用分布式锁。实现逻辑: 指定一个 value,以表示将此 key 作为 redis 的 key,进行锁的管理。当此 key 存在时,无法获取锁。 如果指定了 waitTime,则获取锁会在等待指定秒后失败,并 执行 timeoutHandler 的回调;否则,线程会一直阻塞,直到获取锁。获取锁之后,才会开始执行方法,同时开启一个定时任务,进行锁的续约,每次锁只会保持 两秒,并每秒进行一次续约。方法执行完毕后,会释放锁,并结束定时任务;或在超时后,由 redis 自行释放。 因此,这样的实现可以保证服务挂掉后,其余的服务 可以正常的接手此 key。 建议: 每次的锁定时间大于触发间隔时,近似可以认为此服务独占此锁,当服务挂掉后下一服务可以立即接手。 续约间隔一定要小于锁定时间,否则锁可能自己就过期解开了! 要求:必须是通过代理对象调用此方法才能生效,类自身调用是不生效的!因为本质是 AOP。 如果无法放在方法上,或不能使用代理对象,则可以手动创建 RedisLock,并手动进行加解锁。 后续的所有方法都不是 bean! Mqtt client 通过构建一个 MqttClientConnect,可以快速的申明一个 mqtt 连接,通过配置相关的参数即可实现消息的收发。 DateTimeMapper 时间与字符串之间的转换器,以及特殊时间的相关快速获取方式。 DtoMapper 4.1 版本已标注为废弃,4.2 版本将移除 实体的字段转换器。内核是 Spring BeanUtil,对嵌套实体的支持尚有问题,请注意。 BeanCopierFactory DtoMapper 的替代工具 支持了嵌套对象的转换。但以下是几种字段特殊情况: 无法转换类型不同的情况,如源字段类型是原始类型,目标字段是包装类型,反之亦然。或是可以通过类型的强转达成的类型。 无法转换源类型是目标类型父类的情况。反之可以。 如果源类型/目标类型是泛型的,由于类型擦除,即使泛型参数不一致也可以转换,但是会在取出时报错。 FTPUtil FTP 的工具包,用于实现连接,并进行文件的上传下载。 HttpUtil 用于发起 Http 请求。 通过链式调用,从而满足一次配置,反复请求的目的。 IotUtil 在 HttpUtil 的基础上,封装了 Iot 的写入读取功能。 并在其基础上,进一步提供了标准配方写入(formulationWrite)和阻塞读取(blockUntil)功能。 PagesUtil 分页的一些小工具。 StoppableSchedule 静态的定时任务管理工具。 4、开始编码 生成结构后,需要改哪些东西?哪些不能删除 类 ServerApplication,建议改名,以更好的区分项目启动。 DynamicTableExtension 相关的内容,包括 FrontendType 不能删除。feign 包中的除外。 DatabaseOutput,如果需要导出,可以在执行前进行配置项的修改。 bootstrap.yml 中,需要把 spring.application.name 和 extension-configs 修正。 logback-spring.xml 中,需要把 projectName 和 moduleName 修正。 migrate.sql 中用于存放此模块的建表 SQL。