MavenによるSpringプロジェクトの作成

## はじめに

spring frameworkの学習用にspring bootに頼らずspring MVCのプロジェクトを作成する方法の備忘録

Java17, spring framework6で構成しています

## 構築方法

- シンプルなプロジェクトの作成(アーキタイプ選択のスキップ)にチェック
  ![5037b3485edc45cfbfa2169e8d2cb660png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635129/ee628181-93c0-9d13-c93c-7525508d0ffb.png)

- グループID：ルートパッケージ名
- アーティファクトID：プロジェクト名
  ![4ba60c68c48f4a8c868f59fe5e45d5c0png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635129/918a7dc5-2b39-3263-1792-9d6700981d60.png)

## pom.xml

```xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.demo.example</groupId>
  <artifactId>springDBSample</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <!-- プロパティ -->
  <properties>
    <java.version>17</java.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <org.springframework.version>6.1.4</org.springframework.version>
    <org.thymeleaf.version>3.1.1.RELEASE</org.thymeleaf.version>
  </properties>
  <!-- springMVC -->
  <dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${org.springframework.version}</version>
    </dependency>
    <!-- Validation用のHibernate Validator -->
    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
       <version>2.0.9</version>
    </dependency>
    <!-- Apache Commons Logging -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.5.3</version>
    </dependency>
  </dependencies>
</project>
```

## 動的webモジュール追加

1. [プロパティ] > [プロジェクト・ファセット] > [プロジェクト・ファセット]にチェック
  ![98d625dadb604523ad9167777985c43bpng](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3635129/556f0e55-1375-154a-41c4-540f14eb014b.png)
  
2. [プロジェクトを閉じる] > [プロジェクトを開く]でプロジェクト開きなおす
  
3. [JavaEE ツール] > [デプロイメント記述子スタブの生成]を選択する2. と同様にプロジェクトを開きなおすとweb.xmlが生成される
  

## 最終的なファイル構成

```
SpringMvcSample/src/
│ 
├── java/
|   └── com/example/demo/
|       ├── app/
|       |   └──WelcomeController.java
|       └── config/
|           ├── AppConfig.java
|           ├── DispatcherServlet.java
|           └── WebMvcConfig.java
└── webapp/
    ├── WEB-INF/
    |   ├── lib/
    |   |   ├── jakarta.servlet.jsp.jstl-x.x.x.jar
    |   |   └── jakarta.servlet.jsp.jstl-api-x.x.x.jar
    |   ├── web.xml
    |   └── include.jsp
    └── index.jsp

pom.xml
```

lib/配下のjarはタグライブラリ用のライブラリファイル

## web.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
<display-name>springDBSample</display-name>
  <!-- リスナーの設定 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- AnnotationConfigWebApplicationContextクラスを初期化パラメータに指定 -->
  <context-param>
    <param-name>contextClass</param-name>
    <param-value>
       org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
  </context-param>
  <!-- コンフィギュレーションクラスを初期化パラメータに指定  -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.example.config.AppConfig</param-value>
  </context-param>

  <!-- DispatcherServletをサーブレットコンテナに登録 -->
  <servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- contextClassパラメータにAnnotationConfigWebApplicationContextに登録 -->
    <init-param>
      <param-name>contextClass</param-name>
      <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
    </init-param>
      <!-- contextConfigLocationパラメータにコンフィギュレーションクラスを登録 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        com.example.config.DispatcherServlet
      </param-value>
    </init-param>
  </servlet>
  <!-- DispatcherServletのマッピング -->
  <servlet-mapping>
    <servlet-name>app</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- 文字エンコード設定 -->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>
      org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- タグライブラリの設定 -->
  <jsp-config>
    <jsp-property-group>
      <url-pattern>*.jsp</url-pattern>
      <page-encoding>UTF-8</page-encoding>
      <include-prelude>/WEB-INF/including.jsp</include-prelude>
    </jsp-property-group>
  </jsp-config>
</web-app>
```

#### メモ

- `<listener>`要素：アプリケーションイベント(アプリやセッションの開始/終了など)時の共通処理
- `<context-param>`要素：アプリの内の中で使える共通処理
- `<servlet>`要素：サーブレットの登録を行います
- `<servlet>`要素内の`<init-param>`要素ははサーブレット読み込み時の初期化処理を行う
- forceEncodingをフィルターに設定すると指定の文字エンコーディングで強制上書きされる
- `<jsp-config>`要素の`<url-pattern>*.jsp</url-pattern>`に*.jspと`<include-prelude>`要素に/WEB-INF/including.jspを設定することですべてのJSPにタグライブラリがインクルードされる

## JavaConfig用のコンフィギュレーションクラスを作成

web.xmlで設定したJavaconfig用のクラスを作成します

```java
package com.example.demo.config;

import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

}
```

## DispatcherServletの作成

`<Servlet>`要素に設定したDispatcherServletクラスを作成する
`<servlet-mapping>`要素の`<url-pattern>`要素でルートパスを指定しているためアクセスしてきたときこのクラスが参照される
`@ComponentScan("com.example.demo.app")`の設定により`com.example.demo.app`配下のコンポーネントスキャンが行われ、Bean定義が行われる
web.xmlのサーブレットの`contextConfigLocation`に設定したコンフィギュレーションクラスによりView名の解決を行う
ここではJSPの設定を行っている

```java
package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
@ComponentScan("com.example.demo.app")
public class DispatcherServlet implements WebMvcConfigurer{
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp();
    }
}
```

:::note warn
※WebMvcConfigurerAdapterは非推奨のためWebMvcConfigurerを実装する
:::

## コントローラーの作成

```java
package com.example.demo.app;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class WelcomeController {

    @RequestMapping("/")
    public String home() {
        return "index";
    }
}
```

## ビューの作成

```jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>Hello Word!!</h1>
</body>
</html>
```