Spring Boot + Spring Integration でいろいろ試してみる ( その4 )( 監視しているディレクトリに置かれた Excel ファイルのデータを DB に登録する → 処理が終わったら Excel ファイルを削除/移動する )
概要
記事一覧はこちらです。
- Spring Boot + Spring Integration でいろいろ試してみる ( その3 )( ディレクトリを監視してファイルが置かれたら処理→削除/移動する常駐型アプリケーションを作成する ) で作成した常駐型アプリケーションに以下の機能を追加してみます。
- データを登録するテーブルは Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( その5 )( DB、テーブルの作成 ) で作成した user_info, user_role テーブルを使用します。
- Spring Integration には Excel ファイルを処理するライブラリはありませんので、JXLS を利用します。
- DB の登録処理は Spring Integration が提供する 18. JDBC Support ではなく Doma 2 を使います。
- Excel は Office 365 のものを使用します。
長いので2回に分けます。
参照したサイト・書籍
Jxls Reader
http://jxls.sourceforge.net/reference/reader.htmlSpring Framework Reference Documentation - 8. Resources
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
目次
- 追加する機能の仕様をまとめる
- build.gradle を変更する
- Doma 2 を使うためのファイル・設定を追加し Dao, Entity を生成する
- Filter を作成する
- 動作確認
- Jxls Reader を利用して Excel ファイルのデータを読み込む処理を実装する
- 長くなり過ぎたので次回へ。。。
手順
追加する機能の仕様をまとめる
現在以下の画像のフローですが、
filter と excelToDbChannel を追加して以下のフローに変更します。
※画像は STS の integration-graph で描いています。
Filter を追加して、拡張子が .xlsx でなければ例外を throw して処理を異常終了させます。
※Filter は本来戻り値に boolean 型を返して Message を次の Channel に渡すか否かを判断するためのものですが、例外を throw しないと PseudoTransactionManager によるトランザクション処理が rollback しないので、今回は .xlsx でなければ例外を throw し、そうでなければ true を戻すように実装します。- excelToDbChannel を DirectChannel として追加します。DirectChannel にするのは checkFile –> filter –> process の一連の流れを1つのトランザクションとして処理するためです ( filter、process で例外が throw されるとファイルは error ディレクトリに移動されます )。
Excel ファイルは以下の画像のフォーマットとします。
- 項目は名前、パスワード、メールアドレス、権限の4個です。
- 1行目はヘッダ行、2行目以降をデータ行とします。
- 権限はカンマ区切りで複数記入可能とします。
process では Excel ファイルのデータを1行ずつ以下のように処理します。
- 名前、パスワード、メールアドレスのデータを user_info テーブルに追加します。パスワードは追加持に Spring Security の BCryptPasswordEncoder#encode で暗号化します。
- 権限のデータをカンマを区切り文字として分解して、権限の個数分 user_role テーブルに追加します。
- Service Activator の process では Excel ファイルの全データが登録できたら commit し、できなかった場合には rollback されるようにします。
build.gradle を変更する
feature/5-issue ブランチを作成します。
build.gradle を リンク先のその1の内容 に変更します。
Gradle projects View の左上にある「Refresh all Gradle projects」ボタンをクリックして build.gradle を反映します。
Doma 2 を使うためのファイル・設定を追加し Dao, Entity を生成する
ksbysample-webapp-lending から以下のファイルをコピーします。
※→ のあるファイルは → に書かれた場所に配置します。
- src/main/java/ksbysample/webapp/lending/config/DomaConfig.java
→ src/main/java/ksbysample/eipapp/dirchecker/config/DomaConfig.java - src/main/java/ksbysample/webapp/lending/util/doma/ComponentAndAutowiredDomaConfig.java
→ src/main/java/ksbysample/eipapp/dirchecker/util/doma/ComponentAndAutowiredDomaConfig.java - src/main/java/ksbysample/webapp/lending/util/doma/SelectOptionsUtils.java
→ src/main/java/ksbysample/eipapp/dirchecker/util/doma/SelectOptionsUtils.java - src/main/resources/log4jdbc.log4j2.properties
- src/main/java/ksbysample/webapp/lending/config/DomaConfig.java
src/main/resources の下に application.properties を作成し、リンク先の内容 の内容に変更します。
src/main/java/ksbysample/eipapp/dirchecker の下の Application.java を リンク先の内容 に変更します。
Gradle projects View から domaGen タスクを実行して Dao, Entity を生成します。
Gradle projects View から bootRun タスクを実行して正常に起動するか確認します。Doma 2 の SQL ファイル生成後はそのまま起動するとエラーが出る場合があるので、clean タスク実行 → Rebuild Project 実行をした後に bootRun タスクを実行します。
Tomcat が起動したことを確認できたら Ctrl+F2 を押して停止します。
Filter を作成する
src/main/java/ksbysample/eipapp/dirchecker/eip/channel の下の ChannelConfig.java を リンク先の内容 に変更します。
src/main/java/ksbysample/eipapp/dirchecker/eip/endpoint の下の InDirChecker.java を リンク先の内容 に変更します。
src/main/java/ksbysample/eipapp/dirchecker/eip/endpoint の下の FileProcessor.java を リンク先の内容 に変更します。
動作確認
Gradle projects View から bootRun を実行します。
C:\eipapp\ksbysample-eipapp-dirchecker\data\in に「テストファイル1.xlsx」というファイルを配置すると、ファイルがなくなりました。
↓↓↓
C:\eipapp\ksbysample-eipapp-dirchecker\data\in に「テストファイル2.txt」というファイルを配置すると、error ディレクトリに移動しました。
↓↓↓
Ctrl+F2 を押して Tomcat を停止します。
Jxls Reader を利用して Excel ファイルのデータを読み込む処理を実装する
Jxls Reader で Excel ファイルを処理するためには、
ですので、この順で実装します。
src/main/java/ksbysample/eipapp/dirchecker の下に service.userinfo パッケージを作成します。
src/main/java/ksbysample/eipapp/dirchecker/service/userinfo の下に UserInfoExcelRow.java を作成します。作成後、リンク先の内容 に変更します。
getRoleListFromRoles メソッドの動作確認をしたいのでテストクラスを作成します。UserInfoExcelRow.java のソース上で Ctrl+Shift+T を押してコンテキストメニューを表示した後「Create New Test…」を選択します。「Create Test」ダイアログが表示されたら以下の画像の状態にした後、「OK」ボタンをクリックします。
「Choose Destination Directory」ダイアログが表示されたら「…\src\test\groovy...」の方を選択して「OK」ボタンをクリックします。
src/test/groovy/ksbysample/eipapp/dirchecker/service/userinfo の下に UserInfoExcelRowTest.groovy が作成されますので、リンク先の内容 に変更します。
今の記述では groovy でコンパイルが出来なかったので build.gradle を リンク先のその2の内容 に変更します。
テストを実行して全て成功することを確認します。
Excel ファイルとデータ格納用クラスの対応関係を記述した XML ファイルを作成します。src/main/resources の下に ksbysample/eipapp/dirchecker/service/userinfo ディレクトリを作成します。
src/main/resources/ksbysample/eipapp/dirchecker/service/userinfo の下に userinfo-excel-cfg.xml を作成します。作成後、リンク先の内容 に変更します。
処理を行う Service クラスを実装します。src/main/java/ksbysample/eipapp/dirchecker/service/userinfo の下に UserInfoService.java を作成します。作成後、リンク先の内容 に変更します。
UserInfoService#loadFromExcelToList の動作確認をしたいのでテストクラスを作成します。テスト用の Excel ファイルを src/test/resources の下に配置しますので、まずは src/test/resources の下に ksbysample/eipapp/dirchecker/service/userinfo ディレクトリを作成します。
src/test/resources/ksbysample/eipapp/dirchecker/service/userinfo の下に以下の画像の Excel ファイルを TestData01.xlsx というファイル名で配置します。
テストで AssertJ が使いたいので build.gradle を リンク先のその3の内容 に変更します。
Gradle projects View の左上にある「Refresh all Gradle projects」ボタンをクリックして build.gradle を反映します。
UserInfoService.java のソース上で Ctrl+Shift+T を押してコンテキストメニューを表示した後「Create New Test…」を選択します。「Create Test」ダイアログが表示されたら以下の画像の状態にした後、「OK」ボタンをクリックします。
「Choose Destination Directory」ダイアログが表示されたら「…\src\test\java...」の方を選択して「OK」ボタンをクリックします。
src/test/java/ksbysample/eipapp/dirchecker/service/userinfo の下に UserInfoServiceTest.java が作成されますので、リンク先の内容 に変更します。
テストを実行して全て成功することを確認します。
長くなり過ぎたので次回へ。。。
長くなり過ぎたので一旦区切ります。その2へ。
以下メモ書きです。
- Spring Integration をやるなら STS の integration-graph は便利ですね ( というより必須? )。XML ファイルベースでやるなら、GUI で簡単に XML ファイルを作成できます。
ソースコード
build.gradle
■その1
group 'ksbysample' version '1.1.0-RELEASE' buildscript { ext { springBootVersion = '1.3.7.RELEASE' } repositories { jcenter() maven { url "http://repo.spring.io/repo/" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") classpath("io.spring.gradle:dependency-management-plugin:0.6.0.RELEASE") // for Grgit classpath("org.ajoberstar:grgit:1.7.0") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'spring-boot' apply plugin: 'io.spring.dependency-management' apply plugin: 'groovy' sourceCompatibility = 1.8 targetCompatibility = 1.8 compileJava.options.compilerArgs = ['-Xlint:all'] compileTestGroovy.options.compilerArgs = ['-Xlint:all'] compileTestJava.options.compilerArgs = ['-Xlint:all'] eclipse { classpath { containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER') containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8' } } idea { module { inheritOutputDirs = false outputDir = file("$buildDir/classes/main/") } } configurations { domaGenRuntime } repositories { jcenter() } dependencyManagement { imports { mavenBom 'io.spring.platform:platform-bom:2.0.7.RELEASE' } } dependencies { def jdbcDriver = "org.postgresql:postgresql:9.4.1209" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix A. Dependency versions ( http://docs.spring.io/platform/docs/current/reference/htmlsingle/#appendix-dependency-versions ) 参照 compile('org.springframework.boot:spring-boot-starter-integration') compile('org.springframework.integration:spring-integration-file') compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-data-jpa") testCompile("org.springframework.boot:spring-boot-starter-test") testCompile("org.spockframework:spock-core") { exclude module: "groovy-all" } testCompile("org.spockframework:spock-spring") { exclude module: "groovy-all" } // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの runtime("${jdbcDriver}") compile("org.seasar.doma:doma:2.12.1") compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") compile("org.projectlombok:lombok:1.16.10") compile("org.apache.commons:commons-lang3:3.4") compile("org.jxls:jxls-reader:2.0.2") // for Doma-Gen domaGenRuntime("org.seasar.doma:doma-gen:2.12.1") domaGenRuntime("${jdbcDriver}") } // for Doma-Gen task domaGen << { // まず変更が必要なもの def rootPackageName = 'ksbysample.eipapp.dirchecker' def daoPackagePath = 'src/main/java/ksbysample/eipapp/dirchecker/dao' def dbUrl = 'jdbc:postgresql://localhost/ksbylending' def dbUser = 'ksbylending_user' def dbPassword = 'xxxxxxxx' def tableNamePattern = '.*' // おそらく変更不要なもの def importOfComponentAndAutowiredDomaConfig = "${rootPackageName}.util.doma.ComponentAndAutowiredDomaConfig" def workDirPath = 'work' def workDaoDirPath = "${workDirPath}/dao" // 作業用ディレクトリを削除する clearDir("${workDirPath}") // 現在の Dao インターフェースのバックアップを取得する copy() { from "${daoPackagePath}" into "${workDaoDirPath}/org" } // Dao インターフェース、Entity クラスを生成する ant.taskdef(resource: 'domagentask.properties', classpath: configurations.domaGenRuntime.asPath) ant.gen(url: "${dbUrl}", user: "${dbUser}", password: "${dbPassword}", tableNamePattern: "${tableNamePattern}") { entityConfig(packageName: "${rootPackageName}.entity", useListener: false) daoConfig(packageName: "${rootPackageName}.dao") sqlConfig() } // 生成された Dao インターフェースを作業用ディレクトリにコピーし、 // @ComponentAndAutowiredDomaConfig アノテーションを付加する copy() { from "${daoPackagePath}" into "${workDaoDirPath}/replace" filter { line -> line.replaceAll('import org.seasar.doma.Dao;', "import ${importOfComponentAndAutowiredDomaConfig};\nimport org.seasar.doma.Dao;") .replaceAll('@Dao', '@Dao\n@ComponentAndAutowiredDomaConfig') } } // @ComponentAndAutowiredDomaConfig アノテーションを付加した Dao インターフェースを // dao パッケージへ戻す copy() { from "${workDaoDirPath}/replace" into "${daoPackagePath}" } // 元々 dao パッケージ内にあったファイルを元に戻す copy() { from "${workDaoDirPath}/org" into "${daoPackagePath}" } // 作業用ディレクトリを削除する clearDir("${workDirPath}") // 自動生成したファイルを git add する addGit() } /* ----------------------------------------------------------------------------- * メソッド定義部 ---------------------------------------------------------------------------- */ void clearDir(String dirPath) { delete dirPath } void addGit() { def grgit = org.ajoberstar.grgit.Grgit.open(dir: project.projectDir.parent) grgit.add(patterns: ['.']) }
- version を
1.0.0-RELEASE
→1.1.0-RELEASE
へ変更します。 - buildscript に
classpath("org.ajoberstar:grgit:1.7.0")
を追加します。 configurations { domaGenRuntime }
を追加します。- dependencies に以下の記述を追加します。
def jdbcDriver = "org.postgresql:postgresql:9.4.1209"
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
runtime("${jdbcDriver}")
compile("org.seasar.doma:doma:2.12.1")
compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16")
compile("org.jxls:jxls-reader:2.0.2")
domaGenRuntime("org.seasar.doma:doma-gen:2.12.1")
domaGenRuntime("${jdbcDriver}")
task domaGen << { ... }
を追加します。- clearDir メソッドを追加します。
- addGit メソッドを追加します。open するディレクトリの指定は
project.projectDir
→project.projectDir.parent
へ変更します。
■その2
dependencies { def jdbcDriver = "org.postgresql:postgresql:9.4.1209" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix A. Dependency versions ( http://docs.spring.io/platform/docs/current/reference/htmlsingle/#appendix-dependency-versions ) 参照 compile('org.springframework.boot:spring-boot-starter-integration') compile('org.springframework.integration:spring-integration-file') compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-data-jpa") testCompile("org.springframework.boot:spring-boot-starter-test") testCompile("org.spockframework:spock-core") testCompile("org.spockframework:spock-spring") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの runtime("${jdbcDriver}") compile("org.seasar.doma:doma:2.12.1") compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") compile("org.projectlombok:lombok:1.16.10") compile("org.apache.commons:commons-lang3:3.4") compile("org.jxls:jxls-reader:2.0.2") // for Doma-Gen domaGenRuntime("org.seasar.doma:doma-gen:2.12.1") domaGenRuntime("${jdbcDriver}") }
- spock-core, spock-spring の後の
{ exclude module: "groovy-all" }
の記述を削除します。
■その3
dependencies { def jdbcDriver = "org.postgresql:postgresql:9.4.1209" // dependency-management-plugin によりバージョン番号が自動で設定されるもの // Appendix A. Dependency versions ( http://docs.spring.io/platform/docs/current/reference/htmlsingle/#appendix-dependency-versions ) 参照 compile('org.springframework.boot:spring-boot-starter-integration') compile('org.springframework.integration:spring-integration-file') compile("org.springframework.boot:spring-boot-starter-security") compile("org.springframework.boot:spring-boot-starter-data-jpa") testCompile("org.springframework.boot:spring-boot-starter-test") testCompile("org.spockframework:spock-core") testCompile("org.spockframework:spock-spring") // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの runtime("${jdbcDriver}") compile("org.seasar.doma:doma:2.12.1") compile("org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16") compile("org.projectlombok:lombok:1.16.10") compile("org.apache.commons:commons-lang3:3.4") compile("org.jxls:jxls-reader:2.0.2") testCompile("org.assertj:assertj-core:3.5.2") // for Doma-Gen domaGenRuntime("org.seasar.doma:doma-gen:2.12.1") domaGenRuntime("${jdbcDriver}") }
- dependencies に
testCompile("org.assertj:assertj-core:3.5.2")
を追加します。
application.properties
hibernate.dialect=org.hibernate.dialect.PostgreSQL9Dialect doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect spring.datasource.url=jdbc:log4jdbc:postgresql://localhost/ksbylending spring.datasource.username=ksbylending_user spring.datasource.password=xxxxxxxx spring.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy spring.datasource.initial-size=1
Application.java
package ksbysample.eipapp.dirchecker; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; @SpringBootApplication(exclude = {JpaRepositoriesAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
@SpringBootApplication
→@SpringBootApplication(exclude = {JpaRepositoriesAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
へ変更します。
ChannelConfig.java
package ksbysample.eipapp.dirchecker.eip.channel; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.integration.channel.DirectChannel; import org.springframework.messaging.MessageChannel; @Configuration public class ChannelConfig { @Bean public MessageChannel inChannel() { return new DirectChannel(); } @Bean public MessageChannel excelToDbChannel() { return new DirectChannel(); } }
@Bean public MessageChannel excelToDbChannel() { ... }
を追加します。
InDirChecker.java
package ksbysample.eipapp.dirchecker.eip.endpoint; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.integration.annotation.Filter; import org.springframework.integration.annotation.InboundChannelAdapter; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.Poller; import org.springframework.integration.channel.NullChannel; import org.springframework.integration.file.FileReadingMessageSource; import org.springframework.integration.scheduling.PollerMetadata; import org.springframework.integration.transaction.DefaultTransactionSynchronizationFactory; import org.springframework.integration.transaction.ExpressionEvaluatingTransactionSynchronizationProcessor; import org.springframework.integration.transaction.PseudoTransactionManager; import org.springframework.integration.transaction.TransactionSynchronizationFactory; import org.springframework.messaging.Message; import org.springframework.scheduling.support.PeriodicTrigger; import org.springframework.transaction.interceptor.DefaultTransactionAttribute; import org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource; import org.springframework.transaction.interceptor.TransactionInterceptor; import java.io.File; import java.nio.file.Paths; import java.util.Collections; @MessageEndpoint public class InDirChecker { .......... @InboundChannelAdapter(value = "inChannel", poller = @Poller("checkFilePoller")) public Message<File> checkFile() { return inDirFileReadingMessageSource.receive(); } @Filter(inputChannel = "inChannel", outputChannel = "excelToDbChannel") public boolean filter(Message<File> message) { File file = message.getPayload(); if (!StringUtils.endsWith(file.getName(), ".xlsx")) { throw new RuntimeException( String.format("拡張子が .xlsx のファイルではありません ( %s )。", file.getName())); } return true; } }
@Filter(inputChannel = "inChannel", outputChannel = "excelToDbChannel") public boolean filter(Message<File> message) { ... }
を追加します。
FileProcessor.java
package ksbysample.eipapp.dirchecker.eip.endpoint; import org.springframework.integration.annotation.MessageEndpoint; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.messaging.Message; import java.io.File; @MessageEndpoint public class FileProcessor { @ServiceActivator(inputChannel = "excelToDbChannel") public void process(Message<File> message) throws Exception { File file = message.getPayload(); System.out.println(file.getAbsolutePath()); } }
@ServiceActivator(inputChannel = "inChannel")
→@ServiceActivator(inputChannel = "excelToDbChannel")
に変更します。
UserInfoExcelRow.java
package ksbysample.eipapp.dirchecker.service.userinfo; import lombok.Data; import org.apache.commons.lang3.StringUtils; import java.util.Arrays; import java.util.Collections; import java.util.List; @Data public class UserInfoExcelRow { private String username; private String password; private String mailAddress; private String roles; public List<String> getRoleListFromRoles() { List<String> result = Collections.EMPTY_LIST; if (StringUtils.isNotBlank(this.roles)) { String[] roleArray = roles.split(","); result = Arrays.asList(roleArray); } return result; } }
UserInfoExcelRowTest.groovy
package ksbysample.eipapp.dirchecker.service.userinfo import spock.lang.Specification import spock.lang.Unroll class UserInfoExcelRowTest extends Specification { @Unroll def "GetRoleListFromRoles(#roles) --> #result"() { given: UserInfoExcelRow userInfoExcelRow = new UserInfoExcelRow() userInfoExcelRow.roles = roles expect: userInfoExcelRow.getRoleListFromRoles() == result where: roles || result null || [] "" || [] "ROLE_USER" || ["ROLE_USER"] "ROLE_USER,ROLE_ADMIN" || ["ROLE_USER", "ROLE_ADMIN"] } }
userinfo-excel-cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <workbook> <worksheet name="Sheet1"> <section startRow="0" endRow="0"> </section> <loop startRow="1" endRow="1" items="userInfoExcelRowList" var="userInfoExcelRow" varType="ksbysample.eipapp.dirchecker.service.userinfo.UserInfoExcelRow"> <section startRow="1" endRow="1"> <mapping row="1" col="0">userInfoExcelRow.username</mapping> <mapping row="1" col="1">userInfoExcelRow.password</mapping> <mapping row="1" col="2">userInfoExcelRow.mailAddress</mapping> <mapping row="1" col="3">userInfoExcelRow.roles</mapping> </section> <loopbreakcondition> <rowcheck offset="0"> <cellcheck offset="0"></cellcheck> </rowcheck> </loopbreakcondition> </loop> </worksheet> </workbook>
UserInfoService.java
package ksbysample.eipapp.dirchecker.service.userinfo; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.jxls.reader.ReaderBuilder; import org.jxls.reader.XLSReadStatus; import org.jxls.reader.XLSReader; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; import org.xml.sax.SAXException; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Service public class UserInfoService { private static final String CLASSPATH_USERINFO_EXCEL_CFG_XML = "ksbysample/eipapp/dirchecker/service/userinfo/userinfo-excel-cfg.xml"; public List<UserInfoExcelRow> loadFromExcelToList(File excelFile) throws IOException, SAXException, InvalidFormatException { Resource rsExcelCfgXml = new ClassPathResource(CLASSPATH_USERINFO_EXCEL_CFG_XML); Resource rsUserInfoExcel = new FileSystemResource(excelFile.getAbsolutePath()); XLSReader reader = ReaderBuilder.buildFromXML(rsExcelCfgXml.getFile()); List<UserInfoExcelRow> userInfoExcelRowList = new ArrayList<>(); Map<String, Object> beans = new HashMap<>(); beans.put("userInfoExcelRow", new UserInfoExcelRow()); beans.put("userInfoExcelRowList", userInfoExcelRowList); try (InputStream isUserInfoExcel = new BufferedInputStream(rsUserInfoExcel.getInputStream())) { XLSReadStatus status = reader.read(isUserInfoExcel, beans); } return userInfoExcelRowList; } }
UserInfoServiceTest.java
package ksbysample.eipapp.dirchecker.service.userinfo; import ksbysample.eipapp.dirchecker.Application; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class) public class UserInfoServiceTest { private static final String CLASSPATH_EXCEL_FOR_TEST = "ksbysample/eipapp/dirchecker/service/userinfo/Book1.xlsx"; @Autowired private UserInfoService userInfoService; @Test public void loadFromExcelToList() throws Exception { Resource resource = new ClassPathResource(CLASSPATH_EXCEL_FOR_TEST); List<UserInfoExcelRow> userInfoExcelRowList = userInfoService.loadFromExcelToList(resource.getFile()); assertThat(userInfoExcelRowList).hasSize(2); assertThat(userInfoExcelRowList).extracting("username", "password", "mailAddress", "roles") .containsOnly(tuple("yota takahashi", "12345678", "yota.takahashi@test.co.jp", "ROLE_USER") , tuple("aoi inoue", "abcdefgh", "aoi.inoue@sample.com", "ROLE_ADMIN,ROLE_USER")); } }
履歴
2016/08/29
初版発行。
2016/08/29
* build.gradle から { exclude module: "groovy-all" }
を削除する記述を追加しました。