Slide 1

Slide 1 text

Spring Boot - Framework Jussi Pohjolainen

Slide 2

Slide 2 text

Java as a Platform • Java SE for Desktop • JRE does not come bundled with Windows or Mac OS X. In Linux, it depends on the distribution. • Java EE for Enterprise • Platform for developing backend services • Good compability with legacy systems • Web servers, application servers • Java ME for Mobile • Android uses Java language (Altough Kotlin is preferred), but does not support Java ME! • Support today....? 2

Slide 3

Slide 3 text

Java/Jakarta EE • Oracle: Java Enterprise Edition (Java EE) 8 • Former name: Java 2 Platform Enterprise Edition (J2EE) • Set of specifications for enterprise applications • Java EE apps runs on application servers • https://javaee.github.io/tutorial/toc.html • Eclipse Foundation: Jakarta EE 8 • From 2019 Java EE was rebranded to Jakarta EE • Oracle does not maintain Java EE anymore • Eclipse does not own trademark Java, so Jakarta is used • https://eclipse-ee4j.github.io/jakartaee-tutorial/toc.html • Spring Boot is maybe more popular choice for backend

Slide 4

Slide 4 text

Year Java Version 2004 J2SE5 2006 (2 years) Java SE 6 2011 (5 years) Java SE 7 2014 (4 years) Java SE 8 (LTS) 2017 September (3 years) Java SE 9 2018 March (6 months) Java SE 10 2018 September (6 months) Java SE 11 (LTS) 2019 March (6 months) Java SE 12 2019 September (6 months) Java SE 13 2020 March (6 months) Java SE 14 2020 September (6 months) Java SE 15 2021 March (6 months) Java SE 16 2021 September (6 months) Java SE 17 (LTS) 2022 March (6 months) Java SE 18 2022 September (6 months) Java SE 19

Slide 5

Slide 5 text

OpenJDK Oracle Commercial JDK Oracle OpenJDK Redhat OpenJDK Eclipse Temurin Amazon Corretto Azul Zulu Alibaba dragonwell BellSoft Liberica JDK

Slide 6

Slide 6 text

Java EE Specifications • Java EE is described using specifications, JSRs • There may be different vendor implementations for these specifications • For example object to relational database mapping has a specification JPA • Hibernate, EclipseLink, etc are the implementations of the JPA • Advantage: you can change the implementation! • Disadvantage: slow progress on specifications

Slide 7

Slide 7 text

Example Java EE REST - specifications Servlet API Java API for RESTful Web Services Java Persistence API

Slide 8

Slide 8 text

REST – specifications: abbreviations and versions Servlet 3.1 JAX-RS 2.0 JPA 2.1

Slide 9

Slide 9 text

Different Implementations! JAX-RS 2.0: Jersey | RESTEasy | Restlet | ... JPA 2.1: EclipseLink | Hibernate ... Servlet 3.1: Oracle

Slide 10

Slide 10 text

Servlet Container: GlassFish • Open Source application server project started by Sun Microsystems for Java EE • Reference implementation of Java EE • Supports • JAX-RS, EJB, JavaServer Faces / Pages, RMI, Servlets etc.. • Allows developers to create enterprise apps that are portable and scalable • Download • https://glassfish.java.net/download.html • Next version of GlassFish (Java EE 8) is under development and will be published in GitHub: • https://github.com/glassfish

Slide 11

Slide 11 text

GlassFish is Bundled With Following Implementations JAX-RS 2.0: Jersey JPA 2.1: EclipseLink Servlet 3.1: Oracle

Slide 12

Slide 12 text

Spring Framework

Slide 13

Slide 13 text

Spring Framework • Application framework for Java Platform • Core features can be used with Java SE • Features embedded server • Alternative approach for EJBs and App Servers • Possible to create war packages that can be run on App Servers • Lot of modules • Data Access, Web ...

Slide 14

Slide 14 text

Google Trends

Slide 15

Slide 15 text

Spring Boot • Spring Boot is "convention over configuration" solution for creating stand-alone Spring Apps • Opinionated view of the Spring Platform • Features • Embed Tomcat or Jetty directly (no need for WAR files) • Provides POM files for Maven • Tries to automatically configure Spring whenever possible • No requirement for xml generation

Slide 16

Slide 16 text

Tools • You can do everything in command line using tools like maven or gradle • Spring provides Spring Tool Suite (STS) which is basically an Eclipse Java EE with Spring plug-in • Or you can use Netbeans or IntelliJ IDEA CE / Ultimate

Slide 17

Slide 17 text

Build Tools: Maven

Slide 18

Slide 18 text

Build Tools • Ant (2000) • One of the first "modern" build tools • Very popular among Java • Easy, uses procedural programming idea • Uses XML which is not very good on the concept of procedural programming • XML can began to be very big • Maven (2004) • Uses also XML, but structure is different • Relies conventions and provides available targets (goals) • Has repository support (dependencies) • Gradle (2007) • Uses DSL instead of XML

Slide 19

Slide 19 text

Convention over Configuration • Developers are not required to create build process • Maven offers sensible default behavior for projects • Maven creates a default project structure • Developer adds files to directories and writes configuration to pom.xml

Slide 20

Slide 20 text

Default Project Structure Item Default source code src/main/java resources src/main/resources tests src/test jar target/ byte code target/classes

Slide 21

Slide 21 text

pom.xml • POM, Project Object Model, is an xml file • Base directory of your project • Information about the project and compiling process • Defines dependencies • The pom.xml can inherit a super pom, which provides basic configuration

Slide 22

Slide 22 text

pom.xml 4.0.0 fi.organization my-app 1.0 17 17 artifact is a file and each artifact has a group id, usually like package in Java. Also version is defined. GroupId + artifactId + version creates uniquely identified artifact. Project's dependencies are specified as artifacts

Slide 23

Slide 23 text

Project Structure . ├── pom.xml └── src └── main └── java └── com └── company └── Main.java

Slide 24

Slide 24 text

Main.java package com.company; public class Main { public static void main(String [] args) { System.out.println("Hello World"); } }

Slide 25

Slide 25 text

Commands • To compile • mvn compile • To test (using JUnit) • mvn test • Create jar file • mvn package • To remove target • mvn clean • To run • mvn exec:java -Dexec.mainClass="com.company.Main" • To create Eclipse project • mvn eclipse:eclipse

Slide 26

Slide 26 text

Easier Running with plug-in: mvn exec:java org.codehaus.mojo exec-maven-plugin 1.5.0 com.company.Main false

Slide 27

Slide 27 text

Main – class for jar org.apache.maven.plugins maven-jar-plugin 3.0.2 com.company.Main

Slide 28

Slide 28 text

public class Main { public static void main(String [] args) { try { String data = makeHttpRequest("https://jsonplaceholder.typicode.com/todos/"); System.out.println(data); } catch(URISyntaxException | IOException | InterruptedException e) { e.printStackTrace(); } } public static String makeHttpRequest(String url) throws URISyntaxException, IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(new URI(url)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); return response.body(); } } Uses HttpClient to make http request

Slide 29

Slide 29 text

JSON Parsing ... import org.json.*; public class Main { public static void main(String [] args) { try { String data = makeHttpRequest("https://jsonplaceholder.typicode.com/todos/"); // Output the first title JSONArray allTodos = new JSONArray(data); JSONObject todo = allTodos.getJSONObject(0); System.out.println(todo.getString("title")); } catch(URISyntaxException | IOException | InterruptedException e) { e.printStackTrace(); } } Will Fail! This is not part of java se!

Slide 30

Slide 30 text

Dependency to pom.xml org.json json 20190722

Slide 31

Slide 31 text

Location of downloaded jars • In Unix/Mac • ~/.m2 • In Windows • C:\Documents and Settings\{user-name}\.m2

Slide 32

Slide 32 text

Hello World Spring Boot

Slide 33

Slide 33 text

Steps 1. Define pom.xml 2. Create dir structure • src/main/java/mypackage 3. Create App Starter class

Slide 34

Slide 34 text

Step 1: pom.xml

Slide 35

Slide 35 text

Spring Initializr for Project Creation

Slide 36

Slide 36 text

curl usage! • You can use the initializr via HTTP and curl • curl https://start.spring.io • Example • curl https://start.spring.io/star ter.zip -d dependencies=web -o demo.zip

Slide 37

Slide 37 text

4.0.0 org.springframework.boot spring-boot-starter-parent 2.5.5 com.example demo 0.0.1-SNAPSHOT demo Demo project for Spring Boot 17 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin

Slide 38

Slide 38 text

Step 2: Dir Structure mkdir -p src/main/java/company

Slide 39

Slide 39 text

Step 3: App Starter Class

Slide 40

Slide 40 text

Step 3: App Starter package company; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ComponentScan; @EnableAutoConfiguration @Configuration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Slide 41

Slide 41 text

@EnableAutoConfiguration @Configuration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } Attempts to automatically configure your Spring application based on the jar dependencies that you have added. For example, If HSQLDB is on your classpath, and you have not manually configured any database connection beans, then we will auto-configure an in- memory database.

Slide 42

Slide 42 text

@EnableAutoConfiguration @Configuration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } Indicates that a class declares one or more @Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime. At this time no beans.

Slide 43

Slide 43 text

@EnableAutoConfiguration @Configuration @ComponentScan public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } Search for other components, configurations in the specified package. If no package is specified, current class is taken as the root package.

Slide 44

Slide 44 text

@SpringBootApplication package company; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @SpringBootApplication == @EnableAutoConfiguration, @Configuration, @ComponentScan

Slide 45

Slide 45 text

Compile and Run • Compile • mvn compile • Run • mvn spring-boot:run

Slide 46

Slide 46 text

@Bean - Example import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner doIt() { class MyCommandLineRunner implements CommandLineRunner { public void run(String... args) { System.out.println("Hello World from @Bean!"); } } return new MyCommandLineRunner(); } } @SpringBootApplication contains @Configuration, so it detects methods with @Bean. The method is invoked for you and a new bean is created to container. The Bean created here implements special CommandLineRunner which creates a bean that is run when app starts

Slide 47

Slide 47 text

@Bean - Example import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner doIt() { return (args) -> System.out.println("Hello World from @Bean!"); } } Using Java 8 Lambda

Slide 48

Slide 48 text

Using Components package fi.company import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component class MyCommandLineRunner implements CommandLineRunner { public void run(String... args) { System.out.println("Hello World!"); } } Indicates that an annotated class is a Spring Bean "Component". Spring will create an object from this class for you calling the default constructor. Such classes are considered as candidates for auto-detection when using annotation-based configuration and classpath scanning.

