揭秘Classpath

环境变量CLASSPATH 在安装Java环境的时候,我们需要配置PATH和CLASSPATH。 PATH:PATH比较好理解,我们在命令行需要执行某个命令的时候如python的时候,如果没有配置PATH,则需要进入python.exe所在的文件夹下,然后执行python。那配置PATH中的python所在路径,其实就相当于简化了这个过程,当配置完成后再执行python,首先去PATH中从左到右搜索所有的路径,直到搜索到python.exe,然后利用该路径执行命令,如果找不到则提示该命令不存在。 CLASSPATH:CLASSPATH其实也很好理解,这里来一段Java官方文档的解释: The CLASSPATH variable is one way to tell applications, including the JDK tools, * where to look for user classes *. (Classes that are part of the JRE, JDK platform, and extensions should be defined through other means, such as the bootstrap class path or the extensions directory.) 名如其人,classpath就是classes所在的path,那设置CLASSPATH的作用就是指定java类所在的目录,当我们执行java命令的时候,java需要去哪里找class文件呢,这时候就需要设置classpath,我们可以输出当前环境的classpath查看: * echo %CLASSPATH% * 1 .;C:\Program Files\Java\jdk1.8.0_181\lib;C:\Program Files\Java\jdk1.8.0_181\lib\tools.jar CLASSPATH的扫描同样是从左向右的。我们可以看到参数以 ; 分割,那么第一个参数 *.*指代的就是当前目录,意思是java去当前目录下寻找class文件进行执行。 Spring中的classpath 我们在很多的项目代码的config代码中都可以看到 @PropertySource(value = "classpath:map-config.yaml") 类似的代码,在这里也用到了classpath,这里的classpath什么作用呢? ...

<span title='2022-03-15 17:23:11 +0800 +0800'>March 15, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;YuanPeng11

设计模式-策略模式实战

策略模式概念 https://refactoringguru.cn/design-patterns/strategy 实战应用 背景 健康码组件对接的前端门禁设备都多种开门的方式,刷证,人脸,二维码等。对于每一种开门方式,其需要的返回结果是一样的,只是内部的处理方式不一样。所以这里使用策略模式+工厂模式来实现,通过一个入口以及不同的type来实现调用不同的实现类。具体代码如下。 代码 1. 创建一个Handler接口类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /** * @Author Yuanpeng * @Description 处理健康码请求携带参数的类 根据不同的类型进行 不同的处理 * @Date 2022/1/10 */ public interface HealthCodeHandler { /** * 处理健康码信息的逻辑 * @param query 前置信息 * @return 处理的结果 包括开门信息 健康码信息 核酸信息 疫苗信息等 */ HealthCodeResult handle(HealthCodeQuery query); /** * 获取请求的类型 1.人员唯一标识 personId 2.身份证号 3.二维码 4.人员卡号 5.人脸图片 6.市民卡 * @return 类型 */ Integer getType(); } 2. 创建不同的Handler实现类,这里以二维码的实现类举例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /** * @Author Yuanpeng * @Description 处理二维码的实现类 * @Date 2022/1/10 */ @Service public class QrCodeHandler implements HealthCodeHandler { private static final Logger log = LoggerFactory.getLogger(QrCodeHandler.class); @Override public HealthCodeResult handle(HealthCodeQuery query) { HealthCodeResult result = ResultUtils.getDefaultHeathCodeResult(query, false); // logic code return result; } @Override public Integer getType() { return HealthCodeConstants.QR_CODE_TYPE; } 3. 将所有实现了Handler接口类的实例注入容器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 /** * @Author Yuanpeng * @Description 策略模式的工厂类 加载所有的HealthCodeHandler类 * @Date 2022/1/10 */ @Component public class HealthCodeHandlerFactory implements InitializingBean, ApplicationContextAware { private static final Map<Integer, HealthCodeHandler> HEALTH_CODE_HANDLER_MAP = new HashMap<>(6); private ApplicationContext appContext; /** * 根据健康码信息类型获取对应的处理器 * * @param type 健康码信息类型 * @return 健康码信息类型对应的处理器 */ public HealthCodeHandler getHandler(Integer type) { return HEALTH_CODE_HANDLER_MAP.get(type); } @Override public void afterPropertiesSet() { // 将 Spring 容器中所有的 HealthCodeHandler 注册到 FORM_SUBMIT_HANDLER_MAP appContext.getBeansOfType(HealthCodeHandler.class) .values() .forEach(handler -> HEALTH_CODE_HANDLER_MAP.put(handler.getType(), handler)); } @Override public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException { appContext = applicationContext; } } 4. 入口处根据传参中的type进行不同类的调用 1 2 3 // 使用策略模式来实现对不同类型请求的处理,如果需要添加其它类型信息的处理 只需要实现相应的HealthCodeHandler即可 HealthCodeHandler handler = healthCodeHandlerFactory.getHandler(query.getCardNoType()); HealthCodeResult result = handler.handle(query); 至此,完成了业务上的需求,同时后期如果还有其它类型的开门方式,可以直接写实现类,不用改之前的代码,维护起来比较方便。 ...

