春季启动器的配置备忘录
这是什么?
这是我总结的我在搭建Spring Boot项目时所做的事情。截至2021年5月18日的说法。我决定不再使用Thymeleaf来作为API接收服务器,所以我省略了它,但应该只需要添加一些东西就可以了。
主要是使用Maven(pom.xml)进行配置。有时候还会涉及到类、配置和相关类的部署。关于这是否是正确的解决方案,没有详细说明。特别是在AWS方面,缺乏相关信息,只能摸索着进行。
几乎一定要做的事情
选择当时的最新版本
在目前情况下,我们将根据2.5.0版本的开发进程和是否有更新版本的出现来决定是否使用RC版本。
在Spring Initializr上下载项目的模板。
每次细微的更改都是有意义的,所以基本上如果主要版本有变化的话,最好不要从之前的项目中继承过来。
在此过程中,要确保组和构件(artifact)的设计和考虑中包括相关存储库的存在与否。
https://start.spring.io/ 的网址是
Java的LTS配置(当前版本是11)。
<properties>
<java.version>11</java.version>
</properties>
安装Lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
现在应该没有人烧煤炉了。
使用ModelMapper
<dependency>
<groupId>io.github.yoshikawaa.modelmapper.spring.boot</groupId>
<artifactId>modelmapper-spring-boot-starter</artifactId>
<version>0.1.0</version>
<type>pom</type>
</dependency>
现在不太需要手动编写简单的转换器,但偶尔还是会需要。
在中文本地化时,需要以下选项的释义:
使用OpenApi Generator进行内嵌和编写YAML文件。
由于看到了一些不太光彩的争斗,所以现阶段我还支持 Openapi Generator,但根据开发状况可能会被迫放弃它。我感到很伤心。
我相信现在没有人会用老式的方式来编写REST API的控制器和客户端了。
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION -->
<version>4.3.1</version>
<!-- /RELEASE_VERSION -->
<executions>
<!-- コントローラー用 -->
<execution>
<id>api</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
<language>spring</language>
<configOptions>
<generateApis>true</generateApis>
<apiPackage>jp.nreso.project.api</apiPackage>
<generateModels>true</generateModels>
<modelPackage>jpjp.nreso.project.model</modelPackage>
<generateSupportingFiles>false</generateSupportingFiles>
<sourceFolder>src/main</sourceFolder>
</configOptions>
<output>${project.build.directory}/generated-sources/api</output>
</configuration>
</execution>
<!-- クライアント用 通信先その1 -->
<execution>
<id>client1</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/client1.yaml</inputSpec>
<language>java</language>
<configOptions>
<generateApis>true</generateApis>
<apiPackage>jp.nreso.project.client1</apiPackage>
<generateModels>true</generateModels>
<modelPackage>jp.nreso.project.client1.model</modelPackage>
<sourceFolder>src/main</sourceFolder>
</configOptions>
<output>${project.build.directory}/generated-sources/client1/client</output>
</configuration>
</execution>
<!-- クライアント用 通信先その2 -->
<execution>
<id>client2</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/client2.yaml</inputSpec>
<language>java</language>
<configOptions>
<generateApis>true</generateApis>
<apiPackage>jp.nreso.project.client2</apiPackage>
<generateModels>true</generateModels>
<modelPackage>jp.nreso.project.client2.model</modelPackage>
<sourceFolder>src/main</sourceFolder>
</configOptions>
<output>${project.build.directory}/generated-sources/client2/client</output>
</configuration>
</execution>
</executions>
</plugin>
仅凭上述信息是不够的,需要删除生成代码中阻碍构建的代码。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<delete dir="${project.basedir}/target/generated-sources/api/src/test"/>
<delete dir="${project.basedir}/target/generated-sources/api/src/main/org"/>
<delete
dir="${project.basedir}/target/generated-sources/api/src/main/resources"/>
<delete dir="${project.basedir}/target/generated-sources/client1/client/src/test"/>
<delete>
<fileset
dir="${project.basedir}/target/generated-sources/api/src/main/jp/nreso/api"
includes="*Controller.java"/>
</delete>
<delete dir="${project.basedir}/target/generated-sources/client2/src/test"/>
<delete dir="${project.basedir}/target/generated-sources/client2/src/main/org"/>
<delete>
<fileset
dir="${project.basedir}/target/generated-sources/client2/src/main/jp/nreso/api"
includes="*Controller.java"/>
</delete>
</target>
</configuration>
</execution>
</executions>
将生成的代码添加到源路径中以使其可用。
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/target/generated-sources/api/src/main</source>
<source>${basedir}/target/generated-sources/client1/src/main</source>
<source>${basedir}/target/generated-sources/client2/client/src/main</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
太费时间了,但不做的话会后悔的呢。
Springdoc的配置
为了可视化和执行在开发过程中编写的yaml,必须进行该操作。
此外,在正式环境中,我们必须要将这个东西杀掉,所以,请在SwaggerController.java中实施一个杀死开关(如果找一下的话,可能会有官方的开关)。
另外,为了方便选择,最好在index.html中编写多个yaml并提供选择。
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>0.3</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
@Controller
public class SwaggerController {
@Value("${springfox.documentation.swagger.enable:false}") // これがキルスイッチ
private boolean enable;
@RequestMapping("/")
public String index() {
return enable ? "select.html" : "index.html"; // disabledの場合はindex.htmlなどの魔除けでも404 not foundでもよい
}
@RequestMapping(value = "/api-docs/{api}",
produces = { "application/json" },
method = RequestMethod.GET)
public ResponseEntity<Map> apiDocs(@ApiParam(value = "api", required = true) @PathVariable("api") String api) throws IOException {
String yamlFile = api + ".yaml";
if (enable) {
Yaml yaml = new Yaml();
InputStream is = new ClassPathResource(yamlFile).getInputStream();
Map<String, Object> obj = yaml.load(is);
return new ResponseEntity<>(obj, HttpStatus.OK);
}
throw new RuntimeException();
}
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello</title>
<meta charset="utf-8" />
</head>
<body>
<h1>Select your API</h1>
<p>
<a href="swagger-ui/index.html?url=/api/api-docs/api">Controller</a>
<a href="swagger-ui/index.html?url=/api/api-docs/client1">client 1</a>
<a href="swagger-ui/index.html?url=/api/api-docs/client1">client 2</a>
</p>
</body>
</html>
为了进行数据库访问,可以对mybatis或dao进行设置。
经常使用MySQL
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
错误指导器的设置
如果将项目的 package 设为 jp.nreso.project ,则需要在任何地方设置错误处理器。
具体来说,我们需要处理错误,将服务中出现的各种 RuntimeException 转换为适当的 HTTP 响应。
这篇文章可能会对你有所帮助。请点击以下链接查看:
https://qiita.com/NagaokaKenichi/items/2f199134a881a776b717
如果需要的话,我会去做。 (If needed, I will do it.)
春季安全
如果需要在HTTP头中进行身份验证和授权,需要在Configure类中进行设置。
JWT(Auth0)
目前正在进行的项目似乎正在与Cognito进行协作(由另一个人负责PoC,所以我还没有参与,稍后我会查看进展情况)。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
设置缓存
当需要类似于缓存的东西时,可以将其委托给缓存而不是在服务中添加成员。
实施起来有些复杂。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
登录处理的情况下,将MDC设置为LOG Appender。
在过滤器中进行以下设置,并添加删除操作。
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (認証必要ですよー) {
MDC.put("deviceId", ユーザID);
}
try {
chain.doFilter(request, response);
} finally {
MDC.clear();
}
}
因此可以在访问日志中显示用户ID,很好。
UT/mock 的配置
或许initialzr会处理,但我稍微提一下。
另外,先安装mock的依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
参考设置存储库
只有一种选项:
虽然可能已经包括在initializr中,但是还是写下Spring的内容。
将使用Nexus等工具运营私有的maven仓库的人也在此进行补充。
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
对于AWS
越来越随意地变得,真抱歉。
设置Spring Cloud和AWS的SDK的依赖关系
由于不清楚该如何添加AWS的SDK依赖,或者使用Spring Cloud来解决问题,我感到很尴尬,不太想写太多。
向日志添加器添加访问日志。
将日志从Kubernetes的Pod发送到Cloud Watch Logs所需的步骤。
目前的情况好像还勉强能应付得过去。
在Github公开的项目中,至少有一个不应该使用的。至少这个我一直都在很好地运作。
<dependency>
<groupId>com.j256.cloudwatchlogbackappender</groupId>
<artifactId>cloudwatchlogbackappender</artifactId>
<version>2.1</version>
</dependency>
请创建一个像这样的班级。
public class AccessLogAppender<E> extends ConsoleAppender<E>
如果不进行这种设置,就不行了。
<configuration>
<appender name="CONSOLE" class="jp.nreso.project.api.log.AccessLogAppender">
<dateFormat>yyyyMMdd_HHmm</dateFormat>
<encoder>
<pattern>%h %l %user "%r" %s %b</pattern>
</encoder>
</appender>
<appender-ref ref="CONSOLE"/>
</configuration>
似乎没有正常发送。
尽管不经过这条道路,只要在容器中对FluentD进行设置就可以,但是由于某种特定原因,我一直希望将日志输出到Java端。
Docker配置ECR的设置
为了CI/CD,可以在maven运行时使用参数指定存储库的URL和凭据等信息。
这个文字之后变得模糊不清,无法阅读。