= SpringBoot = <> == Common properties for spring boot == * https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html {{{#!highlight sh # disable web container/server spring.main.web-environment=false spring.jmx.enabled=false #spring.main.banner-mode=off spring.main.banner-mode=console spring.banner.location=classpath:banner.txt }}} == Example == === pom.xml === {{{#!highlight xml 4.0.0 hello test-spring-boot 0.1.0 org.springframework.boot spring-boot-starter-parent 1.4.0.RELEASE org.springframework.boot spring-boot-starter-thymeleaf org.mariadb.jdbc mariadb-java-client 1.4.4 commons-dbcp commons-dbcp 1.4 org.springframework spring-jdbc 4.3.2.RELEASE hello.Application org.springframework.boot spring-boot-maven-plugin spring-milestone http://repo.spring.io/libs-release spring-milestone http://repo.spring.io/libs-release }}} === src/main/java/hello/GreetingController.java === {{{#!highlight java package hello; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; import java.util.ArrayList; @Controller public class GreetingController { private final Logger logger = LoggerFactory.getLogger(GreetingController.class); @Autowired DummyDAO dummyDAO; public GreetingController(){ logger.debug("Greeting controller created."); } @RequestMapping("/greeting") // http://localhost:8080/greeting?name=nnnn public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model) { logger.info("Greeting endpoint called."); model.addAttribute("name", name); return "greeting"; } @RequestMapping(value="/dummy",produces="application/json") @ResponseBody // http://localhost:8080/dummy public List dummy(){ List list= new java.util.ArrayList(); Dummy dummy = new Dummy(); dummy.setFieldA("AAA"); dummy.setFieldB("CCC"); list.add(dummy); Dummy dummy2 = new Dummy(); dummy2.setFieldA("AAA2"); dummy2.setFieldB("CCC2"); list.add(dummy2); return list; } @RequestMapping(value="/dummyname",produces="application/json") @ResponseBody // http://localhost:8080/dummyname public String getDummyName(){ return dummyDAO.getNameFromDummy(); } } }}} === src/main/java/hello/Application.java === {{{#!highlight java package hello; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Bean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ComponentScan @EnableAutoConfiguration public class Application { private static Logger logger; public static void main(String[] args) { logger = LoggerFactory.getLogger(Application.class); logger.info("Starting application"); SpringApplication.run(Application.class, args); } @Bean(name="basicDataSource",destroyMethod="close") public BasicDataSource createBasicDataSource(){ logger.info("Creating basicDataSource"); BasicDataSource bds = new BasicDataSource(); bds.setDriverClassName("org.mariadb.jdbc.Driver"); bds.setUrl("jdbc:mariadb://localhost:3306/springmvchtml"); bds.setUsername("usertest"); bds.setPassword("usertest"); bds.setInitialSize(3); return bds; } /* @Bean(name="jdbcTemplate") public JdbcTemplate jdbcTemplate(){ logger.info("Creating jdbcTemplate"); return new JdbcTemplate( basicDataSource() ); } */ @Bean(name="jdbcTemplate") public JdbcTemplate createJdbcTemplate(@Autowired @Qualifier("basicDataSource") BasicDataSource bds ){ logger.info("Creating jdbcTemplate"); return new JdbcTemplate( bds ); } } }}} === src/main/java/hello/ThreadTimer.java === {{{#!highlight java package hello; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; @Component public class ThreadTimer extends Thread { private int delaySeconds; private Logger logger; private boolean running; private Object monitor=new Object(); private ArrayList subscribers; //@Autowired //WaitThread waitThread; public ThreadTimer() { this.logger = LoggerFactory.getLogger(ThreadTimer.class); logger.info("Created instance of " + this.getClass().getSimpleName()); this.running = true; this.delaySeconds = 5 * 1000; this.setName(this.getClass().getSimpleName() + "_" + this.getName()); this.subscribers = new ArrayList(); } public void addSubscriber(Object subscriber){ this.subscribers.add(subscriber); } @PostConstruct public void init() { logger.info("Starting the thread"); this.start(); } @Override public void run() { while (running) { try { Thread.sleep(this.delaySeconds); logger.info("Delay " + this.getClass().getSimpleName()); for(Object o: this.subscribers){ synchronized(o){ o.notify(); } } } catch (InterruptedException e) { logger.info("ThreadTimer interrupted exception:" + e.getMessage() ); } catch (Exception e) { e.printStackTrace(); logger.info("ThreadTimer exception:" + e.getMessage() ); stopRunning(); } } logger.info("Exited " + this.getClass().getSimpleName()); } public void startRunning() { this.running = true; } public void stopRunning() { this.running = false; } public void destroy(){ logger.info("Called destroy"); this.stopRunning(); this.interrupt(); } } }}} === src/main/java/hello/WaitThread.java === {{{#!highlight java package hello; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @Component public class WaitThread extends Thread { private Logger logger; private boolean running; private Object monitor; @Autowired ThreadTimer timerThread; public WaitThread() { this.logger = LoggerFactory.getLogger(WaitThread.class); logger.info("Created instance of " + this.getClass().getSimpleName()); this.running = true; this.setName(this.getClass().getSimpleName() + "_" + this.getName()); this.monitor=new Object(); } @PostConstruct public void init() { this.timerThread.addSubscriber(this); logger.info("Starting the thread"); this.start(); } public void run() { while (running) { try { synchronized(this){ this.wait(); logger.info("Notification received."); } } catch (InterruptedException e) { logger.info("ThreadTimer interrupted exception:" + e.getMessage() ); } catch (Exception e) { logger.info("WaitThread exception:" + e.getMessage() ); stopRunning(); } } logger.info("Exited " + this.getClass().getSimpleName()); } public void startRunning() { this.running = true; } public void stopRunning() { this.running = false; } public void destroy(){ logger.info("Called destroy"); this.stopRunning(); this.interrupt(); } } }}} === src/main/java/hello/Dummy.java === {{{#!highlight java package hello; public class Dummy{ private String fieldA; private String fieldB; public Dummy(){ } public String getFieldA(){ return fieldA; } public String getFieldB(){ return fieldB; } public void setFieldA(String arg){ fieldA = arg; } public void setFieldB(String arg){ fieldB = arg; } } }}} === src/main/java/hello/DummyDAO.java === {{{#!highlight java package hello; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @Component public class DummyDAO { @Autowired @Qualifier("jdbcTemplate") private JdbcTemplate jdbcTemplate; private Logger logger; public DummyDAO() { logger = LoggerFactory.getLogger(DummyDAO.class); logger.info("Created " + this.getClass().getSimpleName()); } public String getNameFromDummy() { return this.jdbcTemplate.queryForObject("select name from dummy limit 1", String.class); } } }}} === src/main/resources/templates/greeting.html === {{{#!highlight html Getting Started: Serving Web Content

}}} === src/main/resources/application.properties === {{{#!highlight sh logging.file=/tmp/testout.log }}} === src/main/resources/logback-spring.xml === {{{#!highlight xml ${filelog} %date{ISO8601} [%thread] %-5level %logger{35} - %msg%n /tmp/greet.log %date{ISO8601} [%thread] %-5level %logger{35} - %msg%n %yellow(%date{ISO8601}) %green([%thread]) %highlight(%-5level) %cyan(%logger{35}) - %white(%msg%n) }}} === src/main/resources/test.sql === {{{#!highlight sql --JDBC URL: jdbc:mariadb://localhost:3306/springmvchtml --mysql -u root -p create database springmvchtml; create user 'usertest'@'%' identified by '????????'; create user 'usertest'@'localhost' identified by '????????'; grant all on springmvchtml.* to 'usertest'@'%'; grant all on springmvchtml.* to 'usertest'@'localhost'; show grants for 'usertest'@'%'; show grants for 'usertest'@'localhost'; create table springmvchtml.dummy (name varchar(255) ) ; insert into springmvchtml.dummy (name) values('aaaa'); insert into springmvchtml.dummy (name) values('bbbb'); commit; -- mysql -u usertest -p }}} === JAR files list === {{{#!highlight sh 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 {{{#!highlight sh #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 {{{#!highlight java // 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 {{{#!highlight xml javax.inject javax.inject 1 }}} * 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 * Access https://localhost:8443/greeting?name=x == Environment variables == src/main/resources/application.properties {{{ logging.file=/tmp/testout.log server.port=8443 foo.bar=bohica }}} {{{#!highlight java import javax.annotation.Resource; import org.springframework.core.env.Environment; import org.springframework.beans.factory.annotation.Value; //.................... @Resource Environment env; @Value("${foo.bar}") private String fooBar; @RequestMapping(value="/env",produces="application/json") @ResponseBody public List getEnv(){ List ret = new ArrayList(); ret.add( env.getProperty("foo.bar") ); ret.add(fooBar); return ret; } //.................... }}} Override value in application.properties {{{#!highlight sh java -jar target/test-spring-boot-0.1.0.jar --foo.bar=snafu }}} It's also possible to override values with environment variables as for example * FOO_BAR=snafu java -jar target/test-spring-boot-0.1.0.jar The *.* should be replaced by *_* and the lowercase characters must be capitalized. Instead of using @Autowired or @Inject use @Resource (javax.annotation.Resource). == Example JPA RabbitMQ HttpSession Redis == Structure {{{ . ./pom.xml ./src ./src/main ./src/main/java ./src/main/java/hello ./src/main/java/hello/GreetingController.java ./src/main/java/hello/Application.java ./src/main/java/hello/ThreadTimer.java ./src/main/java/hello/WaitThread.java ./src/main/java/hello/Dummy.java ./src/main/java/hello/DummyDAO.java ./src/main/java/hello/DummyJPA.java ./src/main/java/hello/MessageHandler.java ./src/main/java/hello/BroadcastMessageHandler.java ./src/main/java/hello/ConfigHttpSession.java ./src/main/resources ./src/main/resources/templates ./src/main/resources/templates/greeting.html ./src/main/resources/application.properties ./src/main/resources/logback-spring.xml ./src/main/resources/test.sql ./src/main/resources/META-INF ./src/main/resources/META-INF/persistence.xml }}} WaitThread.java {{{#!highlight java package hello; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @Component public class WaitThread extends Thread { private Logger logger; private boolean running; private Object monitor; @Autowired ThreadTimer timerThread; public WaitThread() { this.logger = LoggerFactory.getLogger(WaitThread.class); logger.info("Created instance of " + this.getClass().getSimpleName()); this.running = true; this.setName(this.getClass().getSimpleName() + "_" + this.getName()); this.monitor=new Object(); } @PostConstruct public void init() { this.timerThread.addSubscriber(this); logger.info("Starting the thread"); this.start(); } public void run() { while (running) { try { synchronized(this){ this.wait(); logger.info("Notification received."); } } catch (InterruptedException e) { logger.info("ThreadTimer interrupted exception:" + e.getMessage() ); } catch (Exception e) { logger.info("WaitThread exception:" + e.getMessage() ); stopRunning(); } } logger.info("Exited " + this.getClass().getSimpleName()); } public void startRunning() { this.running = true; } public void stopRunning() { this.running = false; } public void destroy(){ logger.info("Called destroy"); this.stopRunning(); this.interrupt(); } } }}} ThreadTimer.java {{{#!highlight java package hello; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import java.text.MessageFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; @Component public class ThreadTimer extends Thread { private int delaySeconds; private Logger logger; private boolean running; private Object monitor=new Object(); private ArrayList subscribers; public ThreadTimer() { this.logger = LoggerFactory.getLogger(ThreadTimer.class); logger.info("Created instance of " + this.getClass().getSimpleName()); this.running = true; this.delaySeconds = 5 * 1000; this.setName(this.getClass().getSimpleName() + "_" + this.getName()); this.subscribers = new ArrayList(); } public void addSubscriber(Object subscriber){ this.subscribers.add(subscriber); } @PostConstruct public void init() { logger.info("Starting the thread"); this.start(); } @Override public void run() { while (running) { try { Thread.sleep(this.delaySeconds); logger.info("Delay " + this.getClass().getSimpleName()); for(Object o: this.subscribers){ synchronized(o){ o.notify(); } } } catch (InterruptedException e) { logger.info("ThreadTimer interrupted exception:" + e.getMessage() ); } catch (Exception e) { e.printStackTrace(); logger.info("ThreadTimer exception:" + e.getMessage() ); stopRunning(); } } logger.info("Exited " + this.getClass().getSimpleName()); } public void startRunning() { this.running = true; } public void stopRunning() { this.running = false; } public void destroy(){ logger.info("Called destroy"); this.stopRunning(); this.interrupt(); } } }}} MessageHandler.java {{{#!highlight java package hello; import java.nio.charset.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageHandler{ private final Logger logger = LoggerFactory.getLogger(MessageHandler.class); public void handleMessage(byte[] message){ String msg = new String(message, StandardCharsets.UTF_8); logger.info("Received msg " + msg ); } public void handleMessage(String message){ logger.info("Received msg " + message ); } } }}} GreetingController.java {{{#!highlight java package hello; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; import java.util.ArrayList; import org.springframework.web.bind.annotation.PathVariable; //import javax.inject.Inject; import org.springframework.core.env.Environment; import org.springframework.beans.factory.annotation.Value; import javax.annotation.Resource; import org.springframework.amqp.rabbit.core.RabbitTemplate; import javax.servlet.http.HttpSession; @Controller public class GreetingController { private final Logger logger = LoggerFactory.getLogger(GreetingController.class); @Resource DummyDAO dummyDAO; @Resource Environment env; @Resource RabbitTemplate rabbitTemplate; @Value("${instance.name}") String instanceName; public GreetingController(){ logger.debug("Greeting controller created."); } @RequestMapping("/greeting") public String greeting(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model ) { model.addAttribute("name", name); rabbitTemplate.convertAndSend("topicExchange","myQueue", name ); rabbitTemplate.convertAndSend("fanoutExchange","", name ); return "greeting"; } @RequestMapping("/setvalue/{value}") @ResponseBody public String setValue(@PathVariable("value") String value, Model model,HttpSession httpSession) { httpSession.setAttribute("name", value ); return httpSession.getId(); } @RequestMapping("/getvalue") @ResponseBody public String setValue(Model model,HttpSession httpSession) { return (String) httpSession.getAttribute("name"); } @RequestMapping("/instancename") @ResponseBody public String setValue(Model model) { return this.instanceName; } @RequestMapping("/greeting/add/{name}") public String addGreeting(@PathVariable("name") String name, Model model) { model.addAttribute("name", name); dummyDAO.addName(name); return "greeting"; } @RequestMapping(value="/dummy",produces="application/json") @ResponseBody public List dummy(){ return dummyDAO.getAllNames(); } @RequestMapping(value="/dummyname",produces="application/json") @ResponseBody public String getDummyName(){ return dummyDAO.getNameFromDummy(); } @Value("${foo.bar}") private String fooBar; @RequestMapping(value="/env",produces="application/json") @ResponseBody public List getEnv(){ List ret = new ArrayList(); ret.add( env.getProperty("foo.bar") ); ret.add(fooBar); return ret; } } }}} DummyJPA.java {{{#!highlight java package hello; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQuery; import javax.persistence.NamedQueries; @Entity @NamedQueries({ @NamedQuery(name="DummyJPA.getAll", query="Select e From DummyJPA e") }) public class DummyJPA{ @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long id; private String dummy; public DummyJPA(){ } public String getDummy(){ return this.dummy; } public void setDummy(String dummy){ this.dummy=dummy; } @Override public String toString(){ return String.format("Dummy %s", this.dummy); } } }}} DummyDAO.java {{{#!highlight java package hello; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.persistence.PersistenceContext; import javax.persistence.EntityManager; import javax.persistence.Query; import javax.transaction.Transactional; import java.util.List; @Component public class DummyDAO { @Autowired @Qualifier("jdbcTemplate") private JdbcTemplate jdbcTemplate; private Logger logger; @PersistenceContext(unitName="default") EntityManager em; public DummyDAO() { logger = LoggerFactory.getLogger(DummyDAO.class); logger.info("Created " + this.getClass().getSimpleName()); } public String getNameFromDummy() { return this.jdbcTemplate.queryForObject("select name from dummy limit 1", String.class); } @Transactional public void addName(String name){ DummyJPA djpa = new DummyJPA(); djpa.setDummy(name); em.persist(djpa); } @Transactional public List getAllNames(){ return em.createNamedQuery("DummyJPA.getAll",DummyJPA.class).getResultList(); } } }}} Dummy.java {{{#!highlight java package hello; public class Dummy{ private String fieldA; private String fieldB; public Dummy(){ } public String getFieldA(){ return fieldA; } public String getFieldB(){ return fieldB; } public void setFieldA(String arg){ fieldA = arg; } public void setFieldB(String arg){ fieldB = arg; } } }}} ConfigHttpSession.java {{{#!highlight java /* http://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot.html pkg install redis #freebsd add redis_enable="YES" to /etc/rc.conf /usr/local/etc/rc.d/redis start /usr/local/etc/redis.conf requirepass 12345678 keys * hgetall Same as in application.properties spring.redis.password=12345678 https://localhost:8443/setvalue/valx 147569e4-9e6d-4363-a373-b20261513f11 https://localhost:8443/getvalue SESSION=147569e4-9e6d-4363-a373-b20261513f11 2 instances of spring boot using the same redis server curl -k -v --cookie "SESSION=147569e4-9e6d-4363-a373-b20261513f11" https://localhost:8443/getvalue curl -k -v --cookie "SESSION=147569e4-9e6d-4363-a373-b20261513f11" https://localhost:8444/getvalue */ package hello; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @EnableRedisHttpSession public class ConfigHttpSession{ // springSessionRepositoryFilterbean is responsible for replacing the HttpSession with a custom implementation that is backed by Spring Session. } }}} BroadcastMessageHandler.java {{{#!highlight java package hello; import java.nio.charset.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BroadcastMessageHandler{ private final Logger logger = LoggerFactory.getLogger(BroadcastMessageHandler.class); public void handleMessage(byte[] message){ String msg = new String(message, StandardCharsets.UTF_8); logger.info("Received msg " + msg ); } public void handleMessage(String message){ logger.info("Received msg " + message ); } } }}} Application.java {{{#!highlight java package hello; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Bean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.jdbc.core.JdbcTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.domain.EntityScan; 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 javax.annotation.Resource; import org.springframework.util.ResourceUtils; import org.springframework.core.env.Environment; //-- rabbit import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Queue; import org.springframework.amqp.core.TopicExchange; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.AnonymousQueue; import org.springframework.amqp.rabbit.connection.ConnectionFactory; import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; import java.net.URI; //-- rabbit @ComponentScan @EnableAutoConfiguration @EntityScan(basePackages="hello") public class Application { @Resource Environment env; private static Logger logger; public static void main(String[] args) { logger = LoggerFactory.getLogger(Application.class); logger.info("Starting application"); SpringApplication.run(Application.class, args); } @Bean(name="basicDataSource",destroyMethod="close") public BasicDataSource createBasicDataSource(){ logger.info("Creating basicDataSource"); BasicDataSource bds = new BasicDataSource(); // get config data from application.properties bds.setDriverClassName(env.getProperty("db.driverclass") ); bds.setUrl(env.getProperty("db.jdbcurl") ); bds.setUsername( env.getProperty("db.username") ); bds.setPassword( env.getProperty("db.password") ); bds.setInitialSize( Integer.parseInt( env.getProperty("db.initialsizeconnpool")) ); return bds; } @Bean(name="jdbcTemplate") public JdbcTemplate createJdbcTemplate(@Autowired @Qualifier("basicDataSource") BasicDataSource bds ){ logger.info("Creating jdbcTemplate"); return new JdbcTemplate( bds ); } //--- public class TCC implements TomcatConnectorCustomizer{ Environment env; public TCC(Environment env){ this.env=env; } public void customize(Connector connector){ String absoluteKeystoreFile = ""; logger.info(String.format("Keystore file: %s" , env.getProperty("keystore.file") )); try{ absoluteKeystoreFile = ResourceUtils.getFile(env.getProperty("keystore.file")).getAbsolutePath(); logger.info(String.format("Absolute path keystore: %s" , absoluteKeystoreFile ) ); } catch(Exception ex){ logger.error( ex.getMessage() ); } connector.setSecure(true); connector.setScheme("https"); connector.setAttribute("keystoreFile", absoluteKeystoreFile); connector.setAttribute("keystorePass", env.getProperty("keystore.password")); connector.setAttribute("keystoreType", env.getProperty("keystore.type")); connector.setAttribute("keyAlias", env.getProperty("keystore.alias") ); connector.setAttribute("clientAuth", "false"); connector.setAttribute("sslProtocol", "TLS"); connector.setAttribute("SSLEnabled", true); } } public class ESCC implements EmbeddedServletContainerCustomizer{ Environment env; public ESCC(Environment env){ this.env=env; } public void customize(ConfigurableEmbeddedServletContainer container){ TomcatEmbeddedServletContainerFactory containerFactory = (TomcatEmbeddedServletContainerFactory) container; TomcatConnectorCustomizer tcc = new TCC(env); containerFactory.addConnectorCustomizers(tcc); } } @Bean(name="containerCustomizer") public EmbeddedServletContainerCustomizer containerCustomizer() throws FileNotFoundException { logger.info("Creating containerCustomizer"); EmbeddedServletContainerCustomizer escc = new ESCC(env); return escc; } //--- //---- rabbit //import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; @Bean(name="cachingConnectionFactory") CachingConnectionFactory createCachingConnectionFactory(){ logger.info("Creating cachingConnectionFactory"); String uri = env.getProperty("rabbitmq.uri"); URI rabbitmqUri=null; try{ rabbitmqUri = new URI(uri); } catch(Exception ex){ ex.printStackTrace(); } CachingConnectionFactory ret = new CachingConnectionFactory(rabbitmqUri); logger.info(String.format("Created cachingConnectionFactory with hashCode %d" , ret.hashCode() ) ); return ret; } @Bean(name="myQueue") Queue createMyQueue() { logger.info("Creating myQueue"); return new Queue("myQueue", false); } @Bean(name="topicExchange") TopicExchange createTopicExchange() { logger.info("Creating topicExchange"); return new TopicExchange("topicExchange"); } @Bean(name="bindingQueue") Binding binding(@Qualifier("myQueue")Queue queue, @Qualifier("topicExchange")TopicExchange exchange) { logger.info("Creating bindingQueue"); return BindingBuilder.bind(queue).to(exchange).with(queue.getName()); } @Bean(name="workQueueContainer") SimpleMessageListenerContainer createWorkQueueContainer(ConnectionFactory connectionFactory, @Autowired @Qualifier("listenerAdapter") MessageListenerAdapter listenerAdapter,@Qualifier("myQueue") Queue queue) { logger.info("Creating createWorkQueueContainer for work queue"); logger.info(String.format("Using ConnectionFactory with hashCode %d" , connectionFactory.hashCode() ) ); SimpleMessageListenerContainer smlc = new SimpleMessageListenerContainer(); smlc.setConnectionFactory(connectionFactory); smlc.setQueueNames(queue.getName() ); smlc.setMessageListener(listenerAdapter); return smlc; } @Bean(name="listenerAdapter") MessageListenerAdapter listenerAdapter(@Autowired @Qualifier("messageHandler")MessageHandler messageHandler) { logger.info("Creating listenerAdapter"); return new MessageListenerAdapter(messageHandler); } @Bean(name="messageHandler") MessageHandler createMessageHandler() { logger.info("Creating messageHandler"); return new MessageHandler(); } //-------- @Bean(name="fanoutExchange") FanoutExchange createFanoutExchange() { logger.info("Creating fanoutExchange"); return new FanoutExchange("fanoutExchange"); } @Bean(name="anonymousQueue1") AnonymousQueue createAnonymousQueue1() { logger.info("Creating anonQueue1"); return new AnonymousQueue(); } @Bean(name="bindingTopic") Binding bindingTopic(@Qualifier("anonymousQueue1")AnonymousQueue queue, @Qualifier("fanoutExchange")FanoutExchange exchange) { logger.info("Creating bindingTopic"); return BindingBuilder.bind(queue).to(exchange); } @Bean(name="broadcastMessageHandler") BroadcastMessageHandler createBroadcastMessageHandler() { logger.info("Creating broadcastMessageHandlermessageHandler"); return new BroadcastMessageHandler(); } @Bean(name="broadcastListenerAdapter") MessageListenerAdapter createBroadcastlistenerAdapter(@Autowired @Qualifier("broadcastMessageHandler")BroadcastMessageHandler broadcastMessageHandler) { logger.info("Creating broadcastListenerAdapter"); return new MessageListenerAdapter(broadcastMessageHandler); } @Bean(name="topicContainer") SimpleMessageListenerContainer createTopicContainer(ConnectionFactory connectionFactory, @Autowired @Qualifier("broadcastListenerAdapter") MessageListenerAdapter listenerAdapter, @Qualifier("anonymousQueue1") AnonymousQueue anonQueue) { logger.info("Creating container for topic"); logger.info(String.format("Using ConnectionFactory with hashCode %d" , connectionFactory.hashCode() ) ); SimpleMessageListenerContainer smlc = new SimpleMessageListenerContainer(); smlc.setConnectionFactory(connectionFactory); smlc.setQueueNames( anonQueue.getName() ); smlc.setMessageListener(listenerAdapter); return smlc; } //---- //---- rabbit } }}} persistence.xml {{{#!highlight xml basicDataSource }}} greeting.html {{{#!highlight html Getting Started: Serving Web Content

}}} test.sql {{{#!highlight sql --JDBC URL: jdbc:mariadb://localhost:3306/springmvchtml --mysql -u root -p create database springmvchtml; create user 'usertest'@'%' identified by '????'; create user 'usertest'@'localhost' identified by '????'; grant all on springmvchtml.* to 'usertest'@'%'; grant all on springmvchtml.* to 'usertest'@'localhost'; show grants for 'usertest'@'%'; show grants for 'usertest'@'localhost'; create table springmvchtml.dummy (name varchar(255) ) ; insert into springmvchtml.dummy (name) values('aaaa'); insert into springmvchtml.dummy (name) values('bbbb'); commit; -- mysql -u usertest -p }}} logback-spring.xml {{{#!highlight xml ${filelog} %date{ISO8601} [%thread] %-5level %logger{35} - %msg%n /tmp/greet.log %date{ISO8601} [%thread] %-5level %logger{35} - %msg%n %yellow(%date{ISO8601}) %green([%thread]) %highlight(%-5level) %cyan(%logger{35}) - %white(%msg%n) }}} application.properties {{{ logging.file=/tmp/testout.log server.port=8443 foo.bar=bohica instance.name=node1 keystore.file=springboot.p12 keystore.password=???? keystore.type=PKCS12 keystore.alias=springboot db.driverclass=org.mariadb.jdbc.Driver db.jdbcurl=jdbc:mariadb://localhost:3306/springmvchtml db.username=usertest db.password=???? db.initialsizeconnpool=3 #rabbimq parameters rabbitmq.uri=amqp://????:????@localhost:5672 #redis spring.redis.host=localhost spring.redis.password=???????? spring.redis.port=6379 }}} pom.xml {{{#!highlight xml 4.0.0 hello test-spring-boot 0.1.0 org.springframework.boot spring-boot-starter-parent 1.4.0.RELEASE org.springframework.boot spring-boot-starter-thymeleaf org.mariadb.jdbc mariadb-java-client 1.4.4 commons-dbcp commons-dbcp 1.4 org.springframework spring-jdbc 4.3.2.RELEASE org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-starter-amqp javax.inject javax.inject 1 org.springframework.session spring-session 1.2.2.RELEASE org.springframework.boot spring-boot-starter-data-redis hello.Application org.springframework.boot spring-boot-maven-plugin spring-milestone http://repo.spring.io/libs-release spring-milestone http://repo.spring.io/libs-release }}} Libs {{{#!highlight sh -rw-r--r-- 1 vitor vitor 37M Sep 29 15:49 test-spring-boot-0.1.0.jar jar tf test-spring-boot-0.1.0.jar | grep BOOT | grep jar BOOT-INF/lib/spring-session-1.2.2.RELEASE.jar BOOT-INF/lib/spring-boot-starter-data-redis-1.4.0.RELEASE.jar BOOT-INF/lib/jackson-core-2.8.1.jar BOOT-INF/lib/javassist-3.20.0-GA.jar BOOT-INF/lib/jul-to-slf4j-1.7.21.jar BOOT-INF/lib/groovy-2.4.7.jar BOOT-INF/lib/spring-amqp-1.6.1.RELEASE.jar BOOT-INF/lib/hibernate-validator-5.2.4.Final.jar BOOT-INF/lib/classmate-1.3.1.jar BOOT-INF/lib/hibernate-commons-annotations-5.0.1.Final.jar BOOT-INF/lib/tomcat-embed-el-8.5.4.jar BOOT-INF/lib/jedis-2.8.2.jar BOOT-INF/lib/httpcore-4.4.5.jar BOOT-INF/lib/antlr-2.7.7.jar BOOT-INF/lib/xml-apis-1.4.01.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/http-client-1.0.0.RELEASE.jar BOOT-INF/lib/httpclient-4.5.2.jar BOOT-INF/lib/spring-boot-starter-logging-1.4.0.RELEASE.jar BOOT-INF/lib/tomcat-jdbc-8.5.4.jar BOOT-INF/lib/spring-beans-4.3.2.RELEASE.jar BOOT-INF/lib/spring-jdbc-4.3.2.RELEASE.jar BOOT-INF/lib/spring-boot-starter-jdbc-1.4.0.RELEASE.jar BOOT-INF/lib/spring-boot-starter-amqp-1.4.0.RELEASE.jar BOOT-INF/lib/spring-aspects-4.3.2.RELEASE.jar BOOT-INF/lib/commons-dbcp-1.4.jar BOOT-INF/lib/spring-data-commons-1.12.2.RELEASE.jar BOOT-INF/lib/spring-context-support-4.3.2.RELEASE.jar BOOT-INF/lib/spring-data-keyvalue-1.1.2.RELEASE.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/commons-logging-1.2.jar BOOT-INF/lib/spring-tx-4.3.2.RELEASE.jar BOOT-INF/lib/validation-api-1.1.0.Final.jar BOOT-INF/lib/spring-core-4.3.2.RELEASE.jar BOOT-INF/lib/spring-boot-starter-aop-1.4.0.RELEASE.jar BOOT-INF/lib/spring-data-jpa-1.10.2.RELEASE.jar BOOT-INF/lib/commons-pool2-2.4.2.jar BOOT-INF/lib/dom4j-1.6.1.jar BOOT-INF/lib/tomcat-juli-8.5.4.jar BOOT-INF/lib/jcl-over-slf4j-1.7.21.jar BOOT-INF/lib/log4j-over-slf4j-1.7.21.jar BOOT-INF/lib/aspectjweaver-1.8.9.jar BOOT-INF/lib/spring-data-redis-1.7.2.RELEASE.jar BOOT-INF/lib/spring-web-4.3.2.RELEASE.jar BOOT-INF/lib/unbescape-1.1.0.RELEASE.jar BOOT-INF/lib/mariadb-java-client-1.4.4.jar BOOT-INF/lib/amqp-client-3.6.3.jar BOOT-INF/lib/spring-oxm-4.3.2.RELEASE.jar BOOT-INF/lib/tomcat-embed-core-8.5.4.jar BOOT-INF/lib/spring-orm-4.3.2.RELEASE.jar BOOT-INF/lib/hibernate-jpa-2.1-api-1.0.0.Final.jar BOOT-INF/lib/commons-pool-1.6.jar BOOT-INF/lib/thymeleaf-spring4-2.1.5.RELEASE.jar BOOT-INF/lib/hibernate-core-5.0.9.Final.jar BOOT-INF/lib/spring-context-4.3.2.RELEASE.jar BOOT-INF/lib/thymeleaf-2.1.5.RELEASE.jar BOOT-INF/lib/commons-codec-1.10.jar BOOT-INF/lib/spring-boot-starter-web-1.4.0.RELEASE.jar BOOT-INF/lib/spring-webmvc-4.3.2.RELEASE.jar BOOT-INF/lib/slf4j-api-1.7.21.jar BOOT-INF/lib/javax.inject-1.jar BOOT-INF/lib/jackson-annotations-2.8.1.jar BOOT-INF/lib/jandex-2.0.0.Final.jar BOOT-INF/lib/spring-messaging-4.3.2.RELEASE.jar BOOT-INF/lib/ognl-3.0.8.jar BOOT-INF/lib/hibernate-entitymanager-5.0.9.Final.jar BOOT-INF/lib/spring-boot-starter-thymeleaf-1.4.0.RELEASE.jar BOOT-INF/lib/spring-retry-1.1.3.RELEASE.jar BOOT-INF/lib/javax.transaction-api-1.2.jar BOOT-INF/lib/logback-classic-1.1.7.jar BOOT-INF/lib/spring-boot-starter-data-jpa-1.4.0.RELEASE.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/jackson-databind-2.8.1.jar BOOT-INF/lib/spring-rabbit-1.6.1.RELEASE.jar BOOT-INF/lib/spring-aop-4.3.2.RELEASE.jar BOOT-INF/lib/jboss-logging-3.3.0.Final.jar }}} == springTestApp == === pom.xml === {{{#!highlight xml 4.0.0 org.allowed.bitarus springTestApp 0.1.0 org.springframework.boot spring-boot-starter-parent 1.4.2.RELEASE org.springframework.boot spring-boot-starter-web org.allowed.bitarus.springTestApp.Application maven-compiler-plugin 2.3.2 org.springframework.boot spring-boot-maven-plugin spring-releases http://repo.spring.io/libs-release spring-releases http://repo.spring.io/libs-release }}} === src/main/java/org/allowed/bitarus/springTestApp/Application.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import java.util.concurrent.Future; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @ComponentScan @EnableAutoConfiguration @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean(name="tasksFutures") public ArrayList> createTasksFutures(){ System.out.println("Creating tasksFutures"); return new ArrayList>(); } @Bean(name="executors") public ExecutorService createExecutors(){ return Executors.newFixedThreadPool(5); } } }}} === src/main/java/org/allowed/bitarus/springTestApp/Tasker.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.stereotype.Component; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @Component("tasker") public class Tasker { private ExecutorService _es; public Tasker(@Qualifier("executors") ExecutorService es){ System.out.println("Created Tasker !!!!"); _es = es; } public Future addTask(TaskX taskx){ Future f = _es.submit( taskx ); return f; } } }}} === src/main/java/org/allowed/bitarus/springTestApp/Receiver.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.stereotype.Component; import java.util.concurrent.Future; import java.util.ArrayList; import org.springframework.beans.factory.annotation.Qualifier; import javax.annotation.PostConstruct; @Component public class Receiver { private Tasker _t; private ArrayList> _tasks; public Receiver(@Qualifier("tasker")Tasker t, @Qualifier("tasksFutures") ArrayList> tasks ){ System.out.println("Created receiver !!!!"); _t = t; _tasks = tasks; // wait for all tasks ... /* boolean loop=true; while(loop){ boolean allDone=true; for(Future f : tasks){ if(f.isDone()==false){ allDone=false; } } if(allDone){ loop=false; } try{ Thread.sleep(1000); } catch(Exception ex){ } } for(Future f : tasks){ try{ Integer res = f.get(); System.out.println(res); } catch(Exception ex){ } } */ } @PostConstruct public void init(){ System.out.println("Init post construct"); for(int i=0;i<10;i++){ _tasks.add( _t.addTask( new TaskX(5,6) ) ); } } } }}} === TaskX.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import java.util.concurrent.Callable; public class TaskX implements Callable{ private int _x; private int _y; public TaskX(int x,int y){ _x=x; _y=y; } public Integer call() { try { Thread.sleep(5000); } catch(Exception ex){ } int sum = _x+_y; System.out.println("TID:"+Thread.currentThread().getId() + " sumVal:" + sum ); return sum; } } }}} == Example with MongoDB == Think about using '''spring.data.mongodb.uri'''. === pom.xml === {{{#!highlight xml 4.0.0 org.allowed.bitarus springTestApp 0.1.0 org.springframework.boot spring-boot-starter-parent 1.4.2.RELEASE org.springframework.boot spring-boot-starter-web org.springframework.data spring-data-mongodb 1.9.6.RELEASE org.allowed.bitarus.springTestApp.Application maven-compiler-plugin 2.3.2 org.springframework.boot spring-boot-maven-plugin spring-releases http://repo.spring.io/libs-release spring-releases http://repo.spring.io/libs-release }}} === src/main/resources/application.properties === {{{#!highlight bash # disable web container/server spring.main.web-environment=false threadpool.nrExecutors=5 mongox.host=127.0.0.1 mongox.port=27017 mongox.database=mydatabase }}} === src/main/java/org/allowed/bitarus/springTestApp/Application.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.SpringApplication; import org.springframework.context.annotation.ComponentScan; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import java.util.concurrent.Future; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; import org.springframework.data.mongodb.core.MongoTemplate; import com.mongodb.Mongo; import org.springframework.core.env.Environment; import javax.annotation.Resource; @ComponentScan @EnableAutoConfiguration @SpringBootApplication @EnableMongoRepositories // search for MongoDB reps public class Application { @Resource Environment _env; public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean(name="tasksFutures") public ArrayList> createTasksFutures(){ System.out.println("Creating tasksFutures"); return new ArrayList>(); } @Bean(name="executors") public ExecutorService createExecutors(){ System.out.println("Creating executors"); System.out.println(_env.getProperty("threadpool.nrExecutors")); return Executors.newFixedThreadPool(5); } @Bean(name="mongoTemplate") public MongoTemplate mongoTemplate() throws Exception { System.out.println("Creating mongoTemplate"); System.out.println(_env.getProperty("mongox.host")); System.out.println(_env.getProperty("mongox.port")); System.out.println(_env.getProperty("mongox.database")); Mongo mongo = new Mongo( _env.getProperty("mongox.host"), Integer.parseInt(_env.getProperty("mongox.port") ) ); return new MongoTemplate(mongo, _env.getProperty("mongox.database") ); } } }}} === src/main/java/org/allowed/bitarus/springTestApp/Tasker.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.stereotype.Component; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @Component("tasker") public class Tasker { private ExecutorService _es; public Tasker(@Qualifier("executors") ExecutorService es){ System.out.println("Created Tasker !!!!"); _es = es; } public Future addTask(TaskX taskx){ Future f = _es.submit( taskx ); return f; } } }}} === src/main/java/org/allowed/bitarus/springTestApp/Result.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.data.annotation.Id; public class Result { @Id private String id; private int sumResult; public Result(){} public int getSumResult(){return this.sumResult;} public void setSumResult(int sumResult){this.sumResult=sumResult;} public String getId(){return this.id;} public void setId(String id){this.id=id;} } }}} === src/main/java/org/allowed/bitarus/springTestApp/Receiver.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import org.springframework.stereotype.Component; import java.util.concurrent.Future; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Qualifier; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.MongoTemplate; @Component public class Receiver { private Tasker _t; private ArrayList> _tasks; private ResultRepository _repository; public Receiver(@Qualifier("tasker")Tasker t, @Qualifier("tasksFutures") ArrayList> tasks, ResultRepository repository ){ System.out.println("Created receiver !!!!"); _t = t; _tasks = tasks; _repository = repository; } @Autowired private MongoTemplate mongoTemplate; @PostConstruct public void init(){ System.out.println("Init post construct"); for(int i=0;i<10;i++){ _tasks.add( _t.addTask( new TaskX(5,6) ) ); } // wait for all tasks ... boolean loop=true; while(loop){ boolean allDone=true; for(Future f : _tasks){ if(f.isDone()==false){ allDone=false; } } if(allDone){ loop=false; } try{ Thread.sleep(1000); } catch(Exception ex){ } } for(Future f : _tasks){ try{ Integer res = f.get(); System.out.println(res); Result r = new Result(); r.setSumResult(res); _repository.save(r); } catch(Exception ex){ } } System.out.println( _repository.count() ); List res = _repository.findBySumResult(11); for(Result r : res){ r.setSumResult((int)System.currentTimeMillis()); _repository.save(r); } System.out.println("mongoTemplateCount " + mongoTemplate.count(new Query() ,Result.class) ); } } }}} === src/main/java/org/allowed/bitarus/springTestApp/ResultRepository.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import java.util.List; import org.springframework.data.mongodb.repository.MongoRepository; /* Result -> class to store String -> id in collection type Collection result in database mydatabase { "_id" : ObjectId("58828e2822e1a609d96a5e52"), "_class" : "org.allowed.bitarus.springTestApp.Result", "sumResult" : 11 } */ public interface ResultRepository extends MongoRepository { public List findBySumResult(int sumResult); } }}} === src/main/java/org/allowed/bitarus/springTestApp/TaskX.java === {{{#!highlight java package org.allowed.bitarus.springTestApp; import java.util.concurrent.Callable; public class TaskX implements Callable{ private int _x; private int _y; public TaskX(int x,int y){ _x=x; _y=y; } public Integer call() { try { Thread.sleep(5000); } catch(Exception ex){ } int sum = _x+_y; System.out.println("TID:"+Thread.currentThread().getId() + " sumVal:" + sum ); return sum; } } }}} == Integration tests == Integration tests setup and start Spring context before running the tests. {{{#!highlight java // org.springframework.boot // spring-boot-starter-test @Test // test case @RunWith(SpringRunner.class) @MockBean // inject mocked beans // Mockito, given , willReturn Mocks simulates real objects @SpyBean // create proxy for a real object @SpringBootTest // test application context @ActiveProfiles("test") // use application properties for test profile @WebFluxTest // web flux controllers tests @WebMvcTest // web tests //Mockito mocks doNothing().when(objx).objMethod() doReturn(response).when(objx).objMethod() doThrow(Exception.class).when(objx).objMethod() doCallRealMethod().when(objx).objMethod() // application-.properties // application-.yml application-test.properties application-test.yml // org.springframework.test.util.ReflectionTestUtils // ReflectionTestUtils is a collection of reflection-based utility methods for use in unit and integration testing scenarios. ReflectionTestUtils.setField(obj,"fieldname",value) ReflectionTestUtils.invokeMethod(obj,"methodName",args) }}} == JPARepository == * https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html Captures the domain type to manage as well as the domain type's id type. * https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Repository.html Mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects. Specialization of @Component. {{{#!highlight java import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public Repo implements JpaRepository{ } }}} == ConfigurationProperties == * https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html * https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/EnableConfigurationProperties.html * Annotation for externalized configuration. * @EnableConfigurationProperties * @ConfigurationProperties {{{#!highlight sh @ConfigurationProperties(prefix = "server") public class ServerProperties { private Map app; private Map> config; }}}