春季启动器的配置备忘录

这是什么?

这是我总结的我在搭建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>&nbsp;
  <a href="swagger-ui/index.html?url=/api/api-docs/client1">client 1</a>&nbsp;
  <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和凭据等信息。

这个文字之后变得模糊不清,无法阅读。