Slide 49

Slide 49 text

Creating jar • To generate a jar, use • mvn package • Although this will just create a jar with your classes! Filesize is ~3kb • It's not a self-contained uber – jar!

Slide 50

Slide 50 text

Spring Boot Maven Plugin • Allows you to create uber-jar! • Add plugin to pom and mvn package again org.springframework.boot spring-boot-maven-plugin

Slide 51

Slide 51 text

Lab

Slide 52

Slide 52 text

Spring Boot Developer Tools • Add a Dependency for Spring Boot Developer Tools • Property defaults • Caching in templates is a good thing in production. In development phase it can be a bad thing. Developer tools disables caching. • Automatic restart • Restart server automatically when changes in classpath • LiveReload • Includes a embedded LiveReload server that triggers a browser refresh! • Needs browser extension from livereload.com

Slide 53

Slide 53 text

Structuring your Code • Avoid "default package" • can cause problems with annotations • Place main app class in the root package com +- example +- myproject +- Application.java | +- domain | +- Customer.java | +- CustomerRepository.java | +- service | +- CustomerService.java | +- web +- CustomerController.java

Slide 54

Slide 54 text

Logging • Spring Boot provides Commons Logging and leaves the underlying implementation open • Default implementations are Java Util Logging, Log4J2 and Logback • By default, if you use spring- boot-starter-logging in pom.xml this is preconfigured to use Logback org.springframework.boot spring-boot-starter-logging 1.5.3.RELEASE

Slide 55

Slide 55 text

import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class LoggingDemoApplication implements CommandLineRunner { private Log logger = LogFactory.getLog(LoggingDemoApplication.class); public static void main(String[] args) { SpringApplication.run(LoggingDemoApplication.class, args); } @Override public void run(String... strings) throws Exception { logger.debug("This is a debug message"); logger.info("This is an info message"); logger.warn("This is a warn message"); logger.error("This is an error message"); } }

Slide 56

Slide 56 text

Output Notice that the debug here is missing

Slide 57

Slide 57 text

application.properties • Spring Boot allows external configuration • In maven, create src/main/resources/application.properties • This file is read automatically and contains key = value pairs

Slide 58

Slide 58 text

Setting Level: application.properties logging.level.root = debug You will get a lot more logging output, also from the framework

Slide 59

Slide 59 text

Spring Dependency Injection

Slide 60

Slide 60 text

Dependency Injection • Bad Design • Change impacts on every other part of the system • Changes break other parts of the system • Reuse is hard because components are tied up • Solution • Depend on abstractions, not concretions • Java: use interfaces, not implementations • Spring: Use spring container where beans are stored

Slide 61

Slide 61 text

Spring Container • Spring Container is at the core of the Spring Framework • Container will • create objects • wire them together • configure them • manage lifecycle • Objects in the Spring Container are called Spring Beans • What objects to instantiate? Configuration metadata • Can be xml, java annotations or java code

Slide 62

Slide 62 text

Define Interface public interface Movable { public void move(); }

Slide 63

Slide 63 text

Define Implementation to the Interface import org.springframework.stereotype.Service; @Service public class Car implements Movable { public void move() { System.out.println("Car is moving!"); } } Candidate for auto-detection when using annotation-based configuration and classpath scanning. Holds business logic.

Slide 64

Slide 64 text

Spring @Autowired @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired private Movable someMovebleObject; public void run(String... args) { someMovebleObject.move(); } } Candidate for auto-detection when using annotation-based configuration and classpath scanning. General Component. Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.

Slide 65

Slide 65 text

What If Two Concrete Classes? import org.springframework.stereotype.Service; @Service public class Human implements Movable { public void move() { System.out.println("Human is moving"); } }

Slide 66

Slide 66 text

Error! Description: Field someMovebleObject in company.MyCommandLineRunner required a single bean, but 2 were found: - car: defined in file [../classes/company/Car.class] - human: defined in file [../classes/company/Human.class]

Slide 67

Slide 67 text

@Primary @Service @Primary public class Car implements Movable { public void move() { System.out.println("Car is moving!"); } }

Slide 68

Slide 68 text

Bean Name @Service("Human") public class Human implements Movable { public void move() { System.out.println("Human is moving"); } } @Service("Car") public class Car implements Movable { public void move() { System.out.println("Car is moving!"); } }

Slide 69

Slide 69 text

@Qualifier @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired @Qualifier("Car") private Movable movableObject; public void run(String... args) { movableObject.move(); } }

Slide 70

Slide 70 text

@Component • Candidate for auto-detection when using annotation-based configuration and classpath scanning • Special cases: • @Service • For businesslogic, no additional behaviour • @Repository • For data access object • @Controller • Used as a controller in Spring Web MVC

Slide 71

Slide 71 text

@Service • An operation offered as an interface that stands alone in the model, with no encapsulated state. • "Business Serfice Facade" • Specialization of @Component

Slide 72

Slide 72 text

Example @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired private MyBeanLogger myBeanLogger; public void run(String... args) { System.out.println( myBeanLogger.getAllBeans() ); } } Common Bean that is created and added to Spring Container Interface used to indicate that a bean should run when it is contained within a SpringApplication. Inject here some bean that implements MyBeanLogger Use the implementation of the interface

Slide 73

Slide 73 text

Example public interface MyBeanLogger { public String getAllBeans(); }

Slide 74

Slide 74 text

@Service("ThisIsMyBeanLogger") public class BeanLoggerImplementation implements MyBeanLogger { @Autowired ApplicationContext applicationContext; @Override public String getAllBeans() { String allBeans = ""; String[] beanNames = applicationContext.getBeanDefinitionNames(); for (String beanName : beanNames) { allBeans += beanName + " : " + applicationContext.getBean(beanName).getClass().toString() + "\n"; } return allBeans; } } This is a bean that provides business logic Inject here some bean that implements ApplicationContext

Slide 75

Slide 75 text

Output ... org.springframework.boot.type.classreading.ConcurrentReferenceCachingMetadataRead erFactory ThisIsMyBeanLogger : class company.BeanLoggerImplementation myCommandLineRunner : class company.MyCommandLineRunner org.springframework.boot.autoconfigure.AutoConfigurationPackages : class ...

Slide 76

Slide 76 text

@Configuration • Annotating a class with the @Configuration indicates that it will have source of bean specifications • You may have one @Configuration or many • @Bean is a method level annotation • But in simple cases you don't need any configurations

Slide 77

Slide 77 text

@Configuration public class MovableConfiguration { @Bean public Movable getHuman() { return new Human(); } } Define a configuration of our beans. Now we dont' need the @Service in Human and it's possible to create the object in more detail (not just default constructor)

Slide 78

Slide 78 text

Life Cycle of Spring Beans • In traditional Java: use new operator and finalize() is invoked when garbage collector cleans the object • In Spring: define methods for init and destroy • @Bean: custom init() and destroy() • Or you can use @PostConstruct and @PreDestroy

Slide 79

Slide 79 text

@Configuration, init and destroy @Configuration public class MovableConfiguration { @Bean(name = "Car", initMethod = "init", destroyMethod = "cleanup" ) public Movable getCar() { return new Car(); } }

Slide 80

Slide 80 text

And the class public class Car implements Movable { public void move() { System.out.println("Car is moving!"); } public void init() { System.out.println("CAR INIT!"); } public void cleanup() { System.out.println("CAR CLEANUP!"); } }

Slide 81

Slide 81 text

Are these two different objects? @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired private Movable movableObject1; @Autowired private Movable movableObject2; public void run(String... args) { System.out.println(movableObject1); System.out.println(movableObject2); } }

Slide 82

Slide 82 text

Scopes • When declaring a Bean you can also define a scope • Options • Singleton • Only single instance of the class, default • Prototype • Can have many any number of object instances • Note: Spring does not manage the complete lifecycle of a prototype bean: the container instantiates, configures, decorates and otherwise assembles a prototype object, hands it to the. Spring will not call destroy methods • For Web Development • request, session, global-session

Slide 83

Slide 83 text

Example @Configuration public class MovableConfiguration { @Bean(name = "Car") @Scope("prototype") public Movable getCar() { return new Car(); } }

Slide 84

Slide 84 text

Constructor Based Autowiring @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired private Car mercedes; @Autowired private Car bmw; public void run(String... args) { System.out.println(mercedes); System.out.println(mercedes.getMotor()); System.out.println(bmw); System.out.println(bmw.getMotor()); } } It is not necessary to use interfaces, but usually wise to do!

Slide 85

Slide 85 text

Car @Component @Scope("prototype") public class Car { @Autowired private Motor motor; public Car() { System.out.println("Constructor!, motor = " + motor); } public Motor getMotor() { return this.motor; } public void move() { System.out.println("Car is moving!"); } } It's null!

Slide 86

Slide 86 text

Car @Component @Scope("prototype") public class Car { private Motor motor; @Autowired public Car(Motor motor) { System.out.println("Constructor!"); this.motor = motor; } public Motor getMotor() { return this.motor; } public void move() { System.out.println("Car is moving!"); } } Use constructor based autowiring!

Slide 87

Slide 87 text

Motor @Component @Scope("prototype") public class Motor { }

Slide 88

Slide 88 text

Your App class may be a Configuration also @SpringBootApplication @Configuration public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner commandLineRunner() { class MyCommandLineRunner implements CommandLineRunner { public void run(String... args) { System.out.println("Hello World!"); } } return new MyCommandLineRunner(); } }

Slide 89

Slide 89 text

Usage of Inner Class @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner commandLineRunner() { return new CommandLineRunner() { @Override public void run(String... strings) throws Exception { System.out.println("Hello World!"); } }; } }

Slide 90

Slide 90 text

Usage of Lambda @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public CommandLineRunner commandLineRunner() { return (String... strings) -> System.out.println("Hello World!"); } }

Slide 91

Slide 91 text

Lab

Slide 92

Slide 92 text

Spring Web MVC

Slide 93

Slide 93 text

Spring Web MVC • Spring Web MVC provides Model View Controller architecture for Web apps • Separating • Model – POJO • View – Some View Engine, you can choose • Controller - @Controller • Framework is designed around DispatchServlet that handles all the HTTP requests and responses

Slide 94

Slide 94 text

Diagram of HTTP https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

Slide 95

Slide 95 text

HTTP Flow • Incoming HTTP Request • DispatcherServlet consults HandlerMapping to call appropriate Controller • Controller takes the request, makes perhaps business-logic calls and returns a View Name to the DispatcherServlet. Controller also modifies Model data. • DispatcherServlet takes the name and by using ViewResolver to pickup the the defined view • DispatcherServlet has the view and model data and it will create a view which can be rendered

