被遗忘的烦恼
跑步停止
由机器人注入
快乐的人!
电影中 “童年终结者” “冒险电子”
嗨,今天我们再谈性能。 关于开发人员的生产力。
我将讨论如何通过“创意”提升这项技能。 希望我的提示有用,欢迎提出评论和改进。 走吧
普通的开发人员将大部分工作时间都花在日常活动上。 直到最近,我也表演了。 然后我脑中浮现出一些简单而明显的想法:
- 我们很少会写一些新奇的东西
- 在工作时间的很大一部分中,开发人员编写了模板代码
- 我们使用的许多简单构造都易于形式化,在我们的脑海中,我们用几句话来表达它们
我使用Spring Booth / Hibernate的时间最多,因此大多数代码生成和模板都与它们有关,尽管这种方法是通用的,并且您可以轻松地为项目进行类似的改进。
剧院从衣架开始,而Spring Booth应用程序从设置开始。 通常,它们是在文件application.yml
/ application.properties
中签名的,但是也有一些bean /配置必须用代码来描述:
@Configuration @EnableSwagger2 class SwaggerConfig { @Bean Docket documentationApi() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } }
此设置包括Swagger(服务器场上的一个有用项目)。 考虑什么可以自动化? 开发人员知道@Configuration
位于settings类的上方。 即 您可以创建一种空白-配置类的模板,并轻轻一挥即可创建它。 开箱即用的“想法”为用户提供了为自己定制现有模板的机会:

我们将使用:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end import org.springframework.context.annotation.Configuration; @Configuration class ${NAME} { }
对于有经验的开发人员,这里的内容很清楚,对于初学者,我将解释:
第1行:将这样的行添加到新创建的类的代码中
package com.example.-;
第2行:连接所需的注释
第三行:身体课。
请注意,变量${NAME}
将变成一个弹出窗口,我们需要在其中输入类名。
总计:

此模板使我们不必手动在类上编写@Configuration
并解决导入问题。 数量不多,但是对于我们来说开始并获得一些经验很重要。
一个空的设置类就没有什么价值。 让我们学习如何轻松创建bean。 为此,请从“ 编辑器”>“文件和代码模板” ,转到“ 编辑器”>“实时模板” 。 在这里,您可以描述通过键入识别的模式。 在开发环境中,我定义了与Spring一起使用的单独的亚种。 在其中,我们创建一个模板:
@Bean public $CLASS_NAME$ $mthdName$() { return new $CLASS_NAME$($END$); }
CLASS_NAME
变量由用户在弹出窗口中设置,除直接分配外,还用于创建方法名称:

变量mthdName
使用内置方法camelCase()
,该方法将传递CLASS_NAME
的值。 设置发生在Edit变量中 :

变量$END$
表示指针在渲染后的位置。 我们的bean可能具有依赖性(通过构造函数实现),因此您需要使它们成为返回我们的bean的方法的参数:

现在,让我们从上到下浏览应用程序,看看可以用这种简单的方式来加速其他日常任务。
服务专区
常识表明,这种方法在我们有大量代码会在不同地方徘徊的情况下最有用。 例如,常规的spring服务可能依赖于存储库(这意味着需要事务性),进行某种日志记录,并且依赖项是通过构造函数实现的。 为了不每次都列出新创建的类上的所有注释,我们描述模板:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; @Log4j2 @Service @Transactional @RequiredArgsConstructor public class ${NAME} { }
实际上:

接下来是令人讨厌的依赖项列表。 上面,我们使用了内置的camelCase()
方法来描述返回bin的方法的名称。 他们还可以创建字段名称:

private final $CLASS_NAME$ $fieldName$; $END$
为了不每次都按Ctrl + Alt + L (对齐),请启用“ 根据样式重新设置格式”复选框,环境将为您做所有事情:

储存库和实体
即使在最简单的实体中,我们也有许多导入注释。 您可以为他们创建一个非常有效的模板:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import lombok.Getter; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; @Getter @Table @Entity public class ${NAME} { @Id private Long id; }

