Spring Boot Hello Worldの例–口ひげ

embedded Tomcat + Mustache template engineを使用したSpring Boot Webアプリケーションの例、および実行可能JARファイルとしてのパッケージ。
使用される技術:
-
Spring Boot 1.5.2.RELEASE
-
Spring 4.3.7.RELEASE
-
口ひげ1.13
-
Thymeleaf 2.1.5.RELEASE
-
Tomcat Embed 8.5.11
-
メーベン3
-
Java 8
1. プロジェクトディレクトリ

2. プロジェクトの依存関係
spring-boot-starter-mustacheを宣言します。これにより、Spring + MustacheWebアプリケーションの開発に必要なものがすべて取得されます。
pom.xml
4.0.0 spring-boot-web-mustache jar Spring Boot Web Mustache Example Spring Boot Web Mustache Example https://www.example.com 1.0 org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE 1.8 org.springframework.boot spring-boot-starter-mustache org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-devtools true org.webjars bootstrap 3.3.7 org.springframework.boot spring-boot-maven-plugin
プロジェクトの依存関係を表示します。
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Spring Boot Web Mustache Example 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ spring-boot-web-mustache ---
[INFO] org.springframework.boot:spring-boot-web-mustache:jar:1.0
[INFO] +- org.springframework.boot:spring-boot-starter-mustache:jar:1.5.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter:jar:1.5.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-logging:jar:1.5.2.RELEASE:compile
[INFO] | | | +- ch.qos.logback:logback-classic:jar:1.1.11:compile
[INFO] | | | | \- ch.qos.logback:logback-core:jar:1.1.11:compile
[INFO] | | | +- org.slf4j:jcl-over-slf4j:jar:1.7.24:compile
[INFO] | | | +- org.slf4j:jul-to-slf4j:jar:1.7.24:compile
[INFO] | | | \- org.slf4j:log4j-over-slf4j:jar:1.7.24:compile
[INFO] | | \- org.yaml:snakeyaml:jar:1.17:runtime
[INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:1.5.2.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-tomcat:jar:1.5.2.RELEASE:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:8.5.11:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-el:jar:8.5.11:compile
[INFO] | | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:8.5.11:compile
[INFO] | | +- org.hibernate:hibernate-validator:jar:5.3.4.Final:compile
[INFO] | | | +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] | | | +- org.jboss.logging:jboss-logging:jar:3.3.0.Final:compile
[INFO] | | | \- com.fasterxml:classmate:jar:1.3.3:compile
[INFO] | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.8.7:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.8.0:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-core:jar:2.8.7:compile
[INFO] | | +- org.springframework:spring-web:jar:4.3.7.RELEASE:compile
[INFO] | | | +- org.springframework:spring-aop:jar:4.3.7.RELEASE:compile
[INFO] | | | \- org.springframework:spring-beans:jar:4.3.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-webmvc:jar:4.3.7.RELEASE:compile
[INFO] | | \- org.springframework:spring-expression:jar:4.3.7.RELEASE:compile
[INFO] | \- com.samskivert:jmustache:jar:1.13:compile
[INFO] +- org.springframework.boot:spring-boot-starter-test:jar:1.5.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test:jar:1.5.2.RELEASE:test
[INFO] | +- org.springframework.boot:spring-boot-test-autoconfigure:jar:1.5.2.RELEASE:test
[INFO] | +- com.jayway.jsonpath:json-path:jar:2.2.0:test
[INFO] | | +- net.minidev:json-smart:jar:2.2.1:test
[INFO] | | | \- net.minidev:accessors-smart:jar:1.1:test
[INFO] | | | \- org.ow2.asm:asm:jar:5.0.3:test
[INFO] | | \- org.slf4j:slf4j-api:jar:1.7.24:compile
[INFO] | +- junit:junit:jar:4.12:test
[INFO] | +- org.assertj:assertj-core:jar:2.6.0:test
[INFO] | +- org.mockito:mockito-core:jar:1.10.19:test
[INFO] | | \- org.objenesis:objenesis:jar:2.1:test
[INFO] | +- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] | +- org.hamcrest:hamcrest-library:jar:1.3:test
[INFO] | +- org.skyscreamer:jsonassert:jar:1.4.0:test
[INFO] | | \- com.vaadin.external.google:android-json:jar:0.0.20131108.vaadin1:test
[INFO] | +- org.springframework:spring-core:jar:4.3.7.RELEASE:compile
[INFO] | \- org.springframework:spring-test:jar:4.3.7.RELEASE:test
[INFO] +- org.springframework.boot:spring-boot-devtools:jar:1.5.2.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot:jar:1.5.2.RELEASE:compile
[INFO] | | \- org.springframework:spring-context:jar:4.3.7.RELEASE:compile
[INFO] | \- org.springframework.boot:spring-boot-autoconfigure:jar:1.5.2.RELEASE:compile
[INFO] \- org.webjars:bootstrap:jar:3.3.7:compile
[INFO] \- org.webjars:jquery:jar:1.11.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.796 s
[INFO] Finished at: 2017-04-19T11:46:09+08:00
[INFO] Final Memory: 22M/437M
[INFO] ------------------------------------------------------------------------
3. 春のブーツ
3.1 Create a @SpringBootApplication class. このクラスを実行して、Spring Boot Webアプリケーションを起動します。
SpringBootWebApplication.java
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootWebApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootWebApplication.class, args);
}
}
3.2 A simple controller class.
WelcomeController.java
package com.example;
import java.util.Map;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class WelcomeController {
// inject via application.properties
@Value("${app.welcome.message}")
private String MESSAGE = "";
@Value("${app.welcome.title}")
private String TITLE = "";
@RequestMapping("/")
public String welcome(Map model) {
model.put("title", TITLE);
model.put("message", MESSAGE);
return "welcome";
}
// test 5xx errors
@RequestMapping("/5xx")
public String ServiceUnavailable() {
throw new RuntimeException("ABC");
}
}
4. 口ひげ+リソース+静的ファイル
4.1 For Mustache template files, put in src/main/resources/templates/
src/main/resources/templates/layout/header.html
{{title}}
src/main/resources/templates/layout/footer.html
src/main/resources/templates/welcome.html
{{>layout/header}}
Spring Boot Web Mustache Example
{{message}}
{{>layout/footer}}
4.2 For static files like CSS or Javascript, put in /src/main/resources/static/
/src/main/resources/static/css/main.css
h1{
color:#0000FF;
}
h2{
color:#FF0000;
}
4.3 For error templates.
Note
このSpring Boot – Error Handlingを読んで、デフォルトのエラーマッピングページがどのように機能するかを理解してください。
src/main/resources/templates/error.html
Something went wrong: {{status}} {{error}}
src/main/resources/templates/error/5xx.html
I'm a 5xx
4.4 For properties files, put in /src/main/resources/
/src/main/resources/application.properties
app.welcome.message: Hello Mkyong app.welcome.title: Spring Boot Mustache Hello World Example
Note
このSpring Boot Serving static contentを読んで、リソースマッピングを理解してください。
5. 単体テスト
5.1 Unit test example to test above Spring Boot web application.
MoustacheApplicationTests
package com.example;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@DirtiesContext
public class MustacheApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Test
public void testMainPage() throws Exception {
ResponseEntity entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("Hello Mkyong");
}
@Test
public void test404Page() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
HttpEntity requestEntity = new HttpEntity(headers);
ResponseEntity responseEntity = this.restTemplate.exchange("/uri-not-exist", HttpMethod.GET,
requestEntity, String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
assertThat(responseEntity.getBody()).contains("Something went wrong: 404 Not Found");
}
@Test
public void test5xxPage() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
HttpEntity requestEntity = new HttpEntity(headers);
ResponseEntity responseEntity = this.restTemplate.exchange("/5xx", HttpMethod.GET, requestEntity,
String.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(responseEntity.getBody()).contains("I'm a 5xx");
}
}
6. Demo
注
IDEで、@SpringBootApplicationアノテーション付きクラスを実行すると、SpringBootアプリケーション全体が起動します。
6.1 Start the Spring Boot web app.
ターミナル
project$ mvn spring-boot:run
//...
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.5.2.RELEASE)
2017-04-19 12:17:38.014 INFO 6232 --- [ restartedMain] com.example.SpringBootWebApplication : Starting SpringBootWebApplication on MKYONG-WIN10 with PID 6232 (C:\spring-boot\spring-boot-examples\spring-boot-web-mustache\target\classes started by example in C:\spring-boot\spring-boot-examples\spring-boot-web-mustache)
2017-04-19 12:17:38.015 INFO 6232 --- [ restartedMain] com.example.SpringBootWebApplication : No active profile set, falling back to default profiles: default
2017-04-19 12:17:38.074 INFO 6232 --- [ restartedMain] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.352 INFO 6232 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2017-04-19 12:17:39.370 INFO 6232 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service Tomcat
2017-04-19 12:17:39.372 INFO 6232 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.11
2017-04-19 12:17:39.481 INFO 6232 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-04-19 12:17:39.481 INFO 6232 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1410 ms
2017-04-19 12:17:39.649 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-04-19 12:17:39.658 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-04-19 12:17:39.659 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-04-19 12:17:39.659 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-04-19 12:17:39.660 INFO 6232 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-04-19 12:17:39.938 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@af1619: startup date [Wed Apr 19 12:17:38 SGT 2017]; root of context hierarchy
2017-04-19 12:17:39.997 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.example.WelcomeController.welcome(java.util.Map)
2017-04-19 12:17:39.997 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/5xx]}" onto public java.lang.String com.example.WelcomeController.ServiceUnavailable()
2017-04-19 12:17:40.006 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-04-19 12:17:40.006 INFO 6232 --- [ restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-04-19 12:17:40.041 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.041 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.090 INFO 6232 --- [ restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-04-19 12:17:40.332 INFO 6232 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2017-04-19 12:17:40.373 INFO 6232 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-04-19 12:17:40.427 INFO 6232 --- [ restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-04-19 12:17:40.435 INFO 6232 --- [ restartedMain] com.example.SpringBootWebApplication : Started SpringBootWebApplication in 2.737 seconds (JVM running for 3.124)
6.2 Access http://localhost:8080

6.2 Access http://localhost:8080/uri-not-exist

6.2 Access http://localhost:8080/5xx

6. 実行可能JARを構築する
6.1 Package the project to create an executable JAR file.
project$ mvn clean package
6.2 Run It, access http://localhost:8080 again.
project$ java -jar target/spring-boot-web-mustache-1.0.jar
ソースコードをダウンロード
ダウンロード–spring-boot-web-mustache.zip(11 KB)