概要
SpringBoot ⇒ MicrosoftAccessへ接続して、データの取得や更新の処理を作ることを諦めました。
今後似たようなことを検討する時の材料として記事を残します。
やりたかったこと
MicrosoftAccess(accdbファイル)で作られた古いシステムがありました。
SpringBootでそのシステムが持っているテーブルのデータが必要でした。
また、ちょっとめんどくさい点として、そのaccdbファイルはパスワードでロックされているものでした。
UCanAccessの存在
まず、『UCanAccess』というjarがあり、それを使うとJAVAからAccessへの接続ができると分かりました。
build.gradleでjarの用意
build.gradleのdependenciesに下記を追加しました。
implementation ('net.sf.ucanaccess:ucanaccess:5.0.1'){
exclude module: 'commons-logging'
}
implementation ('com.healthmarketscience.jackcess:jackcess-encrypt:4.0.1') {
exclude module: 'commons-logging'
}
パスワード無しaccdbへ接続するだけならucanaccessのみでOKです。
ですが、パスワード付accdbだと jackcess-encryptも追加で必要 です。
また、 commons-loggingを除外 するのもポイントです。
この除外しないとSpring起動時に下記のような警告が出てしまいます。
Standard Commons Logging discovery in action with spring-jcl: please remove commons-logging.jar from classpath in order to avoid potential conflicts
UCanAccessもjackcess-encryptもcommons-logging.jarを使っています。
でもそのjarはSpringBootとなんか衝突して良くないから削除した方がいいよって警告です。
JackcessOpenerInterfaceの実装
jarを用意するだけでは足りず、下記のようなクラスを自作する必要があります。
package com.example.demo;
import java.io.File;
import java.io.IOException;
import com.healthmarketscience.jackcess.Database;
import com.healthmarketscience.jackcess.DatabaseBuilder;
import com.healthmarketscience.jackcess.crypt.CryptCodecProvider;
import net.ucanaccess.jdbc.JackcessOpenerInterface;
//クラス名に縛りは無いです。
//今回はこんな名前にしてみました。
public class Dec implements JackcessOpenerInterface {
@Override
public Database open(File file, String password) throws IOException {
DatabaseBuilder db_ = new DatabaseBuilder(file);
db_.setAutoSync(false);
db_.setCodecProvider(new CryptCodecProvider(password));
db_.setReadOnly(false);
return db_.open();
}
}
Controllerクラス
package com.example.demo;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import jakarta.servlet.http.HttpServletResponse;
@Controller
public class DemoController {
@GetMapping("/")
public void getIndex(HttpServletResponse response) throws IOException {
String url_ = "jdbc:ucanaccess://C:/※フォルダー/dr.accdb;";
//パスワード付accdbの場合、jackcessOpenerに自作クラスを指定するのがポイント。
url_ += "jackcessOpener=com.example.demo.Dec;";
//accdbの場合、ユーザー名は空文字でOK。
String user_ = "";
String password_ = "※パスワード";
try (Connection connection_ = DriverManager.getConnection(url_, user_, password_)) {
System.out.println("接続できた");
String sql_ = "SELECT * FROM t1";
try (Statement statement = connection_.createStatement();
ResultSet resultSet = statement.executeQuery(sql_)) {
while (resultSet.next()) {
System.out.println(resultSet.getString("カラム名だにゃん"));
}
}
} catch (Exception e_) {
e_.printStackTrace();
}
}
}
接続できるが大量の警告が…
この警告が
- 何が原因で起きてるのか。
- 無視してよいものかどうか。
が分からず、突っ込んで調べる時間も無かったです。
これが諦めた理由の一つです。
Accessのデータベース並び順設定によっては更なる警告も
下記のように変更して、さらに『最適化修復』をすれば警告は出なくなります。
これについても、『変更して想定外のバグが起きないか』の判断ができず、動作検証の時間もありませんでした。
運悪く対象のaccdbは『日本語 - レガシー』で作られていました…。
これも諦めた理由の一つです。
蛇足
別プログラムからAccessに接続するならC#がめちゃくちゃ楽でした。
「JAVAで悪戦苦闘してたのは一体何だったの…」
ってレベルでサクッと動作確認サンプル作れました。
バージョン
Microsoft Windows [Version 10.0.19045.4170]
JAVA 17.0.8.1
Spring Boot v3.1.10