Slide 96

Slide 96 text

Diagram of HTTP https://www.tutorialspoint.com/spring/spring_web_mvc_framework.htm

Slide 97

Slide 97 text

Diagram of HTTP http://terasolunaorg.github.io/guideline/1.0.1.RELEASE/en/Overview/SpringMVCOverview.html

Slide 98

Slide 98 text

DispatcherServlet • Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service exporters. • Is an actual Servlet that inherites HttpServlet • It can use any HandlerMapping implementation - pre-built or provided as part of an application - to control the routing of requests to handler objects • This is provided for you

Slide 99

Slide 99 text

HandlerMapping • Interface to be implemented by objects that define a mapping between requests and handler objects. • This class can be implemented by application developers, although this is not necessary • Responsible for mapping the routes in @RequestMapping

Slide 100

Slide 100 text

Controller • Controllers provide access to the application behavior that you typically define through a service interface. • Controllers interpret user input and transform it into a model that is represented to the user by the view. • The @Controller annotation indicates that a particular class serves the role of a controller • Spring does not require you to extend any controller base class or reference the Servlet API

Slide 101

Slide 101 text

Example of Controller package mypackage; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; // This class acts as a controller. // Usually when using @Controller, you will use also @RequestMapping @Controller public class MyController { // When HTTP GET, POST, PUT or OTHER request happens // to http://localhost:8080/greeting // invoke this method @RequestMapping("/greeting") // The return value will be the HTTP Body @ResponseBody public String greeting() { return "Hello World"; } }

Slide 102

Slide 102 text

@RequestMapping Example @Controller public class MyWebController { @Autowired private HtmlHelper htmlHelper; @RequestMapping(value = "/something", method = RequestMethod.GET) @ResponseBody public String getData(@RequestParam("name") String name, @RequestParam("age") String age) { return htmlHelper.createHtmlPage("Hello World", "my name is " + name + " and age is " + age); } } This is just my own component that has basic HTML functionality like printing out valid HTML5 page. Normally you would use some view technology for this

Slide 103

Slide 103 text

@RequestMapping Example @Controller public class MyWebController { @Autowired private HtmlHelper htmlHelper; @RequestMapping(value = "/something", method = RequestMethod.POST) @ResponseBody public String getData(@RequestParam("name") String name, @RequestParam("age") String age) { return htmlHelper.createHtmlPage("Hello World", "my name is " + name + " and age is " + age); } } You can also send these via POST

Slide 104

Slide 104 text

Testing Post using curl curl -d "name=jack&age=20" http://localhost:8080/something All Beans my name is jack and age is 20

Slide 105

Slide 105 text

About Thread Safety – Output of this? @Controller public class MyWebController { private List list = new ArrayList<>(); @Autowired private HtmlHelper htmlHelper; @RequestMapping("increment") @ResponseBody public synchronized String getValue() { list.add("terve"); list.remove(random); return "" + list.toString(); } }

Slide 106

Slide 106 text

@Controllers are Singletons! • One instance of DispatcherServlet • Manages a pool of Threads which it uses to respond to connections (HTTP Requests) • When request arrives, one thread is picked up and in the dispatches the @Controller instance methods • If the nature of the controller is stateless, singleton is the way to go • You can change this by using @Scope("prototype")

Slide 107

Slide 107 text

Servlet threading https://www.tutorialspoint.com/servlets/images/servlet-lifecycle.jpg

Slide 108

Slide 108 text

Testing @Controller public class MyWebController { @RequestMapping("thread") @ResponseBody public String getView() { return "object = " + this + " thread = " + Thread.currentThread().getName(); } }

Slide 109

Slide 109 text

View Templates

Slide 110

Slide 110 text

Diagram of HTTP https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html

Slide 111

Slide 111 text

View Templates • In the previous examples we embedded html inside of Java -> Bad practice • Idea is to separate the HTML from the Java • The view layer may use different technologies to render the view • JSP, Thymeleaf, Tiles, Freemarker, Velocity

Slide 112

Slide 112 text

spring-boot-starter-web • spring-boot-starter-web functions like a set of basic dependencies needed to develop web-applications with spring. These basic dependencies are: • jackson-databind • hibernate-validator • spring-core • spring-web • spring-webmvc • spring-boot-starter • spring-boot-starter-tomcat

Slide 113

Slide 113 text

spring-boot-starter-thymeleaf • spring-boot-starter-thymeleaf is based on spring-boot- starter-web and adds some additional dependencies like the thymeleaf template engine: • thymeleaf-layout-dialect • spring-core • spring-boot-starter • spring-boot-starter-web • thymeleaf-spring4

Slide 114

Slide 114 text

Let's use thymeleaf org.springframework.boot spring-boot-starter-thymeleaf

Slide 115

Slide 115 text

Usage of View package mypackage; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; // This class acts as a controller. // Usually when using @Controller, you will use also @RequestMapping @Controller public class MyController { // When HTTP GET, POST, PUT or OTHER request happens // to http://localhost:8080/greeting // invoke this method @RequestMapping("/greeting") @ResponseBody // By default the method will return the file name of the view! public String greeting() { return "view"; } }

Slide 116

Slide 116 text

src/main/resources/templates/view.html My View

This is my View

Slide 117

Slide 117 text

Result

Slide 118

Slide 118 text

ModelMap – Passing Data to View • @Controller classes are responsible for selecting a view to be rendered • In addition to this, class is responsible for preparing a model map with data • The model map allows abstraction of the view technology • It is transformed to a Thymeleaf Context Object

Slide 119

Slide 119 text