<span title='2022-03-03 18:30:14 +0800 +0800'>March 3, 2022</span>&nbsp;·&nbsp;2 min&nbsp;·&nbsp;YuanPeng11

Pg数据库常用SQL(持续更新)

普通操作 更新多参数SQL 1 update table_a a set (col_a, col_b) = (select b.col_a, b.col_b from table_b b where a.col_c = b.col_c) where exists (select 1 from table_b b where a.col_c = b.col_c) 分组排序 1 select * from (select *, row_number() over(partition by col_a order by col_b) rn from table_a) t where rn = 1; 分组排序删除 1 delete from table_a where id in (select id from (select id, row_number() over(partition by col_a order by col_b) rn from table_a) t where rn != 1); 系统类 查看当前所有连接,连接个数 1 2 3 4 5 6 select * from pg_stat_activity; select count(1) from pg_stat_activity; # 查询最大连接数 show max_connections;

<span title='2022-03-02 19:09:58 +0800 +0800'>March 2, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;YuanPeng11

记一次数据库膨胀问题的解决过程

问题描述 表中记录了图片的base64 表大概有200w数据 占用了300G左右的空间 问题解决 查询了wiki和咨询了总部的pg数据库的同事得知了pg数据库存在膨胀的问题,即垃圾清理问题。所以及时删除了数据,空间也不会得到释放,只有手动进行垃圾清理后空间才能够得到释放,所以根据总部同事提供的排查方案,首先进行数据膨胀的排查。 pg数据库膨胀的问题排查 通过排查后发现,真正大的表是pg_toast_oid表,并且根据排查也发现其dead_tup比较大,实际上这是pg数据库存储大型数据的逻辑toast,后面知识点归纳也会提到这一点。pg_toast_oid表我们分析可知为表中的base64图片的压缩切片存储。 解决方案 大数据量的表VACUUM FULL很慢并且会锁表(VACUUM FULL的原理是复制新表,然后删除旧表),所以直接在业务空闲期进行表的删除和重建。(由于数据已经实时的推送给了三方,在中间数据库中也有数据存储,所以这里没有进行备份,选择了直接删除。删除的时候对于这种大数据的表要进行批量删除,先将部分数据删除,然后在删除整个表,避免长时间的执行删除命令导致业务中断的时间过长。) 引申出来的一点关于数据库操作的建议:尽量避免长连接的操作,如果数据库的并发量比较高,长连接一直占用,将会导致数据库连接不够用,从而产生报错。 后续的过程中删除保留时间过长的数据,并且执行VACUUM FULL命令(kettle流程深夜执行) 此问题产生的思考 BASE64的图片不要存库。选择图片存储地址等方案。 所有的东西设计之初就要想好,并且日后有优化的想法时第一时间优化。 知识点总结归纳 https://juejin.cn/post/7016165148020703246 事务特性-ACID 原子性(Atomicity):对数据库的操作要么执行,要么不执行。 一致性(Consistency):不管操作是否执行,数据保持不变。 隔离性(Isolation):多个事务并发访问,相互隔离。 持久性(Durability):事务操作完成后,将永久保存。 事务并发产生的问题 脏读: 一个事务读取到了另一个未提交事务修改过的数据 不可重复读:同一个事务内,前后多次读取,读取到的数据内容不一致 幻读: 如果一个事务先根据某些搜索条件查询出一些记录,在该事务未提交时,另一个事务写入了一些符合那些搜索条件的记录(如insert、delete、update),就意味着发生了幻读。 MVCC-Multi-Version Concurrency Control Multi-Version Concurrency Control,多版本并发控制 通俗的讲,数据库中同时存在多个版本的数据,并不是整个数据库的多个版本,而是某一条记录的多个版本同时存在,在某个事务对其进行操作的时候,需要查看这一条记录的隐藏列事务版本id,比对事务id并根据事物隔离级别去判断读取哪个版本的数据。 MVCC实现的关键点 事务版本号: 事务每次开启前,都会从数据库获得一个自增长的事务ID,可以从事务ID判断事务的执行先后顺序。这就是事务版本号。 + 有关版本号的经验和思考: 版本号多用于控制并发,常用于乐观锁来解决并发问题,如MySQL的乐观锁解决并发。其基本做法是在数据库的表中引入版本的字段(version),数据每进行一次更新,version+1,当提交更新的时候,比对版本号+1是否相等,不相等则认为当前数据是过期数据。 隐式字段:以MySQL为例,InnoDB存储引擎 trx_id: 记录操作数据事务的事务id roll_pointer: 指针,指向回滚的undo日志 row_id: 如果没主键和非NULL惟一键,有该主键列 undo log: 回滚日志 版本链:通过roll_pointer来指向undo_log 快照读和当前读: 快照读:读的是记录数据的可见版本 当前读:读的是记录数据的最新版本 ReadView:事务执行SQL时产生的读视图 PostgreSQL toast https://zhmin.github.io/posts/postgresql-toast/ toast说白了就是为了存储大型数据,表中的某个列的数据如果过大,则压缩,切分,放到toast表中,在之前问题的排查中,也可以看到真正数据量大的并不是数据存储的本表,而是pg_toast_oid表。 PostgreSQL VACUUM https://www.cnblogs.com/dbadaily/p/vacuum1.html https://www.cnblogs.com/dbadaily/p/vacuum2.html https://www.cnblogs.com/dbadaily/p/vacuum3.html https://www.cnblogs.com/dbadaily/p/vacuum4.html https://www.cnblogs.com/dbadaily/p/vacuum5.html 推荐阅读(我没读) https://www.interdb.jp/pg/

