Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Spring Boot Framework

Spring Boot Framework

Overview of Spring Boot Framework.

Jussi Pohjolainen

May 09, 2017
Tweet

More Decks by Jussi Pohjolainen

Other Decks in Technology

Transcript

  1. 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
  2. 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
  3. 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
  4. OpenJDK Oracle Commercial JDK Oracle OpenJDK Redhat OpenJDK Eclipse Temurin

    Amazon Corretto Azul Zulu Alibaba dragonwell BellSoft Liberica JDK
  5. 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
  6. Example Java EE REST - specifications Servlet API Java API

    for RESTful Web Services Java Persistence API
  7. Different Implementations! JAX-RS 2.0: Jersey | RESTEasy | Restlet |

    ... JPA 2.1: EclipseLink | Hibernate ... Servlet 3.1: Oracle
  8. 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
  9. 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 ...
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven- 4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fi.organization</groupId> <artifactId>my-app</artifactId>

    <version>1.0</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> </dependencies> </project> 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
  16. Project Structure . ├── pom.xml └── src └── main └──

    java └── com └── company └── Main.java
  17. Main.java package com.company; public class Main { public static void

    main(String [] args) { System.out.println("Hello World"); } }
  18. 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
  19. Easier Running with plug-in: mvn exec:java <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId>

    <artifactId>exec-maven-plugin</artifactId> <version>1.5.0</version> <configuration> <mainClass>com.company.Main</mainClass> <cleanupDaemonThreads>false</cleanupDaemonThreads> </configuration> </plugin> </plugins> </build>
  20. Main – class for jar <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> <configuration>

    <archive> <manifest> <mainClass>com.company.Main</mainClass> </manifest> </archive> </configuration> </plugin>
  21. 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<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); return response.body(); } } Uses HttpClient to make http request
  22. 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!
  23. Location of downloaded jars • In Unix/Mac • ~/.m2 •

    In Windows • C:\Documents and Settings\{user-name}\.m2
  24. 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
  25. <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent>

    <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
  26. 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); } }
  27. @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.
  28. @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.
  29. @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.
  30. @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
  31. @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
  32. @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
  33. 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.
  34. 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!
  35. Spring Boot Maven Plugin • Allows you to create uber-jar!

    • Add plugin to pom and mvn package again <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
  36. Lab

  37. 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
  38. 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
  39. 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 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> <version>1.5.3.RELEASE</version> </dependency>
  40. 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"); } }
  41. 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
  42. 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
  43. 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
  44. 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.
  45. 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.
  46. 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"); } }
  47. 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]
  48. @Primary @Service @Primary public class Car implements Movable { public

    void move() { System.out.println("Car is moving!"); } }
  49. 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!"); } }
  50. @Qualifier @Component class MyCommandLineRunner implements CommandLineRunner { @Autowired @Qualifier("Car") private

    Movable movableObject; public void run(String... args) { movableObject.move(); } }
  51. @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
  52. @Service • An operation offered as an interface that stands

    alone in the model, with no encapsulated state. • "Business Serfice Facade" • Specialization of @Component
  53. 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
  54. @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
  55. @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
  56. @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)
  57. 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
  58. @Configuration, init and destroy @Configuration public class MovableConfiguration { @Bean(name

    = "Car", initMethod = "init", destroyMethod = "cleanup" ) public Movable getCar() { return new Car(); } }
  59. 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!"); } }
  60. 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); } }
  61. 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
  62. 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!
  63. 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!
  64. 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!
  65. 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(); } }
  66. 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!"); } }; } }
  67. 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!"); } }
  68. Lab

  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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"; } }
  75. @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
  76. @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
  77. Testing Post using curl curl -d "name=jack&age=20" http://localhost:8080/something <!DOCTYPE html>

    <html> <title> All Beans </title> <body> my name is jack and age is 20 </body> </html>
  78. About Thread Safety – Output of this? @Controller public class

    MyWebController { private List<String> list = new ArrayList<>(); @Autowired private HtmlHelper htmlHelper; @RequestMapping("increment") @ResponseBody public synchronized String getValue() { list.add("terve"); list.remove(random); return "" + list.toString(); } }
  79. @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")
  80. Testing @Controller public class MyWebController { @RequestMapping("thread") @ResponseBody public String

    getView() { return "object = " + this + " thread = " + Thread.currentThread().getName(); } }
  81. 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
  82. 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
  83. 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
  84. 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"; } }
  85. 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
  86. 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; } }
  87. Example 2 @Controller public class MyWebController { @RequestMapping("view") public String

    getView(Model model) { model.addAttribute("name", "Jack"); return "view"; } }
  88. 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!
  89. View <!DOCTYPE HTML> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>My View</title> <meta http-equiv="Content-Type"

    content="text/html; charset=UTF-8" /> </head> <body> <p th:text="'Hello, ' + ${name} + '!'" /> </body> </html>
  90. Model Attributes • Model attributes, or Thymeleaf context variables, can

    be accessed ${attributename} • This is a Spring EL expression
  91. Example @Controller public class MyWebController { @RequestMapping("view") public String getView(Model

    model) { List<Point> points = Arrays.asList(new Point(3,3), new Point(9,8)); model.addAttribute("points", points); return "view"; } }
  92. 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; }
  93. Java 14 Record: only getters record User(String name, String email)

    {} var jack = new User("jack", "[email protected]"); out.println(jack.name()); out.println(jack.email()); out.println(jack.toString()); out.println(jack.equals(jack));
  94. 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"; }
  95. register.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <title>User Registration</title>

    </head> <body> <h1>User Registration</h1> <form action="#" th:action="@{/register}" method="post" th:object="${user}"> <label>Full name:</label><br/> <input type="text" th:field="*{name}" /><br/> <label>E-mail:</label><br/> <input type="text" th:field="*{email}" /><br/> <button type="submit">Register</button> </form> </body> </html>
  96. success.html <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="utf-8"> <title>Registration Success</title>

    <style type="text/css"> </style> </head> <body> <h2>Registration Succeeded!</h2> <p>Full name: <span th:text="${user.name}"></p> <p>E-mail: <span th:text="${user.email}"></p> </body> </html>
  97. 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; }
  98. 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");
  99. @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
  100. @SessionAttributes • Designate which model attributes should be stored in

    the session • So before rendering stuff to View, put the stuff also into session
  101. Form <!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <title>Form</title> </head> <body> <form

    action="remember" method="get"> <input type="text" name="name" placeholder="name" /> <input type="submit" value="Send" /> </form> <p th:text="'Your name was ' + ${session.name}"></p> </body> </html>
  102. @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
  103. @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!
  104. Injecting to @Controller @Controller public class WebController { @Autowired Customer

    customer; } This will fail! Problem: Controller is singleton, Customer session. This is injected only once!
  105. 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
  106. 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
  107. 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
  108. 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!
  109. 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.
  110. Static Custom Error Message • Add a file into /error

    folder • Can be static or built using templates src/ +- main/ +- java/ | + <source code> +- resources/ +- public/ +- error/ | +- 404.html
  111. 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
  112. 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
  113. 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
  114. 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
  115. 3. Cache • Responses should define themselves as cacheable or

    not • Eliminate client-server interactions • In Restful, you can do this by using HTTP Headers
  116. Client Server Cache Client Cache Request contains all information Client

    may store the response to a cache and reuse it
  117. 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
  118. 5. Code on Demand (optional) • Client can download JavaScript,

    Flash or Java Applet from server • Server can decide how things are done
  119. 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
  120. 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
  121. 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
  122. 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
  123. 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
  124. HATEOAS (wikipedia) HTTP/1.1 200 OK Content-Type: application/xml Content-Length: ... <?xml

    version="1.0"?> <account> <account_number>12345</account_number> <balance currency="usd">100.00</balance> <link rel="deposit" href="https://somebank.org/account/12345/deposit" /> <link rel="withdraw" href="https://somebank.org/account/12345/withdraw" /> <link rel="transfer" href="https://somebank.org/account/12345/transfer" /> <link rel="close" href="https://somebank.org/account/12345/close" /> </account>
  125. { "_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
  126. 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
  127. 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
  128. 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
  129. 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}]"; } }
  130. 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}]
  131. 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 } } <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.json</artifactId> <version>1.0.4</version> </dependency>
  132. 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!
  133. 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
  134. 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}
  135. 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); } } <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
  136. Example of XML @RestController public class MyRestController { @RequestMapping(value="location", produces

    = MediaType.APPLICATION_XML_VALUE) public Location getLocation() { return new Location(60,60); } } <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
  137. 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
  138. @RestController public class ExampleController { List<Location> 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<Location> 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
  139. 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<Location> 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
  140. Let's use interfaces: MyRepository public interface MyRepository<T, ID> { public

    T saveEntity(T entity); public void delete(ID id) throws IllegalArgumentException; public Iterable<T> findAll(); public Optional<T> findOne(ID id); } This will work as a base interface. Notice that we can reuse this to work with different entities
  141. LocationRepository public interface LocationRepository extends MyRepository<Location, Integer> { } This

    will just extend the MyRepository but in addition it makes a statement that the entities must be Location and IDs are integers!
  142. Implementation of LocationRepository @Service public class LocationRepositoryImpl implements LocationRepository {

    List<Location> 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<Location> findAll() { return this.locations; } ... Let's implement the LocationRepositories methods
  143. 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
  144. Relations • Group logically relations • GET /threads/1/messages • GET

    /threads/1/messages/1 • POST /threads/1/messages
  145. 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
  146. ResponseEntity // curl -v -H "Content-type: application/json" -X // POST

    -d '{"latitude": 80, "longitude": 80}' http://localhost:8080/locations @PostMapping("/locations") public ResponseEntity<Void> 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<Void>(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
  147. 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 <
  148. 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
  149. 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" }
  150. 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"}
  151. Controller // curl -v -X DELETE http://localhost:8080/locations/7219 @DeleteMapping("/locations/{userId}") public ResponseEntity<Void>

    deleteLocation(@PathVariable int locationId) { locationRepository.delete(locationId); return new ResponseEntity<Void>(HttpStatus.NO_CONTENT); } This will throw an exception if userId is not found
  152. @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
  153. public class CannotFindLocationException extends IllegalArgumentException { private int locationId; public

    CannotFindLocationException(int id) { locationId = id; } public int getLocationId() { return locationId; } }
  154. @ControllerAdvice @ControllerAdvice public class RestResponseEntityExceptionHandler { @ExceptionHandler(CannotFindLocationException.class) public ResponseEntity<ErrorInfo> handleConflict(CannotFindLocationException

    ex) { ErrorInfo e = new ErrorInfo("Could not found location with id " + ex.getLocationId()); return new ResponseEntity<ErrorInfo>(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
  155. 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; } }
  156. 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"}
  157. 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
  158. 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
  159. 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
  160. 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.
  161. 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
  162. 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
  163. pom.xml <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc - -> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!--

    https://mvnrepository.com/artifact/org.apache.derby/derby --> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> </dependency>
  164. 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 ... "); ... } }
  165. jdbcTemplate.execute("CREATE TABLE locations(id int, lat double, lon double)"); jdbcTemplate.update("INSERT INTO

    locations values(0, 60.0, 60.0)"); List<Location> 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
  166. 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';
  167. pom.xml <!-- https://mvnrepository.com/artifact/org.apache.derby/derby --> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derby</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.derby/derbyclient

    --> <dependency> <groupId>org.apache.derby</groupId> <artifactId>derbyclient</artifactId> <version>10.13.1.1</version> </dependency> Apache Derby Database and Embedded Driver Only client driver. Database is installed via JDK and running in network mode
  168. 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
  169. 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
  170. 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) );
  171. 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!
  172. 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
  173. 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
  174. Find, delete • Find • Employee employee = entitymanager.find( Employee.class,

    1201 ); • Delete • entitymanager.remove( employee );
  175. Hibernate Query Language • Load complete set of resources •

    List<Employee> results = entitymanager.createQuery("FROM Employee").getResultList(); • SELECT • List<String> results = entitymanager.createQuery("SELECT firstName FROM Employee").getResultList(); • WHERE • List<Employee> 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")
  176. 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
  177. 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!
  178. CrudRepository interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {

    <S extends T> S save(S entity); T findOne(ID primaryKey); Iterable<T> findAll(); Long count(); void delete(T entity); boolean exists(ID primaryKey); // ... }
  179. @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<Location> list = springDatarepository.findAll(); list.forEach(System.out::println); } } Spring Data will create a implementation for the interface and injects it here!
  180. 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<Location> fetchLocation(@PathVariable int locationId) { Location location = locatinoRepository.findOne(locationId); return new ResponseEntity<Customer>(location, HttpStatus.OK); } }
  181. Own Methods public interface LocationRepositorySpringData extends LocationRepository<Location, Integer> { List<Location>

    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!
  182. Usage // curl http://localhost:8080/springdata/locations?latitude=60 @RequestMapping(value = "/springdata/locations", method=RequestMethod.GET) public Iterable<Location>

    findByLatitude(@RequestParam("latitude") Optional<Double> optionalLatitude) { if(optionalLatitude.isPresent()) { double latitude = optionalLatitude.get(); return locationRepository.findByLatitude(latitude); } else { return locationRepository.findAll(); } }
  183. 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
  184. 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); } }
  185. 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
  186. 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..
  187. 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
  188. 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"
  189. 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
  190. 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?
  191. Wrapper Class public class LocationDTO extends ResourceSupport { private Location

    location; public LocationDTO(Location location) { this.location = location; } public Location getLocation() { return this.location; } }
  192. Usage @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity<LocationDTO> 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>(locationDTO, HttpStatus.OK); } Let's return LocationDTO instead of Location
  193. Result { "location" : { "id" : 1, "latitude" :

    60 ... }, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } } Usually we want these to be on top level
  194. Wrapper Class public class LocationDTO extends ResourceSupport { @JsonUnWrapped private

    Location location; public LocationDTO(Location location) { this.location = location; } public Location getLocation() { return this.location; } }
  195. Result { "id" : 1, "latitude" : 60, "longitude" :

    60, "_links" : { "self" : { "href" : "http://localhost:8080/locations/1" } } }
  196. Wrapper Mapping @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity<LocationDTO> 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>(locationDTO, HttpStatus.OK); } The manual wrapping between DTO and Entity can be a pain. Spring provides you the wrapper: Resources<T>
  197. Resource<T> @RequestMapping(value = "/{userId}", method=RequestMethod.GET) public ResponseEntity<Resource<Location>> fetchLocation(@PathVariable long userId)

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

    ResponseEntity<Resource<Location>> fetchLocation(@PathVariable long userId) { Location location = locationRepository.findOne(userId); return new ResponseEntity<Resource<Location>>(locationToResource(location), HttpStatus.OK); } private Resource<Location> locationToResource(Location location) { Link selfLink = ControllerLinkBuilder.linkTo(MyRestControllerSpringData.class).slash(location.getId()).withSelfRel(); return new Resource<>(location, selfLink); }
  199. 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
  200. 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<Location> fetchLocation(@PathVariable long locationId) throws CannotFindLocationException { var location = database.findById(locationId); if(location.isEmpty()) throw new CannotFindLocationException(locationId); return new ResponseEntity<Location>(location.get(), HttpStatus.OK); }
  201. 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
  202. jar to war • Add / or modify pom.xml •

    <packaging>war</packaging> • 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!
  203. Jar + War in same • You can move the

    tomcat libraries to different folder • Works both in jar and in war! • Add dependency <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> • This will include the libraries but put them in lib-provided/
  204. 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); } }
  205. 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.
  206. 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.
  207. 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!
  208. 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!
  209. @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<Customer> addedCustomer = repository.findById(1); assertTrue(addedCustomer.isPresent() , "not present"); assertTrue(addedCustomer.get().getId() == 1, "wrong id"); assertTrue(addedCustomer.get().getName().equals("Jack"), "wrong name"); }
  210. 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
  211. 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.
  212. 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
  213. 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.
  214. 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
  215. 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
  216. 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
  217. 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
  218. 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
  219. @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 "<h1>My App content.</h1>"; } @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); } }
  220. @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 "<h1>My App content.</h1>"; } @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<String, String> extractUserNameAndPassword(HttpServletRequest request) { return Map.of("name", request.getParameter("name"), "password", request.getParameter("password")); } private boolean isInDatabase(Map<String, String> 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<String, String> userCredentials) { return userCredentials.get("name").equals("admin") && userCredentials.get("password").equals("admin"); } }
  221. 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.
  222. 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]
  223. 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(); }
  224. 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)
  225. 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
  226. 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(); }
  227. @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(); }
  228. 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
  229. 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 );
  230. WebClient • WebClient is an interface representing the main entry

    point for performing web requests • Offers support for both synchronous and asynchronous operations
  231. Scheduling @SpringBootApplication @EnableScheduling public class RestServerApplication { @Scheduled(fixedDelay = 1000)

    public void scheduleFixedDelayTask() { System.out.println( "Fixed delay task - " + System.currentTimeMillis() / 1000); }
  232. 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.
  233. 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
  234. 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
  235. Our service will accept simple json message { "name": "Fred"

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

    @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class Greeting { private String content; }
  237. 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
  238. 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(); }
  239. Dependencies <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> <!-- frontend --> <dependency> <groupId>org.webjars</groupId>

    <artifactId>webjars-locator-core</artifactId> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>sockjs-client</artifactId> <version>1.5.1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>stomp-websocket</artifactId> <version>2.3.4</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.6.0</version> </dependency>
  240. 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); }); }); }