Example 1 @Controller public class MyWebController { @RequestMapping("view") public ModelAndView getView() { // Holder for both Model and View in the web MVC framework ModelAndView mav = new ModelAndView(); // return view.html mav.setViewName("view"); // add object with name = jack value mav.addObject("name", "Jack"); return mav; } }

Slide 120

Slide 120 text

Example 2 @Controller public class MyWebController { @RequestMapping("view") public String getView(Model model) { model.addAttribute("name", "Jack"); return "view"; } }

Slide 121

Slide 121 text

Argument Resolving in Spring • When HTTP Request comes, @RequestMapping annotation is looked up • Finds a match, calls corresponding method • Once the method is figured out, it will read the method signature • What arguments should I pass to the method so I can invoke it? • So when you have Model model in arguments, Spring will automatically create a object for you!

Slide 122

Slide 122 text

View My View

Slide 123

Slide 123 text

Model Attributes • Model attributes, or Thymeleaf context variables, can be accessed ${attributename} • This is a Spring EL expression

Slide 124

Slide 124 text

Example @Controller public class MyWebController { @RequestMapping("view") public String getView(Model model) { List points = Arrays.asList(new Point(3,3), new Point(9,8)); model.addAttribute("points", points); return "view"; } }

Slide 125

Slide 125 text

View

Slide 126

Slide 126 text

Sidenote: Lombok

Slide 127

Slide 127 text

Lombok: Pojo made simple org.projectlombok lombok 1.18.24 provided

Slide 128

Slide 128 text

Lombok public class User { private String name; private String email; public User() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", email='" + email + '\'' + '}'; } } @Getter @Setter @ToString @NoArgsConstructor public class User { private String name; private String email; }

Slide 129

Slide 129 text

Java 14 Record: only getters record User(String name, String email) {} var jack = new User("jack", "jack@gmail.com"); out.println(jack.name()); out.println(jack.email()); out.println(jack.toString()); out.println(jack.equals(jack));

Slide 130

Slide 130 text

Forms

Slide 131

Slide 131 text

Pojo (uses Lombok) @Getter @Setter @ToString @NoArgsConstructor public class User { private String name; private String email; }

Slide 132

Slide 132 text

Mappings @GetMapping("/register") public String showForm(Model model) { User user = new User(); model.addAttribute("user", user); return "register"; } @PostMapping("/register") public String submitForm(@ModelAttribute("user") User user) { return "success"; }

Slide 133

Slide 133 text

register.html User Registration

User Registration

Full name:

E-mail:

Register

Slide 134

Slide 134 text

success.html Registration Success

Registration Succeeded!

Full name:

E-mail:

Slide 135

Slide 135 text

Validation org.springframework.boot spring-boot-starter-validation

Slide 136

Slide 136 text

Pojo @Getter @Setter @ToString @NoArgsConstructor public class User { @NotEmpty(message = "Please enter your name.") private String name; @NotEmpty(message = "Please enter your email.") @Email(message = "Please correct your email.") private String email; }

Slide 137

Slide 137 text

Validation @PostMapping("/register") public String submitForm(@Valid @ModelAttribute("user") User user, BindingResult result) { return result.hasErrors() ? "error" : "success"; }

Slide 138

Slide 138 text

Sessions

Slide 139

Slide 139 text

Sessions • The HttpSession object represents a user session • A user session contains information about the user across multiple HTTP requests. • To do this in Java EE Servlets and in Spring you can use HttpServletRequest • HttpSession session = request.getSession(); • session.setAttribute("userName", "theUserName"); • String userName = (String) session.getAttribute("userName");

Slide 140

Slide 140 text

@Controller public class WebController { @Autowired private HttpServletRequest request; @RequestMapping("session") public ModelAndView showView() { // Get or create the session HttpSession session = request.getSession(true); // Get integer value from the session Integer integerValue = (Integer) session.getAttribute("value"); // If not found, set it to 0 if(integerValue == null) { integerValue = 0; } integerValue++; // Add it to session session.setAttribute("value", integerValue); ModelAndView mav = new ModelAndView(); mav.setViewName("view"); mav.addObject("integerValue", integerValue); return mav; } } Inject the HttpServletRequest

Slide 141

Slide 141 text

@Controller public class WebController { @RequestMapping("session") public ModelAndView showView(HttpServletRequest request) { ... return mav; } } Spring will inject it for you if in argument

Slide 142

Slide 142 text

@Controller public class WebController { @RequestMapping("session") public ModelAndView showView(HttpSession request) { ... return mav; } } Or if you prefer to have the session only!

Slide 143

Slide 143 text

@SessionAttributes • Designate which model attributes should be stored in the session • So before rendering stuff to View, put the stuff also into session

Slide 144

Slide 144 text

Form Form

Slide 145

Slide 145 text

@SessionAttributes @Controller @SessionAttributes("name") public class WebController { @GetMapping("/myform") public ModelAndView singleFieldPage() { return new ModelAndView("myform"); } @GetMapping("remember") public ModelAndView receiveName(@RequestParam("name") String name) { ModelAndView mav = new ModelAndView(); mav.setViewName("myform"); // This will go to session! mav.addObject("name", name); return mav; } } This will typically list the names of model attributes which should be transparently stored in the session

Slide 146

Slide 146 text

@SessionScope @Component @Scope("session") public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } This Bean is NOT singleton or protytype. It's scope is Session!

Slide 147

Slide 147 text

Injecting to @Controller @Controller public class WebController { @Autowired Customer customer; } This will fail! Problem: Controller is singleton, Customer session. This is injected only once!

Slide 148

Slide 148 text

Basic Example with prototype @Controller public class WebController { @Autowired Customer customer; @RequestMapping("showcustomer") @ResponseBody public String showcustomer() { return customer.toString(); } } @Component @Scope("prototype") public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Several instances can be created from the class Always the same instance because the customer is injected only once

Slide 149

Slide 149 text

Basic Example @Controller @Scope("prototype") public class WebController { @Autowired Customer customer; @RequestMapping("showcustomer") @ResponseBody public String showcustomer() { return customer.toString(); } } @Component @Scope("prototype") public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Several instances can be created from the class Now on each request, different object For each request, create new controller

Slide 150

Slide 150 text

Basic Example @Controller public class WebController { @Autowired WebApplicationContext context; @RequestMapping("showcustomer") @ResponseBody public String showcustomer() { return context.getBean("this-is-my- customer").toString(); } @Component("this-is-my-customer") @Scope("prototype") public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Get the bean on each http request Context can be used to look up beans in runtime

Slide 151

Slide 151 text

Solution 1 for Session Scope @Controller public class WebController { @Autowired WebApplicationContext context; @RequestMapping("showcustomer") @ResponseBody public String showcustomer() { return context.getBean("this-is-my- customer").toString(); } @Component("this-is-my-customer") @Scope("session") public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Now this works! We will get a different customer object for each browser session!

Slide 152

Slide 152 text

Solution 2 for Session Scope @Controller public class WebController { @Autowired Customer customer; @RequestMapping("showcustomer") @ResponseBody public String showcustomer() { return customer.toString(); } } @Component @Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) public class Customer { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Let's add proxy here This will use a proxy. Proxy will then fetch the real Customer object.

Slide 153

Slide 153 text

Error Messages

Slide 154

Slide 154 text

Static Custom Error Message • Add a file into /error folder • Can be static or built using templates src/ +- main/ +- java/ | + +- resources/ +- public/ +- error/ | +- 404.html

Slide 155

Slide 155 text

REST and RESTful

Slide 156

Slide 156 text

Rest • Representational State Transfer was introduced and defined in 2000 by Roy Fielding in his theses: • http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_st yle.htm • Way of providing interoperability between computer systems • Does not restrict communication to a particular protocol • Http Web Service API that follows REST principals are called RESTful APIs

Slide 157

Slide 157 text

What makes Rest a Rest? 1. Client – Server 2. Stateless 3. Cacheable 4. Layered system 5. Code on demand (optional) 6. Uniform Interface 1. Identification of resources 2. Manipulation of resources through representations 3. Self-descriptive messages 4. Hypermedia as the engine of application state

Slide 158

Slide 158 text

1. Client Server • Separate UI from the data improves portability of the UI • Improve scalability by simplifying server components • Both components, client and server, can evolve independently

Slide 159

Slide 159 text

2. Stateless • Client - server communication must be stateless in nature • No session data stored on the server • Each request from client to server must contain all the information necessary to understand the request

Slide 160

Slide 160 text

3. Cache • Responses should define themselves as cacheable or not • Eliminate client-server interactions • In Restful, you can do this by using HTTP Headers

Slide 161

Slide 161 text

Client Server Cache Client Cache Request contains all information Client may store the response to a cache and reuse it

Slide 162

Slide 162 text

4. Layered System • Rest can be built using multiple architecture layers • Restrict knowledge of the system to one layer • Client -> Cache -> Middleware -> Server -> DB • For example the middleware can be a cache • Client cannot tell if it's connected to end server or middleware

Slide 163

Slide 163 text

5. Code on Demand (optional) • Client can download JavaScript, Flash or Java Applet from server • Server can decide how things are done

Slide 164

Slide 164 text

6. Uniform Interface • Uniform Interface has four constraints 1. Identication of resources • Every resource has unique URI 2. Manipulation of resources through representations • Representation can be in various formats and is de-coupled from the identification 3. Self-descriptive messages • Each message has enough information to describe how to process the message, for example by using content-type 4. Hypermedia as the engine of application state (HATEOAS) • Server respondes with a set of links what other actions are available

Slide 165

Slide 165 text

6.1 Identification of Resources • Every resource has it's own unique URI • http://company.com/employees/ • URI is an identifier • Result is the resource • Notice that resource is not 'storage object', it's entity • Resources are just some item that can be accessed

Slide 166

Slide 166 text

6.2 Representation • Identified resource can be returned in various formats, like HTML, XML, JSON, SVG, PNG • RESTful apps can send accept header where it defines what kind of data it can handle • Server can send Content-type where it defines the type of the resource • De-coupling the representation of the resource from the URI is key aspect of REST

Slide 167

Slide 167 text

6.3 Self-descriptive Messages • Each client and server response is a message • Message should be self-descriptive • Message contains the body and metadata • In Restful, you use HTTP GET, PUT and HTTP Headers for this

Slide 168

Slide 168 text

6.4 HATEOAS • In perfect you don't need documentation for the API • Include links to the responses • What other • REST client needs no prior information about the service • REST client enters app by simplex fixed URI • All future actions may be discovered within the response • Nearly ALL popular WEB APIs violate HATEOAS

Slide 169

Slide 169 text

HATEOAS (wikipedia) HTTP/1.1 200 OK Content-Type: application/xml Content-Length: ... 12345 100.00

Slide 170

Slide 170 text

Starbucks: Request HTTP POST /order latte

Slide 171

Slide 171 text

Starbucks: Response 201 CREATED Location: http://starbucks.com/order/1234 latte 3.00

Slide 172

Slide 172 text

{ "_embedded" : { "customerList" : [ { "id" : 1, "name" : "A", "_links" : { "self" : { "href" : "http://localhost:8080/customers/1" } } }, { "id" : 2, "name" : "A", "_links" : { "self" : { "href" : "http://localhost:8080customers/2" } } } ] }, "_links" : { "self" : { "href" : "http://localhost:8080/customers" } } } Spring HATEAOS uses HAL format. _embedded means that all the resources are embedded in the response (instead of URIs) Links are given with _links and usually have self relationship. You can define more links like next and prev relationships

Slide 173

Slide 173 text

RESTful

Slide 174

Slide 174 text

Rest and Web Services • Web Service API that follows REST principals are called RESTful APIs • HTTP based RESTful APIs are defined with following aspects • base url • standard http methods

Slide 175

Slide 175 text

Example (wikipedia)

Slide 176

Slide 176 text

Example: REST + XML

Slide 177

Slide 177 text

Example: REST + XML

Slide 178

Slide 178 text

Example: REST + JSON

Slide 179

Slide 179 text

RESTful Design • Identify entities / resources • Create URI to each resource • Categorize if resources are needed to view and/or update • All HTTP Get should be side-effect free • Put hyperlinks to resource representation to enable clients to drill down for more information • Specify the format of response data • Create documentation how to use the service

Slide 180

Slide 180 text

Testing REST • When testing HTTP GET you can just use browser • For more complicated services, you can use tools called cURL: http://curl.haxx.se/ • Via command line you can create HTTP GET, POST, DELETE, PUT commands: • curl GET http://localhost:8080/rest/cars • curl POST –d "{brand: 'skoda'}" http://localhost:8080/rest/cars • curl DELETE http://localhost:8080/rest/cars/0 • Or if you prefer GUI, use Postman Chrome - extension

Slide 181

Slide 181 text

Spring REST

Slide 182

Slide 182 text

Building REST with Spring • You can use @Controller, @ResponseBody and @RequestMapping • Also @RestController available, which basically means @Controller + @ResponseBody @RestController public class MyRestController { @RequestMapping("locations") public String getLocations() { return "[{id: 1, lat: 60, lon: 60}, {id: 1, lat: 60, lon: 60}]"; } }

Slide 183

Slide 183 text

Testing using CURL > GET /locations HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > < HTTP/1.1 200 < Content-Type: text/plain;charset=UTF-8 < Content-Length: 56 < Date: Tue, 11 Apr 2017 08:19:21 GMT < * Curl_http_done: called premature == 0 * Connection #0 to host localhost left intact [{id: 1, lat: 60, lon: 60}, {id: 1, lat: 60, lon: 60}]

Slide 184

Slide 184 text

Java EE JSON Parsing import javax.json.Json; import javax.json.JsonObject; @RestController public class MyRestController { @RequestMapping("location") public JsonObject getLocation() { JsonObject result = Json.createObjectBuilder() .add("id", 1) .add("latitude", 60) .add("longitude", 6) .build(); return result } } org.glassfish javax.json 1.0.4

Slide 185

Slide 185 text

POJO -> JSON Mapping • spring-boot-starter-web functions like a set of basic dependencies needed to develop web-applications with spring. These basic dependencies are: • jackson-databind • hibernate-validator • spring-core • spring-web • spring-webmvc • spring-boot-starter • spring-boot-starter-tomcat Jackson provides automatic mapping between pojo to json!

Slide 186

Slide 186 text

Example public class Location { private double latitude; private double longitude; ... } @RestController public class MyRestController { @RequestMapping("location") public Location getLocation() { return new Location(60,60); } } Automatic JSON mapping

Slide 187

Slide 187 text

Testing with Curl > GET /location HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > < HTTP/1.1 200 < Content-Type: application/json;charset=UTF-8 < Transfer-Encoding: chunked < Date: Tue, 11 Apr 2017 08:33:36 GMT < {"latitude":60.0,"longitude":60.0}

Slide 188

Slide 188 text

POJO -> XML • If you have jackson- dataformat-xml in pom.xml it will be used to render to xml • If not, it uses JAXB that requires that class is annotated with @XmlRootElement @RestController public class MyRestController { @RequestMapping(value="location", produces = MediaType.APPLICATION_XML_VALUE) public Location getLocation() { return new Location(60,60); } } com.fasterxml.jackson.dataformat jackson-dataformat-xml

Slide 189

Slide 189 text

Example of XML @RestController public class MyRestController { @RequestMapping(value="location", produces = MediaType.APPLICATION_XML_VALUE) public Location getLocation() { return new Location(60,60); } } com.fasterxml.jackson.dataformat jackson-dataformat-xml

Slide 190

Slide 190 text

HttpMessageConverter • Internally Spring uses component called HttpMessageConverter to convert Http request to an object and back • Set of default converters are automatically configured for you

Slide 191

Slide 191 text

HttpMessageConverter @Configuration public class MyConfiguration { @Bean public HttpMessageConverter customConverter() { return new FastJsonHttpMessageConverter(); } }

Slide 192

Slide 192 text

@RestController public class ExampleController { List locations; @PostConstruct public void init() { locations = new ArrayList<>(); locations.add(new Location()); } @PostMapping("/locations") public void saveLocation(@RequestBody Location c) { locations.add(c); } @GetMapping("/locations") public Iterable fetchLocation() { return locations; } @GetMapping("/locations/{userId}") public Location fetchLocation(@PathVariable int userId) { for(Location c : locations) { if(c.getId() == userId) { return c; } } return null; } } RestController is a singleton, this is not thread safe

Slide 193

Slide 193 text

Let's clean this up a bit @RestController public class MyRestController { @Autowired LocationRepository locationRepository; @PostMapping("/locations") public void saveLocation(@RequestBody Location location, UriComponentsBuilder b) { locationRepository.saveEntity(location); } @GetMapping("/locations") public Iterable fetchLocation() { return locationRepository.findAll(); } @GetMapping("/locations/{userId}") public Location fetchLocation(@PathVariable int locationId) { return locationRepository.findOne(userId); } } Let's separate the "database" into separate service

Slide 194

Slide 194 text

Let's use interfaces: MyRepository public interface MyRepository { public T saveEntity(T entity); public void delete(ID id) throws IllegalArgumentException; public Iterable findAll(); public Optional findOne(ID id); } This will work as a base interface. Notice that we can reuse this to work with different entities

Slide 195

Slide 195 text

LocationRepository public interface LocationRepository extends MyRepository { } This will just extend the MyRepository but in addition it makes a statement that the entities must be Location and IDs are integers!

Slide 196

Slide 196 text

Implementation of LocationRepository @Service public class LocationRepositoryImpl implements LocationRepository { List locations; @PostConstruct public synchronized void init() { locations = new ArrayList<>(); locations.add(new Location()); } @Override public Location saveEntity(Location location) { locations.add(location); return location; } @Override public Iterable findAll() { return this.locations; } ... Let's implement the LocationRepositories methods

Slide 197

Slide 197 text

Best Practices

Slide 198

Slide 198 text

URLs and Actions • Identify resources • Use nouns, like ticket, user or group • Identify what actions can user apply to them • GET /employees/ • GET /employees/1 • POST /employees • PUT /employees/1 • DELETE /employees/1 • Use plurals in the endpoint name! • So do not: employee/1 vs employees/ • person / people vs goose / geese

Slide 199

Slide 199 text

Relations • Group logically relations • GET /threads/1/messages • GET /threads/1/messages/1 • POST /threads/1/messages

Slide 200

Slide 200 text

Update and Delete • When creating, updating return the updated resource to the client • In case of HTTP POST, return 201 and include Location Header that points to the URL of the resource • In case of HTTP DELETE • 204: no response body • 200: response body with the deleted resource

Slide 201

Slide 201 text

ResponseEntity // curl -v -H "Content-type: application/json" -X // POST -d '{"latitude": 80, "longitude": 80}' http://localhost:8080/locations @PostMapping("/locations") public ResponseEntity saveLocation(@RequestBody Location c, UriComponentsBuilder b) { locations.add(c); UriComponents uriComponents = b.path("/locations/{id}").buildAndExpand(c.getId()); HttpHeaders headers = new HttpHeaders(); headers.setLocation(uriComponents.toUri()); return new ResponseEntity(headers, HttpStatus.CREATED); } To build the location uri. One of the biggest advantages of UriComponentsBuild er is that we can inject it right into a controller method Creates a response with void body, location header and status 201

Slide 202

Slide 202 text

Testing curl -v -H "Content-type: application/json" -X POST -d '{"latitude": 80, "longitude": 80}' http://localhost:8080/locations > POST /locations HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > Content-type: application/json > Content-Length: 33 > < HTTP/1.1 201 < Location: http://localhost:8080/locations/7069 < Content-Length: 0 < Date: Tue, 11 Apr 2017 09:03:59 GMT <

Slide 203

Slide 203 text

Status Codes • 200 OK (HTTP GET) • 201 Created (HTTP POST) • 204 No Content (For example Delete) • 400 Bad Request • 401 Unauthorized • 403 Forbidden • 404 Not Found • 405 Method not found (when method is not allowed for authenticated user) • 409 Conflict • 410 Gone (older apis) • 429 Too many requests

Slide 204

Slide 204 text

Errors • Return sensible HTTP status codes • 400 -> client issues • 500 -> server issues • Also send JSON explaining the error • { "code" : 1234, "message" : "Something bad happened :(", "description" : "More details about the error here" }

Slide 205

Slide 205 text

Case of Delete and Exceptions: curl -v -X DELETE http://localhost:8080/locations/7219 > DELETE /locations/7219 HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > < HTTP/1.1 404 < Content-Type: application/json;charset=UTF-8 < Transfer-Encoding: chunked < Date: Tue, 11 Apr 2017 11:35:28 GMT < {"errorMsg":"Could not found location with id 7219"}

Slide 206

Slide 206 text

Controller // curl -v -X DELETE http://localhost:8080/locations/7219 @DeleteMapping("/locations/{userId}") public ResponseEntity deleteLocation(@PathVariable int locationId) { locationRepository.delete(locationId); return new ResponseEntity(HttpStatus.NO_CONTENT); } This will throw an exception if userId is not found

Slide 207

Slide 207 text

@Override public synchronized void delete(Integer id) throws IllegalArgumentException { Location toBeRemoved = null; for(Location loc : this.locations) { if (loc.getId() == id) { toBeRemoved = loc; } } if(toBeRemoved != null) { this.locations.remove(toBeRemoved); } else { throw new CannotFindLocationException(id); } } My own simple exception class

Slide 208

Slide 208 text

public class CannotFindLocationException extends IllegalArgumentException { private int locationId; public CannotFindLocationException(int id) { locationId = id; } public int getLocationId() { return locationId; } }

Slide 209

Slide 209 text

@ControllerAdvice @ControllerAdvice public class RestResponseEntityExceptionHandler { @ExceptionHandler(CannotFindLocationException.class) public ResponseEntity handleConflict(CannotFindLocationException ex) { ErrorInfo e = new ErrorInfo("Could not found location with id " + ex.getLocationId()); return new ResponseEntity(e, HttpStatus.NOT_FOUND); } } This method will catch if our own exception is thrown! End result is 404 NOT Found and ErrorInfo POJO in JSON

Slide 210

Slide 210 text

ErrorInfo public class ErrorInfo { private String errorMsg; public ErrorInfo() {} public ErrorInfo(String errorMsg) { this.errorMsg = errorMsg; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } }

Slide 211

Slide 211 text

Testing curl -v -X DELETE http://localhost:8080/locations/7219 > DELETE /locations/7219 HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.51.0 > Accept: */* > < HTTP/1.1 404 < Content-Type: application/json;charset=UTF-8 < Transfer-Encoding: chunked < Date: Tue, 11 Apr 2017 11:35:28 GMT < {"errorMsg":"Could not found location with id 7219"}

Slide 212

Slide 212 text

Pretty Print or Not? • If you don't have indentation and whitespaces it's hard to detect the structure of the response • Extra cost is data transfer, but it is really small cost if you use gzip

Slide 213

Slide 213 text

Enable Pretty Print and Gzip in Spring • In application.properties add • spring.jackson.serialization.INDENT_OUTPUT=true • And server compression • server.compression.enabled=true server.compression.mime- types=application/json,application/xml,text/html,text/xml,text/ plain

Slide 214

Slide 214 text

1000 Locations, Pretty Print Disabled, Gzip Disabled Size is 69.9 KB

Slide 215

Slide 215 text

Pretty Print Enabled – Gzip Disabled Size is 86.5 KB

Slide 216

Slide 216 text

Pretty Print Enabled - Gzip Enabled Size is 24.8 KB

Slide 217

Slide 217 text

Pretty Print Disabled - Gzip Enabled Size is 24.1 KB.. So we saved 0.7 KB...

Slide 218

Slide 218 text

Caching • HTTP Provides built-in caching framework • Can be done both in client or in server-side

Slide 219

Slide 219 text

Spring Boot Server Side Caching @SpringBootApplication @EnableCaching public class MyApplication { public static void main(String[] args) { SpringApplication.run(CustomerRestApplication.class, args); } } Inspects every bean for a presence of a @Cache annotation of public methods. Proxy is automatically created to intercept the method call and handle the caching behavior

Slide 220

Slide 220 text

Spring Boot Server Side Caching @Override @Cacheable(cacheNames="locations", sync=true) public synchronized Location findOne(Integer id) { simulateSlowService(); Location locationTobeFound = null; for(Location loc : this.locations) { if (loc.getId() == id) { locationTobeFound = loc; } } return locationTobeFound; } The result of this method is cached. When invocation comes for the second time, cache is used. In here findOne is assosiated with cache named "locations". The cache fetching is not synchronized by default, we can enable it.

Slide 221

Slide 221 text

Database Connections

Slide 222

Slide 222 text

Database Access • Spring has extensive support for different databases • For example, you can use low level JdbcTemplate class or you can use ORM mapping (Hibernate) • Spring Data provides you additional functionality where it creates Repository methods for you directly from interfaces • Spring has great support for embedded in-memory databases • Spring boot autoconfigures H2, HSQL and Derby. You don't need to provide any connection urls, just dependency is enough • In real life, when using real db, you can set connection url's and other stuff in application.properties

Slide 223

Slide 223 text

Spring JDBC Action Spring You Define connection parameters. X Open the connection. X Specify the SQL statement. X Declare parameters and provide parameter values X Prepare and execute the statement. X Set up the loop to iterate through the results (if any). X Do the work for each iteration. X Process any exception. X Handle transactions. X Close the connection, statement and resultset. X

Slide 224

Slide 224 text

pom.xml org.apache.derby derby

Slide 225

Slide 225 text

H2 com.h2database h2 org.springframework.boot spring-boot-starter-data-jpa

Slide 226

Slide 226 text

public class CustomerRestApplication implements CommandLineRunner { @Autowired JdbcTemplate jdbcTemplate; public static void main(String[] args) { SpringApplication.run(CustomerRestApplication.class, args); } @Override public void run(String... strings) throws Exception { jdbcTemplate.execute("CREATE TABLE ... "); ... } }

Slide 227

Slide 227 text

jdbcTemplate.execute("CREATE TABLE locations(id int, lat double, lon double)"); jdbcTemplate.update("INSERT INTO locations values(0, 60.0, 60.0)"); List locations = jdbcTemplate.query("SELECT * FROM locations", (result, rowNum) -> { Location loc = new Location(result.getString("id"), result.getString("lat"), result.getString("lon")); return loc; }); locations.forEach(System.out::println); Functional Interface RowMapper with method T mapRow(ResultSet rs, int rowNum) Java 8 Method Reference

Slide 228

Slide 228 text

Using Real Database (Not in-memory) • Derby, or Java DB, is installed in every JDK • Start Network Server • Windows • java -jar "%DERBY_HOME%\lib\derbyrun.jar" server start • Mac • java -jar $DERBY_HOME/lib/derbyrun.jar server start • Notice that the directory where you start your server is important. • All the databases are saved to the dir where you started the network server • Once your network server runs, open another terminal window and start ij and connect & create database • CONNECT 'jdbc:derby://localhost:1527/mydb;create=true';

Slide 229

Slide 229 text

Starting Derby as a Service

Slide 230

Slide 230 text

Creating new DB

Slide 231

Slide 231 text

pom.xml org.apache.derby derby org.apache.derby derbyclient 10.13.1.1 Apache Derby Database and Embedded Driver Only client driver. Database is installed via JDK and running in network mode

Slide 232

Slide 232 text

src/main/resources/application.properties spring.datasource.url = jdbc:derby://localhost:1527/mydb;create=true spring.datasource.driver-class-name = org.apache.derby.jdbc.ClientDriver

Slide 233

Slide 233 text

Spring JPA

Slide 234

Slide 234 text

JPA • Java Persistence API (JPA) is an specification that describes management of relational data in apps using Java • Basic idea is simple, save objects to relational database • JPA is a specification, hibernate is implementation of this specification. • By default, Spring uses hibernate • When using JPA you will also have to declare the driver for the database • Spring Data JPA enhances JPA

Slide 235

Slide 235 text

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

Slide 236

Slide 236 text

Hibernate • Hibernate ORM is an object-relational mapping framework for Java • Mapping Java classess to databatase tables • Mapping is done by using • 1) XML configuration or • 2) Java annotations • Classes must have no-argument constructor • Collections are stored in Set or List, also generics are supported

Slide 237

Slide 237 text

Example of Java Annotations import javax.persistence.*; @Entity @Table(name = "EMPLOYEE") public class Employee { @Id @GeneratedValue @Column(name = "id") private int id; @Column(name = "first_name") private String firstName; @Column(name = "last_name") private String lastName; @Column(name = "salary") private int salary; create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR(20) default NULL, last_name VARCHAR(20) default NULL, salary INT default NULL, PRIMARY KEY (id) );

Slide 238

Slide 238 text

Annotations • Notice that the package here what we use is standard Java EE API • javax.persistence.*; • @Entitity marks the class as entity bean, it must have a no-argument constructor! • @Table annotation you can set name, catalogue, schema, constraints • @Id and @GeneratedValue • Every entity bean must have primary key! Use @Id • You will have different primary key strategies, by using @GeneratedValue, let hibernate decide what is the best way for the primary key • @Column annotation specifies the details of the column, like name, length, nullable etc. • Only @Id and @Entity here are mandatory!

Slide 239

Slide 239 text

Pure JPA on Java SE public class CreateEmployee { public static void main( String[ ] args ) { EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" ); EntityManager entitymanager = emfactory.createEntityManager( ); entitymanager.getTransaction( ).begin( ); Employee employee = new Employee( ); employee.setEid( 1201 ); employee.setEname( "Gopal" ); employee.setSalary( 40000 ); employee.setDeg( "Technical Manager" ); entitymanager.persist( employee ); entitymanager.getTransaction( ).commit( ); entitymanager.close( ); emfactory.close( ); } } XML file persistence.xml holds persistence units that has information about which DB to use etc Transaction management is mandatory Persists the pojo to the db defined in persistence.xml

Slide 240

Slide 240 text

Spring JPA Approach – Inject EntityManager @SpringBootApplication public class CustomerRestApplication implements CommandLineRunner { @Autowired EntityManager entitymanager; public static void main(String[] args) { SpringApplication.run(CustomerRestApplication.class, args); } @Override @Transactional public void run(String... strings) throws Exception { entitymanager.persist( new Customer("Jack") ); } } Inject the entity manager Let Spring handle the transaction

Slide 241

Slide 241 text

Find, delete • Find • Employee employee = entitymanager.find( Employee.class, 1201 ); • Delete • entitymanager.remove( employee );

Slide 242

Slide 242 text

Hibernate Query Language • Load complete set of resources • List results = entitymanager.createQuery("FROM Employee").getResultList(); • SELECT • List results = entitymanager.createQuery("SELECT firstName FROM Employee").getResultList(); • WHERE • List results = entitymanager.createQuery("FROM Employee WHERE ID = 10").getResultList(); • You will get a warning: [unchecked] unchecked conversion because hibernate is not type safe by design. Solution: • @SuppressWarnings("unchecked")

Slide 243

Slide 243 text

src/main/resources/application.properties spring.datasource.url=jdbc:derby://localhost:1527/mydb;create=true spring.datasource.driver-class-name=org.apache.derby.jdbc.ClientDriver spring.jpa.hibernate.ddl-auto=none You can set spring.jpa.hibernate.ddl- auto explicitly and the standard Hibernate property values are none, validate, update, create, create- drop. Spring Boot chooses a default value for you based on whether it thinks your database is embedded (default create-drop) or not (default none). An embedded database is detected by looking at the Connection type: hsqldb, h2 and derby are embedded, the rest are not

Slide 244

Slide 244 text

Spring Data

Slide 245

Slide 245 text

Spring Data • Spring Data brings you repository abstraction that signicantly reduces the amount of boilerplate code when implementing data access layers • Spring data will create a class for you that handles all the saving and opening • You can define your own methods to a interface and Spring Data will create the method for you!

Slide 246

Slide 246 text

Dependency org.springframework.data spring-data-jpa

Slide 247

Slide 247 text

Extend CrudRepository import org.springframework.data.repository.CrudRepository; public interface LocationRepositorySpringData extends CrudRepository { } CrudRepository provides you basic save and restore methods

Slide 248

Slide 248 text

CrudRepository interface CrudRepository extends Repository { S save(S entity); T findOne(ID primaryKey); Iterable findAll(); Long count(); void delete(T entity); boolean exists(ID primaryKey); // ... }

Slide 249

Slide 249 text

@SpringBootApplication public class App implements CommandLineRunner { @Autowired LocationRepositorySpringData springDatarepository; public static void main(String[] args) { SpringApplication.run(App.class, args); } @Override public void run(String... strings) throws Exception { springDatarepository.save(new Location(...)); springDatarepository.save(new Location(...)); Iterable list = springDatarepository.findAll(); list.forEach(System.out::println); } } Spring Data will create a implementation for the interface and injects it here!

Slide 250

Slide 250 text

Controller and Spring Data @RestController public class MyRestControllerSpringData { @Autowired LocationRepositorySpringData locationRepository; // curl http://localhost:8080/springdata/locations/1234 @RequestMapping(value = "/springdata/locations/{userId}", method=RequestMethod.GET) public ResponseEntity fetchLocation(@PathVariable int locationId) { Location location = locatinoRepository.findOne(locationId); return new ResponseEntity(location, HttpStatus.OK); } }

Slide 251

Slide 251 text

Own Methods public interface LocationRepositorySpringData extends LocationRepository { List findByLatitude(double lat); } find..By, read...By, query...By, count..By, get...By methods are read by Spring Data and Spring Data will implement this method for you!

Slide 252

Slide 252 text

Usage // curl http://localhost:8080/springdata/locations?latitude=60 @RequestMapping(value = "/springdata/locations", method=RequestMethod.GET) public Iterable findByLatitude(@RequestParam("latitude") Optional optionalLatitude) { if(optionalLatitude.isPresent()) { double latitude = optionalLatitude.get(); return locationRepository.findByLatitude(latitude); } else { return locationRepository.findAll(); } }

Slide 253

Slide 253 text

NoSQL

Slide 254

Slide 254 text

Spring Data and NoSQL • Auto-configuration for • Redis, MongoDB, Neo4j, Elasticsearch, Solr Cassandra, Couchbase and LDAP • For example, for MongoDB, a spring-boot-starter-data-mongodb is available

Slide 255

Slide 255 text

Autoinjection @RestController public class MyRestController { @Autowired MongoDbFactory mongo; @RequestMapping(value="location") public void saveLocation() { DB db = mongo.getDb("mydb"); Location location = new Location(55,55); DBCollection collection = db.getCollection("locations"); BasicDBObject document = new BasicDBObject(); document.put("latitude", location.getLatitude()); document.put("longitude", location.getLongitude()); collection.insert(document); } }

Slide 256

Slide 256 text

HATEOAS

Slide 257

Slide 257 text

HATEOAS • Hypermedia As The State Of Application State • Client does not need prior knowledge of how to interact with the server • The server provides links to the client • Spring HATEOAS tries to address link creation and representation assembly

Slide 258

Slide 258 text

Extend from ResourceSupport @Entity public class Location extends ResourceSupport { @Id @GeneratedValue private long myId; private long latitude; private long longitude; ... Notice that ResourceSupport has already getId..

Slide 259

Slide 259 text

Adding a Link Location location = new Location(1, 60, 60); location.add(new Link("http://localhost:8080/locations/1"); { "id" : 1, "latitude" : 60, "longitude": 60, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } } Rather fragile way of creating a link

Slide 260

Slide 260 text

Adding a Link Location location = new Location(1, 60, 60); Link link = ControllerLinkBuilder.linkTo(LocationController.class).withRel("something"); location.add(link); { "id" : 1, "latitude" : 60, "longitude": 60, "_links" : { "something" : { "href" : "http://localhost:8080/locations/" } } } Base url of the @Controller with rel "something"

Slide 261

Slide 261 text

Adding a Link Location location = new Location(1, 60, 60); Link link = ControllerLinkBuilder.linkTo(LocationController.class).slash(location.getId()).withSelfRel(); location.add(link); { "id" : 1, "latitude" : 60, "longitude": 60, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } } Base url / id and rel is self

Slide 262

Slide 262 text

Extend from ResourceSupport @Entity public class Location extends ResourceSupport { @Id @GeneratedValue private long myId; private long latitude; private long longitude; ... What if this class already extends something?

Slide 263

Slide 263 text

Wrapper Class public class LocationDTO extends ResourceSupport { private Location location; public LocationDTO(Location location) { this.location = location; } public Location getLocation() { return this.location; } }

Slide 264

Slide 264 text

Usage @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity fetchLocation(@PathVariable long userId) { Location location = locationRepository.findOne(userId); Link link = ControllerLinkBuilder.linkTo(MyRestControllerSpringData.class).slash(location.getId()).withSelfRel(); LocationDTO locationDTO = new LocationDTO(location); locationDTO.add(link); return new ResponseEntity(locationDTO, HttpStatus.OK); } Let's return LocationDTO instead of Location

Slide 265

Slide 265 text

Result { "location" : { "id" : 1, "latitude" : 60 ... }, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } } Usually we want these to be on top level

Slide 266

Slide 266 text

Wrapper Class public class LocationDTO extends ResourceSupport { @JsonUnWrapped private Location location; public LocationDTO(Location location) { this.location = location; } public Location getLocation() { return this.location; } }

Slide 267

Slide 267 text

Result { "id" : 1, "latitude" : 60, "longitude" : 60, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } }

Slide 268

Slide 268 text

Wrapper Mapping @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity fetchLocation(@PathVariable long userId) { Location location = locationRepository.findOne(userId); Link link = ControllerLinkBuilder.linkTo(MyRestControllerSpringData.class).slash(location.getId()).withSelfRel(); LocationDTO locationDTO = new LocationDTO(location); locationDTO.add(link); return new ResponseEntity(locationDTO, HttpStatus.OK); } The manual wrapping between DTO and Entity can be a pain. Spring provides you the wrapper: Resources

Slide 269

Slide 269 text

Resource @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity> fetchLocation(@PathVariable long userId) { Location location = locationRepository.findOne(userId); Link link = ControllerLinkBuilder.linkTo(MyRestControllerSpringData.class).slash(location.getId()).withSelfRel(); Resource locationDTO = new Resource<>(location); locationDTO.add(link); return new ResponseEntity>(locationDTO, HttpStatus.OK); }

Slide 270

Slide 270 text

Own method for the Conversion @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity> fetchLocation(@PathVariable long userId) { Location location = locationRepository.findOne(userId); return new ResponseEntity>(locationToResource(location), HttpStatus.OK); } private Resource locationToResource(Location location) { Link selfLink = ControllerLinkBuilder.linkTo(MyRestControllerSpringData.class).slash(location.getId()).withSelfRel(); return new Resource<>(location, selfLink); }

Slide 271

Slide 271 text

Swagger / OpenAPI Spec

Slide 272

Slide 272 text

OpenAPI Specification • Readable interface files for describing RESTFul • Previously part of the Swagger framework

Slide 273

Slide 273 text

Dependency org.springdoc springdoc-openapi-ui 1.6.xx

Slide 274

Slide 274 text

OpenAPI Descriptions • Automatically descriptions are available • http://localhost:8080/v3/api-docs/ • You may change this from application.properties • springdoc.api-docs.path=/api-docs • And now they are available • http://localhost:8080/api-docs/ • To see HTML doc • http://localhost:8080/swagger-ui.html

Slide 275

Slide 275 text

Add Information to Doc @Operation(summary = "Get a location by its id") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Found the location", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = Location.class)) }), @ApiResponse(responseCode = "404", description = "Location not found", content = @Content) }) @GetMapping("/api/locations/{locationId}") public ResponseEntity fetchLocation(@PathVariable long locationId) throws CannotFindLocationException { var location = database.findById(locationId); if(location.isEmpty()) throw new CannotFindLocationException(locationId); return new ResponseEntity(location.get(), HttpStatus.OK); }

Slide 276

Slide 276 text

War Creation

Slide 277

Slide 277 text

Jar Creation • By default Spring Boot will create runnable jar file • So your jar will contain Tomcat libraries • By giving command you will get jar package to target/ dir: • mvn clean package

Slide 278

Slide 278 text

jar contains tomcat

Slide 279

Slide 279 text

jar to war • Add / or modify pom.xml • war • Give command again • mvn clean package • And now in target/ dir you should a war • The dir structure of war differs from jar • war contains WEB-INF/classes • But it still contains tomcat libraries!

Slide 280

Slide 280 text

Jar + War in same • You can move the tomcat libraries to different folder • Works both in jar and in war! • Add dependency org.springframework.boot spring-boot-starter-tomcat provided • This will include the libraries but put them in lib-provided/

Slide 281

Slide 281 text

lib-provided

Slide 282

Slide 282 text

Setting up as a Servlet @SpringBootApplication public class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

Slide 283

Slide 283 text

Deploy to Server

Slide 284

Slide 284 text

Testing RESTful API

Slide 285

Slide 285 text

Test Scope Dependencies • The spring-boot-starter-test “Starter” (in the test scope) contains the following provided libraries: • JUnit 5: The de-facto standard for unit testing Java applications. • Spring Test & Spring Boot Test: Utilities and integration test support for Spring Boot applications. • AssertJ: A fluent assertion library. • Hamcrest: A library of matcher objects (also known as constraints or predicates). • Mockito: A Java mocking framework. • JSONassert: An assertion library for JSON. • JsonPath: XPath for JSON.

Slide 286

Slide 286 text

Different Testing Objects • MockMvc • Interact with mocked servlet environment, no real http communication • WebTestClient • Originally testing tool for spring webflux endpoint, but can be used also for running servlet. • TestRestTemplate • Uses real http communication. Will be depricated.

Slide 287

Slide 287 text

Differences

Slide 288

Slide 288 text

src/test/java/.../AppTests.java @SpringBootTest class AppTests { .. } Loads complete Spring application context (primary job is to manage beans). It searches for @SpringBootConfiguration (which is under @SpringBootApplication) and starts the app context in very similar way than production environment. We can now do integration tests!

Slide 289

Slide 289 text

src/test/java/.../AppTests.java @SpringBootTest @AutoConfigureMockMvc class AppTests { @Autowired private MockMvc mockMvc; } To test Spring MVC, we wil use MockMvc object. This is autoconfigured so that it creates a mock web environment without opening a full server!

Slide 290

Slide 290 text

@SpringBootTest @AutoConfigureMockMvc class RestfulAndTestsApplicationTests { @Autowired private MockMvc mockMvc; @Autowired CustomerRepository repository; @Autowired private ObjectMapper objectMapper; @Test public void addWorks() throws Exception { // Create dummy object var customer = new Customer("Jack"); // Transform it to String var customerInString = objectMapper.writeValueAsString(customer); // Create http request RequestBuilder postRequest = MockMvcRequestBuilders .post("/customers") .content(customerInString) .contentType(MediaType.APPLICATION_JSON); // Perform the request mockMvc.perform(postRequest) .andDo(print()) // log information .andExpect(status().isCreated()); // Except 201 // Did it update the database? Optional addedCustomer = repository.findById(1); assertTrue(addedCustomer.isPresent() , "not present"); assertTrue(addedCustomer.get().getId() == 1, "wrong id"); assertTrue(addedCustomer.get().getName().equals("Jack"), "wrong name"); }

Slide 291

Slide 291 text

Spring Security

Slide 292

Slide 292 text

Why Spring Security • Login and logout functionality • SSO / LDAP / OAuth, Tokens/JWT • Allow/bock access to URSL to logged in users • Allow/block access to URLs to logged in users AND with certain roles • Handels common vulnerabilities by default • Session fixation • Clickjacking • Click site request forgery • Method level security

Slide 293

Slide 293 text

Key Concepts • Authentication (who are you?) • Process that verifies that someone or something is who they say they are • On arrival, you knock on the door, and your friend opens it. She recognizes you (authentication) and greets you. • User name / password (knowledge based authentication) • Authorization / Access Control (Can this user do this?) • Process that determines a user or service's level of access • For example, you may enter the kitchen area, but you cannot go into her private office. In other words, you have the authorization to enter the kitchen, but access to her private office is prohibited.

Slide 294

Slide 294 text

Key Concepts • Principal • currently logged in user • App remembers the principal for the user so that name/password is not asked every page load • Granted Authority • What the user can do • List of authorities • Role • Group of authorities • admin role has authorities A, B, C,D • user role has authorities A, B

Slide 295

Slide 295 text

Spring Security • Highly Customizable authentication and access-control framework • Supports • Authentication (logint and logout functionality) • Process that verifies that someone or something is who they say they are • On arrival, you knock on the door, and your friend opens it. She recognizes you (authentication) and greets you. • Authorization / Access Control • Process that determines a user or service's level of access • For example, you may enter the kitchen area, but you cannot go into her private office. In other words, you have the authorization to enter the kitchen, but access to her private office is prohibited.

Slide 296

Slide 296 text

Add Spring Security org.springframework.boot spring-boot-starter-security

Slide 297

Slide 297 text

Filters: Default • Adds mandatory authentication for URLs • Adds login form • Handles login error • Creates a user (which is "user") and sets a default password which is visible when app starts

Slide 298

Slide 298 text

No content

Slide 299

Slide 299 text

application.properties spring.security.user.name=foo spring.security.user.password=foo

Slide 300

Slide 300 text

Configuring Spring Security Authentication • You may want bunch of users (may be in the database) • You may hard code users in memory testing • Spring Security < 5.7 • WebSecurityConfigurerAdapter • Spring Secury >= 5.7 • Component-based security configuration

Slide 301

Slide 301 text

Spring Boot • Enables Spring Security's default configuration • Creates a servlet Filters as a bean names SpringSecurityFilterChain • Responsible for all the security • protecting app urls • validating username and pws • Creates UserDetailsService bean with a username of user and randomly generated passsword that is logged to the console

Slide 302

Slide 302 text

Spring Boot • Requires an authenticated user for any interaction with the app • Generate a default login form for you • User with user and password like 8e557245-... • Protectst the password storage using BCrypt • Lets the user log out • CSRF attact, Session Fixation prevention and protection

Slide 303

Slide 303 text

About Servlet Filter • Java uses Servlet API for web apps underneath • Any Spring Web App is just one servlet • DispatcherServlet (Spring) redeirect incoming HTTP requests to your @Controller or @RestController • You can put filters in front of servlets • Browser -> Filter -> DispatcherServlet -> @Controller

Slide 304

Slide 304 text

No content

Slide 305

Slide 305 text

@SpringBootApplication @Controller public class SecurityDemoApplication extends HttpFilter { final private Log log = LogFactory.getLog(SecurityDemoApplication.class); public static void main(String[] args) { SpringApplication.run(SecurityDemoApplication.class, args); } @GetMapping("hello") @ResponseBody public String hello() { return "

My App content.

"; } @Override protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { var authenticationSuccess = new Random().nextBoolean(); if(!authenticationSuccess) { log.info("Client failed to authenticate"); response.setStatus(401); return; } var authorizationSuccess = new Random().nextBoolean(); if(!authorizationSuccess) { log.info("Client failed to authorize"); response.setStatus(403); return; } log.info("Success on authentication - redirect the call to dispatch servlet."); chain.doFilter(request, response); } }

Slide 306

Slide 306 text

@SpringBootApplication @Controller public class SecurityDemoApplication extends HttpFilter { final private Log log = LogFactory.getLog(SecurityDemoApplication.class); public static void main(String[] args) { SpringApplication.run(SecurityDemoApplication.class, args); } @GetMapping("hello") @ResponseBody public String hello() { return "

My App content.

"; } @Override protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { var userCredentials = extractUserNameAndPassword(request); if(!isInDatabase(userCredentials)) { log.info("Client failed to authenticate"); response.setStatus(401); return; } if(!isAuthorized(userCredentials)) { log.info("Client failed to authorize"); response.setStatus(403); return; } log.info("Success on authentication - redirect the call to dispatch servlet."); chain.doFilter(request, response); } private Map extractUserNameAndPassword(HttpServletRequest request) { return Map.of("name", request.getParameter("name"), "password", request.getParameter("password")); } private boolean isInDatabase(Map userCredentials) { return userCredentials.get("name").equals("admin") && userCredentials.get("password").equals("admin") || userCredentials.get("name").equals("jussi") && userCredentials.get("password").equals("jussi"); } private boolean isAuthorized(Map userCredentials) { return userCredentials.get("name").equals("admin") && userCredentials.get("password").equals("admin"); } }

Slide 307

Slide 307 text

Multiple Filters (FilterChain) • Previous example will lead into one monster filter, split these! • First, go through a LoginMethodFilter… • Then, go through an AuthenticationFilter… • Then, go through an AuthorizationFilter… • Finally, hit your servlet.

Slide 308

Slide 308 text

It will install 15 (!) different filters! 2022-08-06 11:57:53.388 INFO 23623 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.session.DisableEncodeUrlFilter@2a8a4e0c, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@26c89563, org.springframework.security.web.context.SecurityContextPersistenceFilter@6ada9c0c, org.springframework.security.web.header.HeaderWriterFilter@7fb66650, org.springframework.security.web.csrf.CsrfFilter@2cc75074, org.springframework.security.web.authentication.logout.LogoutFilter@6d5c2745, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@574b7f4a, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@31dfc6f5, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@3bd6ba24, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@57cb70be, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6e7c351d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@7b4a0aef, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@58f437b0, org.springframework.security.web.session.SessionManagementFilter@2a869a16, org.springframework.security.web.access.ExceptionTranslationFilter@2da3b078, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@75a0c890]

Slide 309

Slide 309 text

Configure Spring Security @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/", "/home").permitAll() // (1) .anyRequest().authenticated() // (2) .and() .formLogin().and().httpBasic(); // (3) return http.build(); }

Slide 310

Slide 310 text

Roles? http .authorizeRequests() .antMatchers("/", "/home").permitAll() .antMatchers("/secret").hasRole("user") .antMatchers("/admin").hasRole("admin") .anyRequest().authenticated() .and() .formLogin().and().httpBasic();

Slide 311

Slide 311 text

Authentication: InMemoryUserDetailsManager • For testing, you may use InMemoryUserDetailsManager • It will internally store and retreive user-related information.

Slide 312

Slide 312 text

Configure InMemoryUserDetailsManager @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } @Bean public InMemoryUserDetailsManager inMemoryUserDetailsManager() { var admin = User .withUsername("admin") .password(passwordEncoder().encode("admin")) .roles("admin", "user").build(); var user = User .withUsername("jack") .password(passwordEncoder().encode("jack")) .roles("user").build(); return new InMemoryUserDetailsManager(List.of(admin, user)); } No encoding at all! (you should not use this)

Slide 313

Slide 313 text

Configure InMemoryUserDetailsManager @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public InMemoryUserDetailsManager inMemoryUserDetailsManager() { var admin = User .withUsername("admin") .password(passwordEncoder().encode("admin")) .roles("admin", "user").build(); var user = User .withUsername("jack") .password(passwordEncoder().encode("jack")) .roles("user").build(); return new InMemoryUserDetailsManager(List.of(admin, user)); } You can decide encoder

Slide 314

Slide 314 text

Moving towards Databases: H2 org.springframework.boot spring-boot-starter-data-jpa com.h2database h2 runtime

Slide 315

Slide 315 text

Embedded H2 as DB @Bean public DataSource dataSource() { // EmbeddedDatabaseBuilder is a Spring builder which provides convenient // API to create an embedded database in a Spring application. return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) // H2, HSQL, Derby .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION) // data.sql .build(); }

Slide 316

Slide 316 text

InMemoryUserDetailsManager -> UserDetailsManager @Bean public UserDetailsManager users(DataSource dataSource) { }

Slide 317

Slide 317 text

@Bean public UserDetailsManager users(DataSource dataSource) { PasswordEncoder encoder = passwordEncoder(); UserDetails admin = User.withUsername("admin") .password(encoder.encode("admin")) .roles("admin", "user") .build(); UserDetails user = User.withUsername("user") .password(encoder.encode("user")) .roles("user") .build(); JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource); users.createUser(admin); users.createUser(user); return users; } @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); }

Slide 318

Slide 318 text

See the content of the h2 • Modify application.properties • spring.h2.console.enabled=true • Modify HttpSecurity to grant access to h2-console/ • .antMatchers("/h2-console/**").permitAll() • .. • http.csrf().disable(); • http.headers().frameOptions().disable(); • Open url • http://localhost:8080/h2-console

Slide 319

Slide 319 text

h2 - console

Slide 320

Slide 320 text

MySQL mysql mysql-connector-java runtime

Slide 321

Slide 321 text

SQL CREATE DATABASE springsecurity; USE springsecurity; CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(45) NOT NULL, password VARCHAR(245) NOT NULL, enabled INT NOT NULL ); CREATE TABLE authorities ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(45) NOT NULL, authority VARCHAR(45) NOT NULL );

Slide 322

Slide 322 text

application.properties spring.datasource.url=jdbc:mysql://localhost:3306/springsecurity spring.datasource.username=root spring.datasource.password=root

Slide 323

Slide 323 text

Secure RESTful

Slide 324

Slide 324 text

Client Server Log in JWT Use JWT to Access RESTful Return Data

Slide 325

Slide 325 text

WebClient

Slide 326

Slide 326 text

WebClient • WebClient is an interface representing the main entry point for performing web requests • Offers support for both synchronous and asynchronous operations

Slide 327

Slide 327 text

Dependency org.springframework.boot spring-boot-starter-webflux

Slide 328

Slide 328 text

Example WebClient client = WebClient.create(); WebClient.ResponseSpec responseSpec = client.get() .uri("http://example.com") .retrieve();

Slide 329

Slide 329 text

Additional Modules

Slide 330

Slide 330 text

Scheduling @SpringBootApplication @EnableScheduling public class RestServerApplication { @Scheduled(fixedDelay = 1000) public void scheduleFixedDelayTask() { System.out.println( "Fixed delay task - " + System.currentTimeMillis() / 1000); }

Slide 331

Slide 331 text

Actuator • Monitoring our app • Gathering metrics • Understanding traffic

Slide 332

Slide 332 text

Dependency org.springframework.boot spring-boot-starter-actuator

Slide 333

Slide 333 text

URLs: http://localhost/actuator/X • beans: this endpoint returns the list of all the beans configured in our application. • env: provides information about the Spring Environment properties. • health: Shows application health • info: Displays application information, we can configure this in Spring environment properties. • mappings: Displays the list of all @RequestMapping paths. • shutdown: allows us to gracefully shutdown the application. • threaddump: provides the thread dump of the application.

Slide 334

Slide 334 text

Web sockets https://spring.io/guides/gs/messaging-stomp-websocket/

Slide 335

Slide 335 text

Overview • Bidirectional persistent connection between web browser and server • Connection stays open until client or server decides to close connection • Typical use case • Multiple users communication with each other, like chat

Slide 336

Slide 336 text

Streaming Text Oriented Messaging Protocol • Text-based protocol designed to work with web sockets • Similar to HTTP, works over TCP using the following commands • SEND, SUBSCRIBE, UNSUBSCRIBE... • Example SEND destination:/queue/a content-type:text/plain hello world

Slide 337

Slide 337 text

Our service will accept simple json message { "name": "Fred" } @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class HelloMessage { private String name; }

Slide 338

Slide 338 text

Client will get greeting back { "content": "Hello, Fred!" } @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Greeting { private String content; }

Slide 339

Slide 339 text

Controller @MessageMapping("/hello") @SendTo("/topic/greetings") public Greeting greeting(HelloMessage message) throws Exception { Thread.sleep(1000); return new Greeting("Hello, " + message.getName()); } If message is sent to /hello destination, greeting() method is called Return value is broadcast to all subscribers of /topic/greetings

Slide 340

Slide 340 text

Configuration @SpringBootApplication @Controller @Configuration @EnableWebSocketMessageBroker public class DemoApplication implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { // Enable a simple memory-based message broker to carry the greeting messages // back to the client on destinations prefixed with /topic config.enableSimpleBroker("/topic"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // The client will attempt to connect to /my-websocket-service registry.addEndpoint("/my-websocket-service").withSockJS(); }

Slide 341

Slide 341 text

Dependencies org.springframework.boot spring-boot-starter-websocket org.webjars webjars-locator-core org.webjars sockjs-client 1.5.1 org.webjars stomp-websocket 2.3.4 org.webjars jquery 3.6.0

Slide 342

Slide 342 text

Client Hello WebSocket

Slide 343

Slide 343 text

Connect and subscribe function connect() { var socket = new SockJS('/my-websocket-service'); stompClient = Stomp.over(socket); stompClient.connect({}, function (frame) { setConnected(true); console.log('Connected: ' + frame); stompClient.subscribe('/topic/greetings', function (greeting) { showGreeting(JSON.parse(greeting.body).content); }); }); }

Slide 344

Slide 344 text

Send function sendName() { stompClient.send("/hello", {}, JSON.stringify({'name': $("#name").val()})); }