はじめに
10数年前に作成された社内システム(Struts + tomcat + hibernate + SQL Server)があり、Windows Server 2003R2 + SQL Server 2005 で動作していました。流石に昨年にWindows Server 2016に切り替えたのですが、DBはSQL Server 2005のままとなっています。SQL Server 2014に切り替えようとしたのですが、「com.microsoft.sqlserver.jdbc.SQLServerException: サーバーのバージョンがサポートされていません。」のエラーとなり、DBにアクセス出来なくなってしまうからです。
原因は、sqljdbc.jar
を使用しているためで、sqljdbc4.jar
に差し替える必要があるのですが、流石にファイルを変えたくらいでは動作せず、環境構築すら出来ない状態です。
古い環境は捨てて新しい環境で作り直すのはいいんですが、社内システムなので時間はあまり掛けれません。何より今はJavaの知識が足りてません。
Javaの勉強
Javaは、改修作業でクラスの一部を変えたくらいしかしたことがなく、環境構築やフレームワークまわりの知識は化石状態です。
Eclipse 2023をインストールして、WebフレームワークとSQLServerにアクセスくらいまでは動かしたいと思った次第です。
目的にあった下記サイトのプロジェクトが動かそうと四苦八苦しました。
Spring Bootでデータベース(SQL Server)にアクセスする方法
環境
- Windows 11 Home
- Eclipse 2023
- SQL Server 2022(開発者向けの無料エディション)
- Microsoft SQL Server Management Studio
- Java 17
- Maven
- Spring Boot 3.1.0
- Spring Data JPA 3.1.0
- Spring Thymleaf 3.1.0
- Lombok 1.18.26
- mssql-jdbc 11.2.3
説明
- Mavenは、JavaプログラムをビルドするためのツールでC言語だとmakeのようなもの、
pom.xml
に依存関係を記述すればSpring Bootなどのフレームワークのダウンロードなど自動でしてくれます。読み方は「メイヴェン」です。 - Spring bootは、環境設定を簡略化しJavaによる開発を効率化できるフレームワークです。今回はWebアプリケーションの開発をサポートするフレームワークとして使用する。Strutsの代替と思えばいい。
- Spring Data JPAは、Spring BootのO/RマッパーでJavaクラスとDBテーブルをつなぎ合わせてくれるHibernate(ハイバーネート)ライブラリを内部実装している。
- Spring Thymleafは、テンプレートエンジンの1つで表示に関する処理しか記述できません、読み方は「タイムリーフ」です。
- Lombokは、 アノテーションによってセッターやゲッター、コンストラクターなどのクラスの機能を自動生成するためのライブラリです。読み方は「ロンボック」または「ロンボク」です。
プロジェクト作成
「新規 Spring スターター・プロジェクトの作成」を選択します。
名前を「HelloSqlServer」にしました。
- Spring Boot DevTools
- Lombok
- Spring Data JPA
- MS SQL Server Driver
- Thymleaf
- Spring Web
※使用頻度高の欄はデフォルトボタンで中身が書き換わるので、表示内容は個人により違います。
ソースコード
下記サイトの内容を、環境に合わせて一部書き換えています。
Spring Bootでデータベース(SQL Server)にアクセスする方法
DB接続情報の設定
spring.datasource.url=jdbc:sqlserver://localhost:1433;databaseName=testdb;encrypt=true;trustServerCertificate=true
spring.datasource.username=sa
spring.datasource.password=password
モデル
javax.persistence
ではエラーになるためjakarta.persistence
に書き換えています。
package com.example.model;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "weather")
public class Weather {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer temperature;
private Integer humidity;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getTemperature() {
return temperature;
}
public void setTemperature(Integer temperature) {
this.temperature = temperature;
}
public Integer getHumidity() {
return humidity;
}
public void setHumidity(Integer humidity) {
this.humidity = humidity;
}
}
リポジトリ
package com.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.model.Weather;
@Repository
public interface WeatherRepository extends JpaRepository<Weather, Integer> {
}
サービス
package com.example.services;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.model.Weather;
import com.example.repository.WeatherRepository;
@Service
public class WeatherService {
@Autowired
WeatherRepository weatherRepository;
/**
* レコードを全件取得する。
*
* @return
*/
public List<Weather> findAllWeatherData() {
return weatherRepository.findAll();
}
}
コントローラ
package com.example;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.model.Weather;
import com.example.services.WeatherService;
@Controller
public class HelloSqlServerController {
@Autowired
WeatherService weatherService;
@RequestMapping("/")
public String hello(Model model) {
model.addAttribute("title", "SQL Serverから取得したデータ");
// 気象データの取得
List<Weather> weatherDataList = weatherService.findAllWeatherData();
model.addAttribute("weatherDataList", weatherDataList);
return "index";
}
}
テンプレート
src/main/resourceフォルダのtemplateフォルダに作成します。
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title></title>
</head>
<body>
<p>
<span th:text="${title}">Hello World!</span>
</p>
<table>
<tr th:each="data : ${weatherDataList}" th:object="${data}">
<td th:text="*{id}"></td>
<td th:text="*{name}"></td>
<td th:text="*{temperature}"></td>
<td th:text="*{humidity}"></td>
</tr>
</table>
</body>
</html>
最終プロジェクト
DB作成
データベース作成
Microsoft SQL Server Management Studioでサーバーに接続後、今回は新しいデータベースとして「testdb」を作成します。
テーブル作成
create table weather (
id int NOT NULL IDENTITY (1, 1) primary key, -- ID
name varchar(20), -- 地名
temperature int, -- 気温
humidity int, -- 湿度
);
データ追加
insert into weather (name, temperature, humidity) values
('稚内', 1, 55),
('盛岡', 6, 53),
('前橋', 10, 40),
('名古屋', 12, 65),
('佐賀', 14, 67),
('那覇', 22, 69);
認証モード
最初はWindows認証でやろうとしたのですが、mssql-jdbc_auth(以前の sqljdbc_auth.dll)の導入が必要だったりと面倒くさくなったので、素直にSQL Server認証モードにしました。
実行
実行で「Spring Bootアプリケーション」をクリックします。
ブラウザで以下のURLを開きます。
http://localhost:8080/
以下のように、SQL Serverからデータを読み込んで表示できました。
最後に
何とか、Spring Boot + SQL Serverにアクセスするところまで出来ました。今の社内システムをあまり時間を掛けないで移植するには、JSPを動くようにする必要があります。それはまた別途記事にします。
休日に自宅で試した結果から会社で同じことを実行しようとしたのですが、これが嵌まりました。
会社だと「Spring スターター・プロジェクトの作成」から「利用可能なコンテンツがありません」と出たり、Mavenを使用するとダウンロードエラーとなるなど、プロジェクト作成すら出来ない状態で解決するまで一苦労でした。
原因はセキュリティに関連するもので、証明書をkeytoolを使用して登録する必要がありました。これもまた別途記事にしたいと思います。