u-ryo's blog

various information for coding...

Category: Spring boot

CSV Download on Spring Boot REST

| Comments

Spring BootでCSV downloadを実現するのに、 Spring MVC で CSV をダウンロードさせるを参考にしました。 要するに、

  • compile "com.fasterxml.jackson.dataformat:jackson-dataformat-csv" in build.gradle
  • Bean classの各fieldに@JsonProperty
  • field出力順を制御したいので@JsonPropertyOrder({"login", "filename",...})
  • CsvMapper mapper = new CsvMapper();してCsvSchema schema = mapper.schemaFor(SomeBean.class).withHeader();してreturn mapper.writer(schema).writeValueAsString(beans);
  • compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"を入れて@JsonFormat(pattern="yyyy/MM/dd HH:mm:ss")してmapper.registerModule(new JavaTimeModule());すると、ZonedDateTimeを如意に表示できる?Formatting Java Time with Spring Boot using JSON

Daemonizing Jhipster Application

| Comments

JHipsterのapplicationで、 OS(Ubuntu 18.04)起動時にapplicationもdaemonとして自動起動するようにするには。

きっとSpring Bootでdaemonizeする方法を探ればいいと思って、 61. Installing Spring Boot Applicationsにあるように、

1
2
3
bootJar {
	launchScript()
}

でもこれ、Spring Boot 2での話で、 こちとらまだJHipster 4.14.4、Spring Bootは1.5です。 そんなものはない、と当然失敗します。 なのでもうちょっと古い記事を探しました。

spring bootアプリの起動スクリプトを作るを見て、

1
2
3
4
5
apply plugin: 'spring-boot'

springBoot {
    executable = true
}

としたんですが、plugin 'spring-boot'はないと言われ、 executable = truebuild.gradleに既に書いてありました。

そもそもそんなことしなくても、 Using in Production にあるように、

1
$ gradle bootRepackage -Pprod

でexecutable war作れるんですね。 で、それを/etc/init.d/にsymlinkすればいいだけという。 -Pprodを付けないとdevelopment versionになってしまいます。 あとは、update-rc.d appname defaultsで登録すれば良いです。

XML Marshaling in Spring Boot

| Comments

Spring Boot applicationで単一xml fileを返すREST作ってあって、 そこではxmlと同じ構造のJava bean作って返すだけで、 marshalingについてはframework側がよしなにやってくれました。 client側がHTTP Request HeaderにAccept: application/xmlとすれば。 そうでないとjsonになります。まぁそれはそれでいいんです。いいと思いました。

その後、複数xmlをまとめてZIPにして返すRESTを求められました。 そうすると、自分でXMLにmarshalingしなければなりません。 と、Gson? でもbuild.gradle見ると折角jackson読み込んでいるようなので、 jacksonでmarshalしました。new ObjectMapper()して、 mapper.write(ZipOutputStream)みたいなことすると、 一回(=one file)書いただけでstreamを勝手に? closeするようなので、 一旦Stringにしてからzos.write()しました。 また、build.gradlecompile "...jackson-dataformat-xml"も必要でした。

しかしそうすると、今度はXMLを返すRESTの方で、 返されるXMLの形が微妙に違っていました。具体的には、

  1. @XmlRootElement(name=...)で指定した名前が効かない
  2. XML Object中でList要素がnestされる (<object></object><object></object>...だったのが <object><object></object><object></object>...</object>に)

@XmlRootElementはJAXBのannotation (javax.xml.bind.annotation.XmlRootElement)で、 これが効かないというのだからJAXBが効いてないのだろうと思い、 そういえばbuild.gradlejackson-dataformat-xmlって書いたな、 というのを思い出し、 ZIP中でのXMLのmarshallingをJAXBのものでやるようにして build.gradleからjackson-dataformat-xmlを追い出したら、 元に戻りました。

JAXBでのmarshalling、ちょこっと面倒ですが、 context = JAXBContext.newInstance(Bean.class)して marshaller = context.createMarshaller()作って、 marshaller.marshal(bean, zipOutputStream)すればいいんですね。