SpringBoot
Example
pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <groupId>hello</groupId>
6 <artifactId>test-spring-boot</artifactId>
7 <version>0.1.0</version>
8 <parent>
9 <groupId>org.springframework.boot</groupId>
10 <artifactId>spring-boot-starter-parent</artifactId>
11 <version>1.4.0.RELEASE</version>
12 </parent>
13 <dependencies>
14 <dependency>
15 <groupId>org.springframework.boot</groupId>
16 <artifactId>spring-boot-starter-thymeleaf</artifactId>
17 </dependency>
18 <dependency>
19 <groupId>org.mariadb.jdbc</groupId>
20 <artifactId>mariadb-java-client</artifactId>
21 <version>1.4.4</version>
22 </dependency>
23 <dependency>
24 <groupId>commons-dbcp</groupId>
25 <artifactId>commons-dbcp</artifactId>
26 <version>1.4</version>
27 </dependency>
28
29 <dependency>
30 <groupId>org.springframework</groupId>
31 <artifactId>spring-jdbc</artifactId>
32 <version>4.3.2.RELEASE</version>
33 </dependency>
34
35 </dependencies>
36 <properties>
37 <start-class>hello.Application</start-class>
38 </properties>
39 <build>
40 <plugins>
41 <plugin>
42 <groupId>org.springframework.boot</groupId>
43 <artifactId>spring-boot-maven-plugin</artifactId>
44 </plugin>
45 </plugins>
46 </build>
47 <repositories>
48 <repository>
49 <id>spring-milestone</id>
50 <url>http://repo.spring.io/libs-release</url>
51 </repository>
52 </repositories>
53 <pluginRepositories>
54 <pluginRepository>
55 <id>spring-milestone</id>
56 <url>http://repo.spring.io/libs-release</url>
57 </pluginRepository>
58 </pluginRepositories>
59 </project>
src/main/java/hello/GreetingController.java
1 package hello;
2
3 import org.springframework.stereotype.Controller;
4 import org.springframework.ui.Model;
5 import org.springframework.web.bind.annotation.RequestMapping;
6 import org.springframework.web.bind.annotation.RequestParam;
7
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10 import org.springframework.web.bind.annotation.ResponseBody;
11 import org.springframework.beans.factory.annotation.Autowired;
12
13 import java.util.List;
14 import java.util.ArrayList;
15
16 @Controller
17 public class GreetingController {
18 private final Logger logger = LoggerFactory.getLogger(GreetingController.class);
19 @Autowired
20 DummyDAO dummyDAO;
21
22 public GreetingController(){
23 logger.debug("Greeting controller created.");
24 }
25
26 @RequestMapping("/greeting")
27 // http://localhost:8080/greeting?name=nnnn
28 public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) {
29 logger.info("Greeting endpoint called.");
30 model.addAttribute("name", name);
31 return "greeting";
32 }
33
34 @RequestMapping(value="/dummy",produces="application/json")
35 @ResponseBody
36 // http://localhost:8080/dummy
37 public List<Dummy> dummy(){
38 List<Dummy> list= new java.util.ArrayList<Dummy>();
39 Dummy dummy = new Dummy();
40 dummy.setFieldA("AAA");
41 dummy.setFieldB("CCC");
42 list.add(dummy);
43
44 Dummy dummy2 = new Dummy();
45 dummy2.setFieldA("AAA2");
46 dummy2.setFieldB("CCC2");
47 list.add(dummy2);
48
49 return list;
50 }
51
52 @RequestMapping(value="/dummyname",produces="application/json")
53 @ResponseBody
54 // http://localhost:8080/dummyname
55 public String getDummyName(){
56 return dummyDAO.getNameFromDummy();
57 }
58
59
60 }
src/main/java/hello/Application.java
1 package hello;
2
3 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
4 import org.springframework.boot.SpringApplication;
5 import org.springframework.context.annotation.ComponentScan;
6 import org.springframework.context.annotation.Bean;
7 import org.springframework.beans.factory.annotation.Autowired;
8 import org.springframework.beans.factory.annotation.Qualifier;
9
10 import org.apache.commons.dbcp.BasicDataSource;
11 import org.springframework.jdbc.core.JdbcTemplate;
12
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 @ComponentScan
17 @EnableAutoConfiguration
18 public class Application {
19 private static Logger logger;
20
21 public static void main(String[] args) {
22 logger = LoggerFactory.getLogger(Application.class);
23 logger.info("Starting application");
24 SpringApplication.run(Application.class, args);
25 }
26
27 @Bean(name="basicDataSource",destroyMethod="close")
28 public BasicDataSource createBasicDataSource(){
29 logger.info("Creating basicDataSource");
30 BasicDataSource bds = new BasicDataSource();
31 bds.setDriverClassName("org.mariadb.jdbc.Driver");
32 bds.setUrl("jdbc:mariadb://localhost:3306/springmvchtml");
33 bds.setUsername("usertest");
34 bds.setPassword("usertest");
35 bds.setInitialSize(3);
36 return bds;
37 }
38 /*
39 @Bean(name="jdbcTemplate")
40 public JdbcTemplate jdbcTemplate(){
41 logger.info("Creating jdbcTemplate");
42 return new JdbcTemplate( basicDataSource() );
43 }
44 */
45 @Bean(name="jdbcTemplate")
46 public JdbcTemplate createJdbcTemplate(@Autowired @Qualifier("basicDataSource") BasicDataSource bds ){
47 logger.info("Creating jdbcTemplate");
48 return new JdbcTemplate( bds );
49 }
50
51 }
src/main/java/hello/ThreadTimer.java
1 package hello;
2
3 import org.springframework.stereotype.Component;
4 import javax.annotation.PostConstruct;
5 import org.springframework.beans.factory.annotation.Autowired;
6 import java.text.MessageFormat;
7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory;
9 import java.util.ArrayList;
10
11 @Component
12 public class ThreadTimer extends Thread {
13 private int delaySeconds;
14 private Logger logger;
15 private boolean running;
16 private Object monitor=new Object();
17 private ArrayList<Object> subscribers;
18
19 //@Autowired
20 //WaitThread waitThread;
21
22 public ThreadTimer() {
23 this.logger = LoggerFactory.getLogger(ThreadTimer.class);
24 logger.info("Created instance of " + this.getClass().getSimpleName());
25 this.running = true;
26 this.delaySeconds = 5 * 1000;
27 this.setName(this.getClass().getSimpleName() + "_" + this.getName());
28 this.subscribers = new ArrayList<Object>();
29 }
30
31 public void addSubscriber(Object subscriber){
32 this.subscribers.add(subscriber);
33 }
34
35 @PostConstruct
36 public void init() {
37 logger.info("Starting the thread");
38 this.start();
39 }
40
41 @Override
42 public void run() {
43 while (running) {
44 try {
45 Thread.sleep(this.delaySeconds);
46 logger.info("Delay " + this.getClass().getSimpleName());
47
48 for(Object o: this.subscribers){
49 synchronized(o){
50 o.notify();
51 }
52 }
53 }
54 catch (InterruptedException e) {
55 logger.info("ThreadTimer interrupted exception:" + e.getMessage() );
56 }
57 catch (Exception e) {
58 e.printStackTrace();
59 logger.info("ThreadTimer exception:" + e.getMessage() );
60 stopRunning();
61 }
62 }
63 logger.info("Exited " + this.getClass().getSimpleName());
64 }
65
66 public void startRunning() {
67 this.running = true;
68 }
69
70 public void stopRunning() {
71 this.running = false;
72 }
73
74 public void destroy(){
75 logger.info("Called destroy");
76 this.stopRunning();
77 this.interrupt();
78 }
79 }
src/main/java/hello/WaitThread.java
1 package hello;
2
3 import org.springframework.stereotype.Component;
4 import javax.annotation.PostConstruct;
5 import java.text.MessageFormat;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8 import org.springframework.beans.factory.annotation.Autowired;
9
10 @Component
11 public class WaitThread extends Thread {
12 private Logger logger;
13 private boolean running;
14 private Object monitor;
15
16 @Autowired
17 ThreadTimer timerThread;
18
19 public WaitThread() {
20 this.logger = LoggerFactory.getLogger(WaitThread.class);
21 logger.info("Created instance of " + this.getClass().getSimpleName());
22 this.running = true;
23 this.setName(this.getClass().getSimpleName() + "_" + this.getName());
24 this.monitor=new Object();
25 }
26
27 @PostConstruct
28 public void init() {
29 this.timerThread.addSubscriber(this);
30 logger.info("Starting the thread");
31 this.start();
32 }
33
34 public void run() {
35 while (running) {
36 try {
37 synchronized(this){
38 this.wait();
39 logger.info("Notification received.");
40 }
41 }
42 catch (InterruptedException e) {
43 logger.info("ThreadTimer interrupted exception:" + e.getMessage() );
44 }
45 catch (Exception e) {
46 logger.info("WaitThread exception:" + e.getMessage() );
47 stopRunning();
48 }
49 }
50 logger.info("Exited " + this.getClass().getSimpleName());
51 }
52
53 public void startRunning() {
54 this.running = true;
55 }
56
57 public void stopRunning() {
58 this.running = false;
59 }
60
61 public void destroy(){
62 logger.info("Called destroy");
63 this.stopRunning();
64 this.interrupt();
65 }
66 }
src/main/java/hello/Dummy.java
1 package hello;
2
3 public class Dummy{
4 private String fieldA;
5 private String fieldB;
6
7 public Dummy(){
8 }
9
10 public String getFieldA(){
11 return fieldA;
12 }
13
14 public String getFieldB(){
15 return fieldB;
16 }
17
18 public void setFieldA(String arg){
19 fieldA = arg;
20 }
21
22 public void setFieldB(String arg){
23 fieldB = arg;
24 }
25 }
src/main/java/hello/DummyDAO.java
1 package hello;
2
3 import org.slf4j.Logger;
4 import org.slf4j.LoggerFactory;
5
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.beans.factory.annotation.Qualifier;
8 import org.springframework.jdbc.core.JdbcTemplate;
9 import org.springframework.stereotype.Component;
10
11 @Component
12 public class DummyDAO {
13 @Autowired
14 @Qualifier("jdbcTemplate")
15 private JdbcTemplate jdbcTemplate;
16 private Logger logger;
17
18 public DummyDAO() {
19 logger = LoggerFactory.getLogger(DummyDAO.class);
20 logger.info("Created " + this.getClass().getSimpleName());
21 }
22
23 public String getNameFromDummy() {
24 return this.jdbcTemplate.queryForObject("select name from dummy limit 1", String.class);
25 }
26 }
src/main/resources/templates/greeting.html
src/main/resources/application.properties
1 logging.file=/tmp/testout.log
src/main/resources/logback-spring.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <configuration>
3 <!--
4 <include resource="org/springframework/boot/logging/logback/defaults.xml" />
5 <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
6 <include resource="org/springframework/boot/logging/logback/file-appender.xml" />
7 -->
8 <!-- override spring logback default behaviour -->
9 <appender name="FILE" class="ch.qos.logback.core.FileAppender">
10 <file>${filelog}</file>
11 <encoder>
12 <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
13 </encoder>
14 </appender>
15
16 <appender name="GREETFILE" class="ch.qos.logback.core.FileAppender">
17 <file>/tmp/greet.log</file>
18 <encoder>
19 <pattern>%date{ISO8601} [%thread] %-5level %logger{35} - %msg%n</pattern>
20 </encoder>
21 </appender>
22
23 <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
24 <layout class="ch.qos.logback.classic.PatternLayout">
25 <Pattern>%yellow(%date{ISO8601}) %green([%thread]) %highlight(%-5level) %cyan(%logger{35}) - %white(%msg%n) </Pattern>
26 </layout>
27 </appender>
28
29 <root level="INFO">
30 <appender-ref ref="FILE" />
31 <appender-ref ref="CONSOLE"/>
32 </root>
33
34 <logger name="hello.GreetingController" level="debug" additivity="false">
35 <appender-ref ref="GREETFILE"/>
36 <appender-ref ref="CONSOLE" />
37 </logger>
38
39 </configuration>
src/main/resources/test.sql
1 --JDBC URL: jdbc:mariadb://localhost:3306/springmvchtml
2 --mysql -u root -p
3 create database springmvchtml;
4 create user 'usertest'@'%' identified by '????????';
5 create user 'usertest'@'localhost' identified by '????????';
6 grant all on springmvchtml.* to 'usertest'@'%';
7 grant all on springmvchtml.* to 'usertest'@'localhost';
8 show grants for 'usertest'@'%';
9 show grants for 'usertest'@'localhost';
10 create table springmvchtml.dummy (name varchar(255) ) ;
11 insert into springmvchtml.dummy (name) values('aaaa');
12 insert into springmvchtml.dummy (name) values('bbbb');
13 commit;
14 -- mysql -u usertest -p
15
JAR files list
- jar tf target/test-spring-boot-0.1.0.jar | grep "\.jar"
BOOT-INF/lib/jackson-core-2.8.1.jar BOOT-INF/lib/spring-web-4.3.2.RELEASE.jar BOOT-INF/lib/unbescape-1.1.0.RELEASE.jar BOOT-INF/lib/javassist-3.20.0-GA.jar BOOT-INF/lib/mariadb-java-client-1.4.4.jar BOOT-INF/lib/jul-to-slf4j-1.7.21.jar BOOT-INF/lib/groovy-2.4.7.jar BOOT-INF/lib/hibernate-validator-5.2.4.Final.jar BOOT-INF/lib/classmate-1.3.1.jar BOOT-INF/lib/tomcat-embed-el-8.5.4.jar BOOT-INF/lib/tomcat-embed-core-8.5.4.jar BOOT-INF/lib/commons-pool-1.6.jar BOOT-INF/lib/thymeleaf-spring4-2.1.5.RELEASE.jar BOOT-INF/lib/spring-context-4.3.2.RELEASE.jar BOOT-INF/lib/thymeleaf-2.1.5.RELEASE.jar BOOT-INF/lib/spring-boot-starter-tomcat-1.4.0.RELEASE.jar BOOT-INF/lib/thymeleaf-layout-dialect-1.4.0.jar BOOT-INF/lib/spring-boot-autoconfigure-1.4.0.RELEASE.jar BOOT-INF/lib/snakeyaml-1.17.jar BOOT-INF/lib/spring-boot-starter-web-1.4.0.RELEASE.jar BOOT-INF/lib/spring-boot-starter-logging-1.4.0.RELEASE.jar BOOT-INF/lib/spring-webmvc-4.3.2.RELEASE.jar BOOT-INF/lib/spring-beans-4.3.2.RELEASE.jar BOOT-INF/lib/slf4j-api-1.7.21.jar BOOT-INF/lib/spring-jdbc-4.3.2.RELEASE.jar BOOT-INF/lib/jackson-annotations-2.8.1.jar BOOT-INF/lib/commons-dbcp-1.4.jar BOOT-INF/lib/ognl-3.0.8.jar BOOT-INF/lib/spring-boot-starter-1.4.0.RELEASE.jar BOOT-INF/lib/tomcat-embed-websocket-8.5.4.jar BOOT-INF/lib/spring-boot-starter-thymeleaf-1.4.0.RELEASE.jar BOOT-INF/lib/spring-tx-4.3.2.RELEASE.jar BOOT-INF/lib/logback-classic-1.1.7.jar BOOT-INF/lib/spring-boot-1.4.0.RELEASE.jar BOOT-INF/lib/spring-expression-4.3.2.RELEASE.jar BOOT-INF/lib/logback-core-1.1.7.jar BOOT-INF/lib/validation-api-1.1.0.Final.jar BOOT-INF/lib/spring-core-4.3.2.RELEASE.jar BOOT-INF/lib/jackson-databind-2.8.1.jar BOOT-INF/lib/jcl-over-slf4j-1.7.21.jar BOOT-INF/lib/log4j-over-slf4j-1.7.21.jar BOOT-INF/lib/spring-aop-4.3.2.RELEASE.jar BOOT-INF/lib/jboss-logging-3.3.0.Final.jar
Add HTTPS/SSL support
Keystore creation
#create keystore with key springboot keytool -genkey -alias springboot -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore springboot.p12 -validity 3650 Enter keystore password: 12345678 Re-enter new password: 12345678 What is your first and last name? [Unknown]: Spring Boot What is the name of your organizational unit? [Unknown]: Boot What is the name of your organization? [Unknown]: Boot What is the name of your City or Locality? [Unknown]: Lisbon What is the name of your State or Province? [Unknown]: Estremadura What is the two-letter country code for this unit? [Unknown]: PT Is CN=Spring Boot, OU=Boot, O=Boot, L=Lisbon, ST=Estremadura, C=PT correct? [no]: yes #list keys keytool -list -v -keystore springboot.p12 -storetype pkcs12
Code to add in Application class/configuration
// import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer; // import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer; // import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; // import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer; // import java.io.FileNotFoundException; // import org.apache.catalina.connector.Connector; // import org.springframework.beans.factory.annotation.Value; // import javax.inject.Inject; // import org.springframework.util.ResourceUtils; public class TCC implements TomcatConnectorCustomizer{ private String keystoreFile; private String keystorePassword; private String keystoreType; private String keystoreAlias; public TCC(String keystoreFile, String keystorePassword, String keystoreType, String keystoreAlias){ this.keystoreFile=keystoreFile; this.keystorePassword=keystorePassword; this.keystoreType=keystoreType; this.keystoreAlias=keystoreAlias; } public void customize(Connector connector){ connector.setSecure(true); connector.setScheme("https"); connector.setAttribute("keystoreFile", keystoreFile); connector.setAttribute("keystorePass", keystorePassword); connector.setAttribute("keystoreType", keystoreType); connector.setAttribute("keyAlias", keystoreAlias); connector.setAttribute("clientAuth", "false"); connector.setAttribute("sslProtocol", "TLS"); connector.setAttribute("SSLEnabled", true); } } public class ESCC implements EmbeddedServletContainerCustomizer{ private String keystoreFile; private String keystorePassword; private String keystoreType; private String keystoreAlias; public ESCC(String keystoreFile, String keystorePassword, String keystoreType, String keystoreAlias){ this.keystoreFile=keystoreFile; this.keystorePassword=keystorePassword; this.keystoreType=keystoreType; this.keystoreAlias=keystoreAlias; } public void customize(ConfigurableEmbeddedServletContainer container){ TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) container; TomcatConnectorCustomizer tcc = new TCC(keystoreFile,keystorePassword,keystoreType,keystoreAlias); containerFactory.addConnectorCustomizers(tcc); } } @Bean @Inject public EmbeddedServletContainerCustomizer containerCustomizer( @Value("${keystore.file}") String keystoreFile, @Value("${keystore.password}") String keystorePassword, @Value("${keystore.type}") String keystoreType, @Value("${keystore.alias}") String keystoreAlias) throws FileNotFoundException { final String absoluteKeystoreFile = ResourceUtils.getFile(keystoreFile).getAbsolutePath(); EmbeddedServletContainerCustomizer escc = new ESCC(absoluteKeystoreFile,keystorePassword,keystoreType,keystoreAlias); return escc; }
pom.xml
<!-- Add dependency to support @Inject annotation --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
- Add server.port=8443 to application.properties or use system property -Dserver.port=8443
- Run java -Dfilelog=/tmp/out.log -Dkeystore.file=springboot.p12 -Dkeystore.password=12345678 -Dkeystore.type=PKCS12 -Dkeystore.alias=springboot -jar target/test-spring-boot-0.1.0.jar