페이지

2020년 4월 2일 목요일

Spring Boot





  • What is Spring Boot
  1. Radically faster getting started experience
  2. "Opinionated" approach to configuration / defaults
       - Intelligent defaults
       - Gets out of the way quickly


    3. What does it involve?
       - Easier dependency management
       - Automatic configuration / reasonable defaults
       - Different build / deployment options.


  • What Spring Boot is NOT
  1. Plugins for IDEs
       - Use Boot with any IDE(or none at all)

    2. Code generation

___________________________________________________________________________
Demonstration - Spring Boot

Create a new, bare-bones Spring application

eclipse
Help -> eclipse marketplace -> spring ide search -> Spring Tools 4 (aka Spring Tool suite 4) 4.6.0. RELEASE -> install -> restart

Project Explorer right click -> new -> other -> Spring Boot -> Spring Starter Project

name: microserviceBoot, java Version 8 -> next -> next


"Tomcat version 8.0 only supports J2EE 1.2, 1.3, 1.4, and Java EE 5 and 6 WEb modules"
project foloer .settings>org.eclipse.wst.common.project.facet.core.xm

          

 
 
 
 
 
  4.0
"/>  => 2.5
 


____________________________________________________________________________

  • Spring Boot - What just Happened?
  1. Boilerplate project structure created
      - Mostly folder structure
      - "Application" class + test
      - Maven POM (or Gradle if desired)

    2. Dependency Management


  • Running Spring Boot-What Just Happened?
  1. SpringApplication
        - Created Spring Application Context

    2. @SpringBootApplication
       - Combination of @Configuration
           i) Marks a configuration file
           ii) Java equivalent of file
       
       - ...And @ComponentScan
           i) Looks for @Componenrts (none at the moment)

       - ...And @EnableAutoConfiguration
           i) Master runtime switch for Spring Boot
           ii) Examines ApplicationContext & classpath
           iii) Creates missing beans based on intelligent defaults


____________________________________________________________________________________
Demonstration - Adding Web Capability

- Adding spring-boot-starter-web dependency
- Adding HelloController

pom.xml
spring-boot-starter => spring-boot-starter-web

com.example.demo package
create classes => WhateverIWant

package com.example.demo;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class WhateverIWant {

@RequestMapping("/hi")
public @ResponseBody String hiThere()
{
return "hello world!";
}

}


Run As -> Spring Boot App

____________________________________________________________________________________

  • Adding Web - What Just Happened?
  1. spring-boot-starter-web Dependency
       - Adds spring-web, spring-mvc jars
       - Adds embedded Tomcat jars

    2. When application starts...
       - Your beans are created
       - @EnableAutoConfiguration looks for  'missing' beans
          i) Based on your beans + classpath
          ii) Notices @Controller / Spring MVC jars
     
       - Automatically creates MVC beans
          i) DispatcherServlet, HandlerMappings, Adapters, ViewResolvers

       - Launches embedded Tomcat instance.



  • But wait, I want a WAR...
  1. To Convert from JAR to WAR:
      - Change POM packaging
      - Extend SpringBootServletInitializer

 


   2. Deploy to app server
      - URL becomes http://localhost:8080//

_______________________________________________________________________________________

Demonstration - WAR Deployment

-WAR Packaging
-SpringBootServletInitializer


pom.xml

element 
 jar -> war
 or add war


MicroservicesBootApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class MicroservicesBootApplication extends SpringBootServletInitializer{


/**
* Used when run as a JAR
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(MicroservicesBootApplication.class, args);
}

/**
* Used when run as a WAR
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {

return builder.sources(MicroservicesBootApplication.class);
}



}

________________________________________________________________________________________

  • What about Web Pages?
  1. Spring MVC supports a wide range of view options
  2. Easy to use JSP, Freemarker, Velocity, Thymeleaf
  3. Boot automatically establishes defaults
      - InternalResourceViewResolver for JSPs
      - ThymeleafViewResolver
         i) If Thymeleaf is on the classpath
    
     4. spring-boot-starter-thymeleaf

___________________________________________________________________________________________

Demonstration - Thymeleaf web pages

- spring-boot-starter-thymeleaf
- /templates folder
- Controller adjustments
- Web page


pom.xml

add


org.springframework.boot
spring-boot-starter-thymeleaf

search google  => spring boot reference

spring Boot Reference Guide

spring-boot-starter-thymeleaf 

resource add Folder
name: templates

add hello.html




Hello name-goes-heae from a Thymeleaf page





WhateverIWant.java

@RequestMapping("/hi/{name}")
public  String hiThere(Map model, @PathVariable String name)
{
model.put("name", name);
return "hello";
}

____________________________________________________________________________________________

  • What Just Happended?
  1. spring-boot-starter-theymeleaf
       - Brought in required jars
       - Automatically configured ThymeleafViewResolver

    2. Controller returned a 'logical view name'
   
    3. View Resolver found a matching template

    4. Render



  • But wait, I want JSPs...

  1. Thymeleaf and other templating approaches are way too advanced for my organization!
       - Besides, we have lots of existing JSPs


    2. No Problem!
  
    3. Just as easy to use JSPs!
       - Place JSPs in desired web-relative location
       - Set spring.mvc,view.prefix / spring.mvc.view.suffix as needed. 
       - (remove thymeleaf starter pom)

______________________________________________________________________________________________

Demonstration - JSP Web Pages

- Place JSP in desired folder
- Set spring.mvc.view.prefix / spring.mvc.view.suffix
- Exclude spring-boot-starter-tomcat

Project Explorer

src -> main -> webapp -> create folder -> WEB-INF -> views -> hello.jsp





Hello ${name} from a JSP page




src/main/resources/appcliaction.properties


spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp



_______________________________________________________________________________________________

  • What Just Happened?
  1. No ThymeleafViewRresolver configured
  2. Controller returned a 'logical view name'
  3. InternalResourceViewResolver forwarded to JSP
  4. Render



  • Spring & REST
  1. REST capability is built in to Spring MVC
      - Simply use domain objects as parameters / return values.
      - Mark with @RequestBody / @ResponseBody
      - Spring MVC automatically handles XML/JSON conversion
           *Based on converters available in classpath.


___________________________________________________________________________________________

DemonStration - REST Controllers in Spring MVC
 
- Additional domain objects
- Automatic HTTP Message Conversion


package com.example.demo.domain;

public class Player {

String name;
String position;



public Player() {
super();

}


public Player(String name, String position) {
this();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}



}



package com.example.demo.domain;

import java.util.Set;

public class Team {
String name;
String location;
String mascotte;
Set players; 
public Team() {
super();
}

public Team(String location, String name, Set players) {
this();
this.location = location;
this.name = name;
this.players = players;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getMascotte() {
return mascotte;
}
public void setMascotte(String mascotte) {
this.mascotte = mascotte;
}
public Set getPlayers() {
return players;
}
public void setPlayers(Set players) {
this.players = players;
}

}



package com.example.demo;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.example.demo.domain.Player;
import com.example.demo.domain.Team;

@Controller
public class WhateverIWant {
private Team team;
@PostConstruct
public void init()
{
Set players = new HashSet<>();
players.add(new Player("Charlien Brown", "pitcher"));
players.add(new Player("Snoopy", "shortstop"));
team = new Team("California", "Peanuts", players);
}
@RequestMapping("/hi")
public @ResponseBody Team hiThere()
{
return team;
}

}


____________________________________________________________________________________________


What Just Happened?

1. Controller returned a domain object
   - Not a logical view name (page)

2. Spring MVC noticed @ResponseBody
   - Or @RestController

3. Invoked correct HttpMessageConverter
  - Based on
     * Requested format
     * JARS on classpath


What if I want XML?

1. No Problem!

2. Annotate domain classes with JAXB annotations
  - JAXB already part of java SE

3. When App Starts
   - Spring creates HttpMessageConverter fo JAXB
      * Based on classpath contents

4. XML or JSON returned
   - based on requested format



@XmlRootElement   => xml out
Accept: application/xml

Accept: application/json


Adding JPA Capability

1. Adding the spring-boot-starter-data-jps Dependency
   - Adds Spring JDBC/ Transaction Management
   - Adds Spring ORM
   - Adds Hibernate / entity manager
   - Adds Spring Data JPA subproject
     * (explained later)


2. Does NOT add a Database Driver
   - Add one manually (HSQL)






Spring Data JPA

1. Typical web application architecture

2. REST Controllers provide CRUD interface to clients

3. DAO provide CRUD interface to DB




Spring Data - Instant Repositories

1. Spring Data provides dynamic repositories

2. You provide the interface, Spring Data dynamically implements.
- JPA, MongoDB, GemFire, etc.

3. Service Layer / Controllers have almost no logic.


_____________________________________________________________________________________________

Demonstraion - Adding Spring Data JPA

- spring-boot-starter-data-jpa
- org.hsqldb / hsqldb
- Annotate domain objects with JPA
- Extend CrudRepository


pom.xml


org.springframework.boot
spring-boot-starter-data-jpa


org.hsqldb
hsqldb



package com.example.demo.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Player {

@Id @GeneratedValue
Long id;
String name;
String position;



public Player() {
super();

}


public Player(String name, String position) {
this();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}



}



package com.example.demo.domain;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
@Entity
public class Team {
@Id @GeneratedValue
Long id;
String name;
String location;
String mascotte;
@OneToMany(cascade=CascadeType.ALL) 
@JoinColumn(name="teamId")
Set players; 
public Team() {
super();
}

public Team(String location, String name, Set players) {
this();
this.location = location;
this.name = name;
this.players = players;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getMascotte() {
return mascotte;
}
public void setMascotte(String mascotte) {
this.mascotte = mascotte;
}
public Set getPlayers() {
return players;
}
public void setPlayers(Set players) {
this.players = players;
}

}

package com.example.demo.dao;



import java.util.List;

import org.springframework.data.repository.CrudRepository;

import com.example.demo.domain.Team;

public interface TeamDao extends CrudRepository {
List findAll();
Team findByName(String name);

}


package com.example.demo;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

import com.example.demo.dao.TeamDao;
import com.example.demo.domain.Player;
import com.example.demo.domain.Team;

@SpringBootApplication
public class MicroservicesBootApplication extends SpringBootServletInitializer{

/**
* Used when run as a JAR
* @param args
*/
public static void main(String[] args) {
SpringApplication.run(MicroservicesBootApplication.class, args);
}

/**
* Used when run as a WAR
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(MicroservicesBootApplication.class);
}
@PostConstruct
public void init()
{
Set players = new HashSet<>();
players.add(new Player("Charlien Brown", "pitcher"));
players.add(new Player("Snoopy", "shortstop"));
Team team = new Team("California", "Peanuts", players);
teamDao.save(team);
}
@Autowired TeamDao teamDao;

}


package com.example.demo;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.dao.TeamDao;
import com.example.demo.domain.Player;
import com.example.demo.domain.Team;

@RestController
public class WhateverIWant {
@Autowired TeamDao teamDao;

@RequestMapping("/teams/{name}")
public  Team hiThere(@PathVariable String name)
{
return teamDao.findByName(name);
}

}

_____________________________________________________________________________________________

Adding Spring Data JPA - What Just Happened?

1. What I did:
  - Added dependencies for spring-boot-starter-data-jpa and hsqldb
  - Annotated Domain objects with plain JPA annotations
  - Added an interface for Spring Data JPA
  - Dependency injected info controller


2. When application starts...
   - Spring Data dynamically implements repositories
     * find*(), delete(), save() methods implemented.
   - DataSource, Transaction Management, all handled.


Spring Data - REST

1. Often, applicatons simply expose DAO methods as REST resources

2. String Data REST handles this automatically...

Adding Spring Data REST

1. Plugs into dynamic repositories

2. Generates RRESTful interface
 - GET, PUT, POST, DELETE

3. Code needed only to override defaults.


__________________________________________________________________________________________

__________________________________________________________________________________________

Adding Spring Data REST - What Just Happened?

1. when applicaton starts...
   - @RestResource annotations interpreted
   - @Controllers beans created
   - @RequestMappings created


Adding HATEOAS

1. Spring Data Rest simply returns RESTful resources
- Conversion handled by Jackson, or JAXB

2. Underlying Data Relationships used to build Links
- If matching repositories exist

3. Consider the Team -> Player relationship

4. Player Repository needed to force link creation


__________________________________________________________________________________________

Demonstration - Adding HATEOAS Links
-  Creating a Player DAO


package com.example.demo.domain;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Player {

@Id @GeneratedValue
Long id;
String name;
String position;



public Player() {
super();

}


public Player(String name, String position) {
this();
this.name = name;
this.position = position;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPosition() {
return position;
}
public void setPosition(String position) {
this.position = position;
}



}

_______________________________________________________________________________________________

HATEOAS - What Just Happened?

1. Spring Data REST noticed two repositories
  - The relationship between entities is know via JPA annotations.

2. Spring automatically represents the children as links
  - @RestResource determines names of links


Summary
1. Spring Boot makes it easy to start projects
  - And easy to add featrure sets to projects
  - Opinionated apporach
  - Run as JAR or WAR
  - Web Applications (JSP, Thymeleaf, others)

2. REST
  - Automatic resource conversion

3. Spring Data JPA
  - Automatic repository implementation
 
4. Spring Data REST
  - Automatic REST controllers