<span title='2022-02-25 13:44:17 +0800 +0800'>February 25, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;YuanPeng11

IDEA+EasyCode实现自动生成代码

需求 对于增删改查类的代码,每次都要写很多重复的代码,所以考虑使用自动生成代码来减少重复工作。 自动生成代码的现状 目前有多种方式可以自动生成代码: 将模板引擎集成到项目中,通过代码的形式自动生成代码,此种方法和项目耦合度较高,对项目由侵入性 在线网站自动生成代码,使用互联网,安全性较低 IDEA+groovy方法,目前了解到生成的代码比较简单,定制化程度不高 IDEA插件生成,一般插件也都是以模板引擎为基础,进行代码的生成 最后选择了第四种,IDEA插件的方式,插件使用的是EasyCode, 基于velocity模板引擎。 > https://gitee.com/makejava/EasyCode Velocity(速度)语法 比较精简的一种语言,关键字不多,和代码混合使用。教程:https://www.cnblogs.com/hduwbf/p/6201731.html EasyCode 我的模板(具有个人风格,可以进行修改使用) Controller 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/controller/$!{workPath}", "Controller.java") ##包路径(宏定义) #setPackageSuffix("controller$!{workPackage}") $!{autoImport.vm} import io.swagger.annotations.ApiOperation; import $!{tableInfo.savePackageName}.service$!{workPackage}.$!{serviceType}; import $!{tableInfo.savePackageName}.dto$!{workPackage}.$!{dtoType}; import $!{tableInfo.savePackageName}.vo$!{workPackage}.$!{voType}; import org.springframework.web.bind.annotation.*; import io.swagger.annotations.Api; import org.apache.commons.lang3.StringUtils; import javax.annotation.Resource; import java.util.List; ##表注释(宏定义) #classNotes("表控制层") @Api(tags = "$!{tableInfo.comment}") @RestController @RequestMapping("$!entityName") public class $!apiType { @Resource private $!serviceType $!serviceName; /** * 分页查询所有数据 * * @param query 查询实体 * @return 所有数据 */ @PostMapping("/queryPage") @ApiOperation("按字段条件分页查询$!{tableInfo.comment}") public BaseResult<PageVo<$!voType>> query$!{entityType}ByPage(@RequestBody $!{queryType} query) { return $!{serviceName}.queryByPage(query); } /** * 通过主键查询多条数据 * * @param query 查询实体 * @return 多条数据 */ @PostMapping("/query") @ApiOperation("根据Id查询$!{tableInfo.comment}") public BaseResult<List<$!voType>> query(@RequestBody $!{queryType} query) { return $!{serviceName}.queryByCondition(query); } /** * 新增数据 * * @param dto 实体对象 * @return 新增结果 */ @PostMapping("/save") @ApiOperation("新增$!{tableInfo.comment}数据") public BaseResult<Object> save(@RequestBody $!{dtoType} dto) { //数据校验 if (StringUtils.isBlank(dto.getName())) { return new BaseResult<>(ResponseEnum.NO_ARGS.getCode(), ResponseEnum.NO_ARGS.getMessage()); } if ($!{serviceName}.isExist(dto)) { return new BaseResult<>(ResponseEnum.REPEAT.getCode(), ResponseEnum.REPEAT.getMessage()); } return $!{serviceName}.save(dto); } /** * 修改数据 * * @param dto 实体对象 * @return 修改结果 */ @PostMapping("/update") @ApiOperation("更新$!{tableInfo.comment}") public BaseResult<Object> update($!{dtoType} dto) { //数据校验 if (StringUtils.isBlank(dto.getName())) { return new BaseResult<>(ResponseEnum.NO_ARGS.getCode(), ResponseEnum.NO_ARGS.getMessage()); } return $!{serviceName}.update(dto); } /** * 删除多条数据 * * @param ids 主键ids * @return 删除结果 */ @PostMapping("/delete") @ApiOperation("根据Id软删除$!{tableInfo.comment}数据") public BaseResult<List<SingleResult>> deleteByRowIds(List<Long> ids) { List<SingleResult> result = new ArrayList<>(); ids.forEach(x -> { // 数据校验 if (!$!{serviceName}.isExistById(x)) { result.add(SingleResult.successBuild(x.toString())); } else { result.add($!{serviceName}.deleteById(x)); } }); return BaseResult.success(result); } } Entity 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/entity$!{workPath}", ".java") ##包路径(宏定义) #setPackageSuffix("entity$!{workPackage}") import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.persistence.*; import java.io.Serializable; import java.util.Date; ##表注释(宏定义) #classNotes("") @Data ##@ApiModel(value="$tableInfo.savePackageName.replace(".","-")-entity$!{workCommon}-$!{entityType}") @ApiModel(value="$!{tableInfo.comment}") @Table(name = "$!{tableInfo.obj.name}") public class $!entityType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "$!{column.obj.name}") @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @Column(name = "$!{column.obj.name}") @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } Service 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/service$!{workPath}", "Service.java") ##包路径(宏定义) #setPackageSuffix("service$!{workPackage}") $!{autoimpot.vm} ##表注释(宏定义) #classNotes("表服务接口") public interface $!serviceType { BaseResult<PageVo<$!{voType}>> queryByPage($!{queryType} query); BaseResult<List<$!{voType}>> queryByCondition($!{queryType} query); BaseResult<Object> save($!{dtoType} dto); BaseResult<List<SingleResult>> saveBatch(List<$!{dtoType}> dtos); BaseResult<Object> update($!{dtoType} dto); BaseResult<List<SingleResult>> updateBatch(List<$!{dtoType}> dtos); SingleResult deleteById(Long id); boolean isExist($!{dtoType} dto); boolean isExistById(Long id); } ServiceImpl 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/service/impl/$!{workPath}", "ServiceImpl.java") ##包路径(宏定义) #setPackageSuffix("service.impl$!{workPackage}") $!{autoimport.vm} import org.apache.commons.lang3.StringUtils; import javax.transaction.Transactional; import $!{tableInfo.savePackageName}.entity$!{workPackage}.$!{entityType}; import javax.persistence.criteria.Predicate; #classNotes("表服务实现类") @Service public class $!{serviceImplType} implements $!{serviceType} { @Resource private $!{repositoryType} $!{repositoryName}; /** * 查询多条数据 * * @param query 查询参数 * @return 实例对象 */ @Override public BaseResult<List<$!{voType}>> queryByCondition($!{queryType} query) { List<$!{tableInfo.name}> items = $!{repositoryName}.findAll(getWhereClause(query)); return BaseResult.success(BaseConverter.convertAll(items, $!{voType}.class)); } /** * 分页查询 * * @param query 筛选条件 * @return 查询结果 */ @Override public BaseResult<PageVo<$!voType>> queryByPage($!{queryType} query) { try { Sort sort = Sort.by("desc".equals(query.getSortOrder()) ? Sort.Direction.DESC : Sort.Direction.ASC, query.getSortField()); Pageable pageable = PageRequest.of(query.getPageNo() - 1, (query.getPageSize()), sort); Page<$!{tableInfo.name}> page = $!{repositoryName}.findAll(getWhereClause(query), pageable); return BaseResult.success(BaseConverter.convertPage(page, $!{voType}.class)); } catch (Exception e) { return new BaseResult<>("-1", "查询分页失败"); } } /** * 新增数据 * * @param dto dto对象 * @return vo $!voName */ @Override public BaseResult<Object> save($!dtoType dto) { try { $!{tableInfo.name} entity = BaseConverter.convert(dto, $!{tableInfo.name}.class); $!{repositoryName}.save(entity); } catch (Exception e) { return new BaseResult<>("-1", "保存失败"); } return new BaseResult<>(); } /** * 批量新增数据 * * @param dtos dto对象 * @return BaseResult */ @Override public BaseResult<List<SingleResult>> saveBatch(List<$!dtoType> dtos) { try { List<$!{tableInfo.name}> entitys = BaseConverter.convertAll(dtos, $!{tableInfo.name}.class); $!{repositoryName}.saveAll(entitys); } catch (Exception e) { return new BaseResult<>("-1", "保存失败"); } return new BaseResult<>(); } /** * 修改数据 * * @param dto dto对象 * @return BaseResult */ @Override @Transactional public BaseResult<Object> update($!dtoType dto) { try { $!{tableInfo.name} entity = BaseConverter.convert(dto, $!{tableInfo.name}.class); $!{repositoryName}.save(entity); } catch (Exception e) { return new BaseResult<>("-1", "更新失败"); } return new BaseResult<>(); } /** * 批量修改数据 * * @param dtos dto对象 * @return 实例对象 */ @Override @Transactional public BaseResult<List<SingleResult>> updateBatch(List<$!dtoType> dtos) { try { List<$!{tableInfo.name}> entitys = BaseConverter.convertAll(dtos, $!{tableInfo.name}.class); $!{repositoryName}.saveAll(entitys); } catch (Exception e) { return new BaseResult<>("-1", "批量更新失败"); } return new BaseResult<>(); } /** * 通过主键删除数据 * * @param id 主键 * @return 是否成功 */ @Override @Transactional public SingleResult deleteById(Long id) { try { $!{repositoryName}.updateDeletedById(id); } catch (Exception e) { return SingleResult.build(id.toString(), "false", "删除异常"); } return SingleResult.successBuild(id.toString()); } @Override public boolean isExist($!{dtoType} dto) { Integer exist = $!{repositoryName}.isExist(dto.getName()); return null != exist; } @Override public boolean isExistById(Long id) { Integer exist = $!{repositoryName}.isExistById(id); return null != exist; } private Specification<$!{tableInfo.name}> getWhereClause($!{queryType} query) { return (Specification<$!{tableInfo.name}>) (root, criteriaQuery, criteriaBuilder) -> { List<Predicate> predicates = new ArrayList<>(); if (StringUtils.isNotBlank(query.getName())) { predicates.add(criteriaBuilder.like(root.get("name"), "%" + query.getName() + "%")); } if (ObjectUtils.isNotEmpty(query.getCreatedTime())) { //大于等于开始时间 predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), DateUtil.parse(query.getCreatedTime()))); } if (ObjectUtils.isNotEmpty(query.getCreatedTime())) { //小于等于结束时间 predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), DateUtil.parse(query.getCreatedTime()))); } return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; } } VO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $!{init.vm} $!{define.vm} ##保存文件 #save("/vo$!{workPath}", "VO.java") ##包路径(宏定义) #setPackageSuffix("vo$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import java.util.Date; ##表注释(宏定义) #classNotes("") @Data @ApiModel(value="$tableInfo.savePackageName.replace(".","-")-dto$!{workCommon}-$!{voType}") public class $!voType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } DTO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 $!{init.vm} $!{define.vm} ##保存文件 #save("/dto$!{workPath}", "DTO.java") ##包路径(宏定义) #setPackageSuffix("dto$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import lombok.Data; import java.util.Date; ##表注释(宏定义) #classNotes("") @Data @ApiModel(value="$tableInfo.savePackageName.replace(".","-")-dto$!{workCommon}-$!{dtoType}") public class $!dtoType implements Serializable { private static final long serialVersionUID = 1L; ## 主键列 #foreach($column in $tableInfo.pkColumn) /** * $!column.comment */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($column.type) $!column.name; #end ## 其他列 #foreach($column in $tableInfo.otherColumn) /** * $!{column.comment} */ @ApiModelProperty(value = "$!column.comment") private $!tool.getClsNameByFullName($!column.type) $!column.name; #end } Repository JPA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ##导入宏定义 $!{init.vm} $!{define.vm} ##保存文件(宏定义) #save("/repository/$!{workPath}", "Repository.java") ##包路径(宏定义) #setPackageSuffix("repository$!{workPackage}") import com.javahik.hiklife.easycode.entity.$!{tableInfo.name}; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; ##表注释(宏定义) #classNotes("表数据库访问层") @Repository public interface $!{repositoryType} extends JpaRepository<$!{tableInfo.name}, String>, JpaSpecificationExecutor<$!{tableInfo.name}> { @Modifying @Query(nativeQuery = true, value = "update $!{tableInfo.name} set deleted = '1' where id = ?1") void updateDeletedById(Long id); @Query(nativeQuery = true, value = "select 1 from $!{tableInfo.name} where name = ?1 limit 1") Integer isExist(String name); @Query(nativeQuery = true, value = "select 1 from $!{tableInfo.name} where id = ?1 limit 1") Integer isExistById(Long id); } QueryDTO 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 $!{init.vm} $!{define.vm} ##保存文件 #save("/dto$!{workPath}", "Query.java") ##包路径(宏定义) #setPackageSuffix("dto$!{workPackage}") ##自动导入包(全局变量) $!{autoImport.vm} import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import lombok.Data; import java.util.Date; ##表注释(宏定义) #classNotes("查询类") @Data public class $!{queryType} implements Serializable { private static final long serialVersionUID = 1L; private Integer pageNo = 1; private Integer pageSize = 20; private String sortField = "createDate"; private String sortOrder = "desc"; private String createdTime; private String name; } Define 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ##(Velocity宏定义) ##定义设置表名后缀的宏定义,调用方式:#setTableSuffix("Test") #macro(setTableSuffix $suffix) #set($tableName = $!tool.append($tableInfo.name, $suffix)) #end ##定义设置包名后缀的宏定义,调用方式:#setPackageSuffix("Test") #macro(setPackageSuffix $suffix) #if($suffix!="")package #end#if($tableInfo.savePackageName!="")$!{tableInfo.savePackageName}.#{end}$!suffix; #end ##定义直接保存路径与文件名简化的宏定义,调用方式:#save("/entity", ".java") #macro(save $path $fileName) $!callback.setSavePath($tool.append($tableInfo.savePath, $path)) $!callback.setFileName($tool.append($tableInfo.name, $fileName)) #end ## 自定义entity、Mapper、Service、Api、DTO、VO的名字减少拼接,增加重用性 #set($entityType = $!tool.firstUpperCase($!tableInfo.name)) #set($entityName = $!tool.firstLowerCase($!tableInfo.name)) #set($mapperType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Mapper")) #set($mapperName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Mapper")) #set($repositoryType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Repository")) #set($repositoryName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Repository")) #set($serviceType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Service")) #set($serviceName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Service")) #set($serviceImplType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "ServiceImpl")) #set($serviceImplName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "ServiceImpl")) #set($apiType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Controller")) #set($apiName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "Controller")) #set($dtoType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "DTO")) #set($dtoName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "DTO")) #set($queryType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "Query")) #set($queryName = "query") #set($voType = $!tool.append($!tool.firstUpperCase($!tableInfo.name), "VO")) #set($voName = $!tool.append($!tool.firstLowerCase($!tableInfo.name), "VO")) ## 自定义类注解 #macro(classNotes $notes) /** * @Description $!tableInfo.obj.name $notes * @Author $!author * @Date $!time.currTime() */ #end Init 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ##初始化区域 ##去掉表的t_前缀 $!tableInfo.setName($tool.getClassName($tableInfo.obj.name.replaceFirst("tb_",""))) ## 设置业务模块名 #set($index = 0) #foreach ($element in $tableInfo.obj.name.split("_")) #set($index = $index +1) #if($index == 3) #set($work = $element) #end #end #if($!{work}) ## 包.模块名 #set($workPackage = $!tool.append(".",$!{work})) ## 路径/模块名 #set($workPath = $!tool.append("/",$!{work})) ## Common-模块名 #set($workCommon = $!tool.append("-",$!{work})) #end ##参考阿里巴巴开发手册,POJO 类中布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误 #foreach($column in $tableInfo.fullColumn) #if($column.name.startsWith("is") && $column.type.equals("java.lang.Boolean")) $!column.setName($tool.firstLowerCase($column.name.substring(2))) #end #end ##实现动态排除列 #set($temp = $tool.newHashSet("testCreateTime", "otherColumn")) #foreach($item in $temp) #set($newList = $tool.newArrayList()) #foreach($column in $tableInfo.fullColumn) #if($column.name!=$item) ##带有反回值的方法调用时使用$tool.call来消除返回值 $tool.call($newList.add($column)) #end #end ##重新保存 $tableInfo.setFullColumn($newList) #end ##对importList进行篡改 #set($temp = $tool.newHashSet()) #foreach($column in $tableInfo.fullColumn) #if(!$column.type.startsWith("java.lang.")) ##带有反回值的方法调用时使用$tool.call来消除返回值 $tool.call($temp.add($column.type)) #end #end ##覆盖 #set($importList = $temp) autoimport 1 2 3 4 ##自动导入包(仅导入实体属性需要的包,通常用于实体类) #foreach($import in $importList) import $!import; #end

<span title='2022-02-12 15:12:48 +0800 +0800'>February 12, 2022</span>&nbsp;·&nbsp;9 min&nbsp;·&nbsp;YuanPeng11