在2019年,如果您使用的是Hibernate,那么当然也要使用Spring Date,如果是这样,则需要创建存储库。 让我们加快其创建速度:
#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end #parse("File Header.java") import org.springframework.data.jpa.repository.JpaRepository; public interface ${Entity_name}Repository extends JpaRepository<${Entity_name}, ${Key}>{ }

如果将光标放在实体上(标记为@Entity
和@Table
的类)并按Alt + Enter,则 “ Idea”会建议立即创建存储库,但这不是那么聪明: 当前,用户无法更改/添加意图( Editor> Intentions ),但是您可以编写自己的插件:

测试中
通常,代码中模板构造的数量越多,自动化收益就越大。 测试是重复性最高的工作之一。 那些看过Cyril Tolkachev “春季测试的诅咒”的报告的人知道,有一种简单的方法可以使所有测试的上下文只出现一次:创建一个抽象类,并从该类继承所有测试。
描述类似
package com.example; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import org.springframework.test.context.junit.jupiter.SpringExtension; @Transactional @SpringBootTest @ExtendWith(SpringExtension.class) public abstract class BaseTest { }
我们可以轻松地使所有新创建的测试继承BaseTest
。 为此,您需要更改创建默认测试的模板:

在代码中:
import com.example.BaseTest; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; #parse("File Header.java") class ${NAME} extends BaseTest { ${BODY} }
接下来,我们描述依赖性。 我不想每次都拨打
@Autowired private MyService service;
因此,在“ 编辑器”>“实时模板 ”部分中,编写
@Autowired private $CLASS_NAME$ $fieldName$; $END$
变量$fieldName$
描述与创建Bean示例中的描述完全相同,但有一个例外:要在创建字段后立即将光标不切换到该字段,您需要检查Skip如果已定义 :

基本上,@ @Autowired
仅用于类字段,因此请确保在“ 适用于”下拉列表中设置“声明” :

我们看:

顺便说一下,由于我们正在为某个类创建测试,因此没有什么阻止我们在创建它时立即引入必要的依赖项( toCamelCase()
在这里不起作用 ,因此使用了Velocity ):
import com.example.demo.BaseTest; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; #parse("File Header.java") class ${NAME} extends BaseTest { #set($bodyLength = $NAME.length() - 4) #set($field = $NAME.substring(0, 1).toLowerCase() + $NAME.substring(1, $bodyLength)) @Autowired private ${CLASS_NAME} ${field}; ${BODY} }

我的经验表明,只要有可能,所有测试都应贯穿于各个领域。 即使选中了一项服务以取出实体并切断其一部分字段的服务,还是最好诚实地获取实体,即 从数据库中。 因此,对于大多数测试,我使用一种环境从诚实的数据中获取一种数据,并在使用@Sql
进行测试之前加载它们。
每个任务都需要手工完成数据采样,但是将它们链接到所需的测试可以轻松实现自动化。 再次,转到编辑器>实时模板的JUnit部分,然后编写:
@Sql("/sql/$CLASS_NAME$.sql") $END$

现在,输入sql
,我们将获得一个包含1条记录的下拉列表,并选择以下内容:
@Sql("/sql/MyEntityRepositoryTest.sql") class MyEntityRepositoryTest extends BaseTest { }
请注意,我们所指的文件尚不存在,因此当您以原始格式运行测试时,它肯定会崩溃。 但是,从版本193.1617开始,该Idea突出显示了一个不存在的文件,最重要的是,它建议创建它!

后缀
最强大的工具之一是使用后缀表达式(终止)来创建/添加代码。 最简单的例子:

有很多补全,您可以在“ 编辑器”>“常规”>“后缀完成”部分中看到所有补全 :

也有各种实验的范围。 我自己完成了将变量替换为基于AssertJ的测试表达式的工作:

在生活中,它看起来像这样:

有用的链接
如果您打算通过Idea来提高自己的技能,请务必查看两个出色的报告:
Anton Arkhipov-与IntelliJ IDEA的有效合作
Tagir Valeev-IntelliJ IDEA中的原子重构:我们自己弯曲IDE
仅此而已,很少会分心,请记住,时间是我们唯一真正不可再生的资源。