Merge branch 'master' of https://github.com/abh1navv/tutorials into BAEL-3201
This commit is contained in:
@@ -44,12 +44,13 @@
|
||||
<module>spring-boot-groovy</module>
|
||||
<!-- <module>spring-boot-gradle</module> --> <!-- Not a maven project -->
|
||||
<module>spring-boot-jasypt</module>
|
||||
<module>spring-boot-jsp</module>
|
||||
<module>spring-boot-keycloak</module>
|
||||
<module>spring-boot-keycloak-2</module>
|
||||
<module>spring-boot-libraries</module>
|
||||
<module>spring-boot-libraries-2</module>
|
||||
<module>spring-boot-libraries-comparison</module>
|
||||
<module>spring-boot-logging-log4j2</module>
|
||||
<module>spring-boot-multiple-datasources</module>
|
||||
<module>spring-boot-mvc</module>
|
||||
<module>spring-boot-mvc-2</module>
|
||||
<module>spring-boot-mvc-3</module>
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<?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">
|
||||
<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>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>spring-boot-data-3</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-data-3</name>
|
||||
<description>spring-boot-data-3</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@@ -21,13 +24,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
@@ -44,4 +45,4 @@
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -0,0 +1,3 @@
|
||||
### Relevant Articles:
|
||||
|
||||
- [Spring Boot With JavaServer Pages (JSP)](https://www.baeldung.com/spring-boot-jsp)
|
||||
@@ -0,0 +1,105 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-boot-jsp</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>spring-boot-jsp</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit</groupId>
|
||||
<artifactId>junit-bom</artifactId>
|
||||
<version>${junit-jupiter.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-bom</artifactId>
|
||||
<version>${log4j2.version}</version>
|
||||
<scope>import</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>jstl</artifactId>
|
||||
<version>${jstl.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.tomcat.embed</groupId>
|
||||
<artifactId>tomcat-embed-jasper</artifactId>
|
||||
<!--uncomment below if deploying in web container -->
|
||||
<!--<scope>provided</scope> -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!--uncomment below if deploying in web container -->
|
||||
<!--<dependency> -->
|
||||
<!-- <groupId>org.springframework.boot</groupId> -->
|
||||
<!-- <artifactId>spring-boot-starter-tomcat</artifactId> -->
|
||||
<!-- <scope>provided</scope> -->
|
||||
<!--</dependency> -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>spring-boot-jsp</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<configuration>
|
||||
<mainClass>com.baeldung.boot.jsp.SpringBootJspApplication</mainClass>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<jstl.version>1.2</jstl.version>
|
||||
<spring-boot.version>2.4.4</spring-boot.version>
|
||||
<log4j2.version>2.17.1</log4j2.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.baeldung.boot.jsp;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = "com.baeldung.boot.jsp")
|
||||
public class SpringBootJspApplication extends SpringBootServletInitializer {
|
||||
|
||||
|
||||
//comment below if deploying outside web container -->
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
|
||||
return builder.sources(SpringBootJspApplication.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootJspApplication.class);
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.baeldung.boot.jsp;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.impl.InMemoryBookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
@Configuration
|
||||
public class SpringBootJspConfiguration {
|
||||
|
||||
@Bean
|
||||
public BookRepository provideBookRepository() {
|
||||
return new InMemoryBookRepository(initialBookData());
|
||||
}
|
||||
|
||||
private static Map<String, BookData> initialBookData() {
|
||||
Map<String, BookData> initData = new HashMap<>();
|
||||
initData.put("ISBN-1", new BookData("ISBN-1", "Book 1", "Book 1 Author"));
|
||||
initData.put("ISBN-2", new BookData("ISBN-2", "Book 2", "Book 2 Author"));
|
||||
initData.put("ISBN-3", new BookData("ISBN-3", "Book 3", "Book 3 Author"));
|
||||
return initData;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.baeldung.boot.jsp.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import com.baeldung.boot.jsp.service.BookService;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/book")
|
||||
public class BookController {
|
||||
|
||||
private final BookService bookService;
|
||||
|
||||
public BookController(BookService bookService) {
|
||||
this.bookService = bookService;
|
||||
}
|
||||
|
||||
@GetMapping("/viewBooks")
|
||||
public String viewBooks(Model model) {
|
||||
model.addAttribute("books", bookService.getBooks());
|
||||
return "view-books";
|
||||
}
|
||||
|
||||
@GetMapping("/addBook")
|
||||
public String addBookView(Model model) {
|
||||
model.addAttribute("book", new Book());
|
||||
return "add-book";
|
||||
}
|
||||
|
||||
@PostMapping("/addBook")
|
||||
public RedirectView addBook(@ModelAttribute("book") Book book, RedirectAttributes redirectAttributes) {
|
||||
final RedirectView redirectView = new RedirectView("/book/addBook", true);
|
||||
Book savedBook = bookService.addBook(book);
|
||||
redirectAttributes.addFlashAttribute("savedBook", savedBook);
|
||||
redirectAttributes.addFlashAttribute("addBookSuccess", true);
|
||||
return redirectView;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.baeldung.boot.jsp.controller;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/")
|
||||
public class HomeController {
|
||||
|
||||
@GetMapping("")
|
||||
public String index() {
|
||||
return "index";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.boot.jsp.dto;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class Book {
|
||||
private String isbn;
|
||||
private String name;
|
||||
private String author;
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.boot.jsp.exception;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DuplicateBookException extends RuntimeException {
|
||||
private final Book book;
|
||||
|
||||
public DuplicateBookException(Book book) {
|
||||
this.book = book;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baeldung.boot.jsp.exception;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@ControllerAdvice
|
||||
public class LibraryControllerAdvice {
|
||||
|
||||
@ExceptionHandler(value = DuplicateBookException.class)
|
||||
public ModelAndView duplicateBookException(DuplicateBookException e) {
|
||||
final ModelAndView modelAndView = new ModelAndView();
|
||||
modelAndView.addObject("ref", e.getBook().getIsbn());
|
||||
modelAndView.addObject("object", e.getBook());
|
||||
modelAndView.addObject("message", "Cannot add an already existing book");
|
||||
modelAndView.setViewName("error-book");
|
||||
return modelAndView;
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.boot.jsp.repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
public interface BookRepository {
|
||||
Collection<BookData> findAll();
|
||||
|
||||
Optional<BookData> findById(String isbn);
|
||||
|
||||
BookData add(BookData book);
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.baeldung.boot.jsp.repository.impl;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
public class InMemoryBookRepository implements BookRepository {
|
||||
|
||||
private final Map<String, BookData> storedBooks;
|
||||
|
||||
public InMemoryBookRepository(Map<String, BookData> storedBooks) {
|
||||
this.storedBooks = new HashMap<>();
|
||||
this.storedBooks.putAll(storedBooks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<BookData> findAll() {
|
||||
if (storedBooks.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return storedBooks.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BookData> findById(String isbn) {
|
||||
return Optional.ofNullable(storedBooks.get(isbn));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BookData add(BookData book) {
|
||||
storedBooks.put(book.getIsbn(), book);
|
||||
return book;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.baeldung.boot.jsp.repository.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BookData {
|
||||
private String isbn;
|
||||
private String name;
|
||||
private String author;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.baeldung.boot.jsp.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
|
||||
public interface BookService {
|
||||
Collection<Book> getBooks();
|
||||
|
||||
Book addBook(Book book);
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.baeldung.boot.jsp.service.impl;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.baeldung.boot.jsp.exception.DuplicateBookException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
import com.baeldung.boot.jsp.service.BookService;
|
||||
|
||||
@Service
|
||||
public class BookServiceImpl implements BookService {
|
||||
|
||||
private final BookRepository bookRepository;
|
||||
|
||||
public BookServiceImpl(BookRepository bookRepository) {
|
||||
this.bookRepository = bookRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Book> getBooks() {
|
||||
return bookRepository.findAll()
|
||||
.stream()
|
||||
.map(BookServiceImpl::convertBookData)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book addBook(Book book) {
|
||||
final Optional<BookData> existingBook = bookRepository.findById(book.getIsbn());
|
||||
if (existingBook.isPresent()) {
|
||||
throw new DuplicateBookException(book);
|
||||
}
|
||||
|
||||
final BookData savedBook = bookRepository.add(convertBook(book));
|
||||
return convertBookData(savedBook);
|
||||
}
|
||||
|
||||
private static Book convertBookData(BookData bookData) {
|
||||
return new Book(bookData.getIsbn(), bookData.getName(), bookData.getAuthor());
|
||||
}
|
||||
|
||||
private static BookData convertBook(Book book) {
|
||||
return new BookData(book.getIsbn(), book.getName(), book.getAuthor());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
server.servlet.context-path=/spring-boot-jsp
|
||||
|
||||
spring.mvc.view.prefix: /WEB-INF/jsp/
|
||||
spring.mvc.view.suffix: .jsp
|
||||
@@ -0,0 +1,10 @@
|
||||
table {
|
||||
font-family: arial, sans-serif;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td, th {
|
||||
border: 1px solid #dddddd;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
Opps! 4xx Error Occurred.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Add Book</title>
|
||||
</head>
|
||||
<body>
|
||||
<c:if test="${addBookSuccess}">
|
||||
<div>Successfully added Book with ISBN: ${savedBook.isbn}</div>
|
||||
</c:if>
|
||||
|
||||
<c:url var="add_book_url" value="/book/addBook"/>
|
||||
<form:form action="${add_book_url}" method="post" modelAttribute="book">
|
||||
<form:label path="isbn">ISBN: </form:label> <form:input type="text" path="isbn"/>
|
||||
<form:label path="name">Book Name: </form:label> <form:input type="text" path="name"/>
|
||||
<form:label path="author">Author Name: </form:label> <form:input path="author"/>
|
||||
<input type="submit" value="submit"/>
|
||||
</form:form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
<%--
|
||||
Created by IntelliJ IDEA.
|
||||
User: jason
|
||||
Date: 3/13/21
|
||||
Time: 10:39 PM
|
||||
To change this template use File | Settings | File Templates.
|
||||
--%>
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<html>
|
||||
<head>
|
||||
<title>Error</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Reference: ${ref}</p>
|
||||
<p>Error Message: ${message}</p>
|
||||
<p>Object: ${object}</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<html>
|
||||
<head>
|
||||
<title>Index page</title>
|
||||
</head>
|
||||
<body>
|
||||
<div> This is index page </div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,28 @@
|
||||
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
|
||||
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<html>
|
||||
<head>
|
||||
<title>View Books</title>
|
||||
<link href="<c:url value="/css/common.css"/>" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ISBN</th>
|
||||
<th>Name</th>
|
||||
<th>Author</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<c:forEach items="${books}" var="book">
|
||||
<tr>
|
||||
<td>${book.isbn}</td>
|
||||
<td>${book.name}</td>
|
||||
<td>${book.author}</td>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package com.baeldung.boot.jsp.controller;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasProperty;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.impl.InMemoryBookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@WebAppConfiguration
|
||||
@ContextConfiguration
|
||||
@AutoConfigureMockMvc
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class BookControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private BookRepository bookRepository;
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void whenAddBook_thenBookSaved() throws Exception {
|
||||
MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.param("isbn", "isbn1")
|
||||
.param("name", "name1")
|
||||
.param("author", "author1");
|
||||
mockMvc.perform(addBookRequest)
|
||||
.andReturn();
|
||||
|
||||
Optional<BookData> storedBookOpt = bookRepository.findById("isbn1");
|
||||
assertTrue(storedBookOpt.isPresent());
|
||||
assertEquals("name1", storedBookOpt.get()
|
||||
.getName());
|
||||
assertEquals("author1", storedBookOpt.get()
|
||||
.getAuthor());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void givenAlreadyExistingBook_whenAddBook_thenShowErrorPage() throws Exception {
|
||||
MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.param("isbn", "isbn1")
|
||||
.param("name", "name1")
|
||||
.param("author", "author1");
|
||||
ResultActions addBookResult = mockMvc.perform(addBookRequest);
|
||||
|
||||
addBookResult.andExpect(view().name("error-book"))
|
||||
.andExpect(model().attribute("ref", "isbn1"))
|
||||
.andExpect(model().attribute("object", hasProperty("isbn", equalTo("isbn1"))))
|
||||
.andExpect(model().attribute("message", "Cannot add an already existing book"));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.boot.jsp")
|
||||
static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public BookRepository provideBookRepository() {
|
||||
return new InMemoryBookRepository(Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.baeldung.boot.jsp.controller;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.AdditionalAnswers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import com.baeldung.boot.jsp.service.BookService;
|
||||
|
||||
@WebMvcTest(BookController.class)
|
||||
class BookControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@MockBean
|
||||
private BookService bookService;
|
||||
|
||||
@Test
|
||||
public void whenViewBooks_thenReturnBooksView() throws Exception {
|
||||
when(bookService.getBooks()).thenReturn(existingBooks());
|
||||
ResultActions viewBooksResult = mockMvc.perform(get("/book/viewBooks"));
|
||||
|
||||
viewBooksResult.andExpect(view().name("view-books"))
|
||||
.andExpect(model().attribute("books", hasSize(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddBookView_thenReturnAddBooksView() throws Exception {
|
||||
ResultActions addBookViewResult = mockMvc.perform(get("/book/addBook"));
|
||||
|
||||
addBookViewResult.andExpect(view().name("add-book"))
|
||||
.andExpect(model().attribute("book", isA(Book.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddBookPost_thenRedirectToAddBookView() throws Exception {
|
||||
when(bookService.addBook(any(Book.class))).thenAnswer(AdditionalAnswers.returnsFirstArg());
|
||||
MockHttpServletRequestBuilder addBookRequest = MockMvcRequestBuilders.post("/book/addBook")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.param("isbn", "isbn1")
|
||||
.param("name", "name1")
|
||||
.param("author", "author1");
|
||||
ResultActions addBookResult = mockMvc.perform(addBookRequest);
|
||||
|
||||
addBookResult.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("/book/addBook"))
|
||||
.andExpect(flash().attribute("savedBook", hasProperty("isbn", equalTo("isbn1"))))
|
||||
.andExpect(flash().attribute("addBookSuccess", true));
|
||||
}
|
||||
|
||||
private static Collection<Book> existingBooks() {
|
||||
List<Book> books = new ArrayList<>();
|
||||
books.add(new Book("isbn1", "name1", "author1"));
|
||||
books.add(new Book("isbn2", "name2", "author2"));
|
||||
books.add(new Book("isbn3", "name3", "author3"));
|
||||
return books;
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.baeldung.boot.jsp.repository.impl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
public class InMemoryBookRepositoryUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenEmtpyData_whenFindAll_thenReturnEmptyCollection() {
|
||||
BookRepository bookRepository = new InMemoryBookRepository(Collections.emptyMap());
|
||||
Collection<BookData> storedBooks = bookRepository.findAll();
|
||||
|
||||
assertEquals(0, storedBooks.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInitialData_whenFindAll_thenReturnInitialData() {
|
||||
BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
|
||||
Collection<BookData> storedBooks = bookRepository.findAll();
|
||||
|
||||
assertEquals(3, storedBooks.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInitialData_whenFindUnavailableIsbn_thenReturnEmpty() {
|
||||
BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
|
||||
Optional<BookData> storedBookOpt = bookRepository.findById("isbn4");
|
||||
|
||||
assertFalse(storedBookOpt.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenInitialData_whenFindAvailableIsbn_thenReturnItem() {
|
||||
BookRepository bookRepository = new InMemoryBookRepository(initialBookData());
|
||||
Optional<BookData> storedBookOpt = bookRepository.findById("isbn1");
|
||||
|
||||
assertTrue(storedBookOpt.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAddedIsbn_whenFindAvailableIsbn_thenReturnItem() {
|
||||
BookRepository bookRepository = new InMemoryBookRepository(Collections.emptyMap());
|
||||
bookRepository.add(new BookData("isbn4", "name4", "author4"));
|
||||
Optional<BookData> storedBookOpt = bookRepository.findById("isbn4");
|
||||
|
||||
assertTrue(storedBookOpt.isPresent());
|
||||
}
|
||||
|
||||
private static Map<String, BookData> initialBookData() {
|
||||
Map<String, BookData> initData = new HashMap<>();
|
||||
initData.put("isbn1", new BookData("isbn1", "name1", "author1"));
|
||||
initData.put("isbn2", new BookData("isbn2", "name2", "author2"));
|
||||
initData.put("isbn3", new BookData("isbn3", "name3", "author3"));
|
||||
return initData;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.baeldung.boot.jsp.service;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import com.baeldung.boot.jsp.exception.DuplicateBookException;
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.impl.InMemoryBookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||
public class BookServiceIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private BookService bookService;
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void givenNoAddedBooks_whenGetAllBooks_thenReturnInitialBooks() {
|
||||
Collection<Book> storedBooks = bookService.getBooks();
|
||||
|
||||
assertEquals(3, storedBooks.size());
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-1"))));
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-2"))));
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("ISBN-TEST-3"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void givenBookNotAlreadyExists_whenAddBook_thenReturnSuccessfully() {
|
||||
Book bookToBeAdded = new Book("ISBN-ADD-TEST-4", "Added Book 4", "Added Book 4 Author");
|
||||
Book storedBook = bookService.addBook(bookToBeAdded);
|
||||
|
||||
assertEquals(bookToBeAdded.getIsbn(), storedBook.getIsbn());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void givenBookAlreadyExists_whenAddBook_thenDuplicateBookException() {
|
||||
Book bookToBeAdded = new Book("ISBN-ADD-TEST-4", "Updated Book 4", "Updated Book 4 Author");
|
||||
|
||||
assertThrows(DuplicateBookException.class, () -> bookService.addBook(bookToBeAdded));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.boot.jsp")
|
||||
static class ContextConfiguration {
|
||||
|
||||
@Bean
|
||||
public BookRepository provideBookRepository() {
|
||||
return new InMemoryBookRepository(initialBookData());
|
||||
}
|
||||
|
||||
private static Map<String, BookData> initialBookData() {
|
||||
Map<String, BookData> initData = new HashMap<>();
|
||||
initData.put("ISBN-TEST-1", new BookData("ISBN-TEST-1", "Book 1", "Book 1 Author"));
|
||||
initData.put("ISBN-TEST-2", new BookData("ISBN-TEST-2", "Book 2", "Book 2 Author"));
|
||||
initData.put("ISBN-TEST-3", new BookData("ISBN-TEST-3", "Book 3", "Book 3 Author"));
|
||||
return initData;
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.baeldung.boot.jsp.service.impl;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.AdditionalAnswers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import com.baeldung.boot.jsp.dto.Book;
|
||||
import com.baeldung.boot.jsp.exception.DuplicateBookException;
|
||||
import com.baeldung.boot.jsp.repository.BookRepository;
|
||||
import com.baeldung.boot.jsp.repository.model.BookData;
|
||||
import com.baeldung.boot.jsp.service.BookService;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class BookServiceImplUnitTest {
|
||||
|
||||
@Mock
|
||||
private BookRepository bookRepository;
|
||||
|
||||
@Test
|
||||
public void whenGetBooks_thenAllBooksReturned() {
|
||||
when(bookRepository.findAll()).thenReturn(existingBooks());
|
||||
BookService bookService = new BookServiceImpl(bookRepository);
|
||||
|
||||
Collection<Book> storedBooks = bookService.getBooks();
|
||||
assertEquals(3, storedBooks.size());
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn1"))));
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn2"))));
|
||||
assertThat(storedBooks, hasItem(hasProperty("isbn", equalTo("isbn3"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddBook_thenAddSuccessful() {
|
||||
when(bookRepository.findById(anyString())).thenReturn(Optional.empty());
|
||||
when(bookRepository.add(any(BookData.class))).thenAnswer(AdditionalAnswers.returnsFirstArg());
|
||||
BookService bookService = new BookServiceImpl(bookRepository);
|
||||
Book book = bookService.addBook(new Book("isbn1", "name1", "author1"));
|
||||
|
||||
assertEquals("isbn1", book.getIsbn());
|
||||
assertEquals("name1", book.getName());
|
||||
assertEquals("author1", book.getAuthor());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenBookAlreadyExist_whenAddBook_thenDuplicateBookException() {
|
||||
BookData existingBook = new BookData("isbn1", "name1", "author1");
|
||||
when(bookRepository.findById("isbn1")).thenReturn(Optional.of(existingBook));
|
||||
BookService bookService = new BookServiceImpl(bookRepository);
|
||||
Book bookToBeAdded = new Book("isbn1", "name1", "author1");
|
||||
|
||||
assertThrows(DuplicateBookException.class, () -> bookService.addBook(bookToBeAdded));
|
||||
}
|
||||
|
||||
private static Collection<BookData> existingBooks() {
|
||||
List<BookData> books = new ArrayList<>();
|
||||
books.add(new BookData("isbn1", "name1", "author1"));
|
||||
books.add(new BookData("isbn2", "name2", "author2"));
|
||||
books.add(new BookData("isbn3", "name3", "author3"));
|
||||
return books;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration scan="true" scanPeriod="15 seconds" debug="false">
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>[%d{ISO8601}]-[%thread] %-5level %logger - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -0,0 +1,6 @@
|
||||
## Spring Boot Keycloak
|
||||
|
||||
This module contains articles about Keycloak in Spring Boot projects.
|
||||
|
||||
## Relevant articles:
|
||||
- [Disabling Keycloak Security in Spring Boot](https://www.baeldung.com/spring-keycloak-security-disable)
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung.keycloak</groupId>
|
||||
<artifactId>spring-boot-keycloak-2</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<name>spring-boot-keycloak-2</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>This is a simple application demonstrating integration between Keycloak and Spring Boot.</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<keycloak-adapter-bom.version>15.0.2</keycloak-adapter-bom.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-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.bom</groupId>
|
||||
<artifactId>keycloak-adapter-bom</artifactId>
|
||||
<version>${keycloak-adapter-bom.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
</configuration>
|
||||
+5
-8
@@ -1,28 +1,25 @@
|
||||
package com.baeldung.disablingkeycloak;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@SpringBootTest(classes = App.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@RunWith(SpringRunner.class)
|
||||
@ActiveProfiles("disablingkeycloak")
|
||||
public class DisablingKeycloakIntegrationTest {
|
||||
class DisablingKeycloakIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void givenUnauthenticated_whenGettingUser_shouldReturnUser() {
|
||||
void givenUnauthenticated_whenGettingUser_shouldReturnUser() {
|
||||
ResponseEntity<User> responseEntity = restTemplate.getForEntity("/users/1", User.class);
|
||||
|
||||
assertEquals(HttpStatus.SC_OK, responseEntity.getStatusCodeValue());
|
||||
@@ -10,4 +10,3 @@ This module contains articles about Keycloak in Spring Boot projects.
|
||||
- [Customizing Themes for Keycloak](https://www.baeldung.com/spring-keycloak-custom-themes)
|
||||
- [Securing SOAP Web Services With Keycloak](https://www.baeldung.com/soap-keycloak)
|
||||
- [Get Keycloak User ID in Spring](https://www.baeldung.com/spring-keycloak-get-user-id)
|
||||
- [Disabling Keycloak Security in Spring Boot](https://www.baeldung.com/spring-keycloak-security-disable)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
.local-db
|
||||
@@ -1,58 +0,0 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-boot-multiple-datasources</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>spring-boot-multiple-datasources</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Module For Spring Boot With Multiple Datasources</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot.version>2.6.3</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
package com.baeldung.spring.datasources.todos;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Todo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private String title;
|
||||
private boolean completed;
|
||||
|
||||
public Todo() {
|
||||
}
|
||||
|
||||
public Todo(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public boolean isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
|
||||
public void setCompleted(boolean completed) {
|
||||
this.completed = completed;
|
||||
}
|
||||
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package com.baeldung.spring.datasources.todos;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
public class TodoDatasourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("spring.datasource.todos")
|
||||
public DataSourceProperties todosDataSourceProperties() {
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public DataSource todosDataSource() {
|
||||
return todosDataSourceProperties()
|
||||
.initializeDataSourceBuilder()
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
package com.baeldung.spring.datasources.todos;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories(
|
||||
basePackageClasses = Todo.class,
|
||||
entityManagerFactoryRef = "todosEntityManagerFactory",
|
||||
transactionManagerRef = "todosTransactionManager"
|
||||
)
|
||||
public class TodoJpaConfiguration {
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean todosEntityManagerFactory(
|
||||
@Qualifier("todosDataSource") DataSource dataSource,
|
||||
EntityManagerFactoryBuilder builder) {
|
||||
return builder
|
||||
.dataSource(dataSource)
|
||||
.packages(Todo.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager todosTransactionManager(
|
||||
@Qualifier("todosEntityManagerFactory") LocalContainerEntityManagerFactoryBean todosEntityManagerFactory) {
|
||||
return new JpaTransactionManager(Objects.requireNonNull(todosEntityManagerFactory.getObject()));
|
||||
}
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
package com.baeldung.spring.datasources.todos;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface TodoRepository extends JpaRepository<Todo, Long> {
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package com.baeldung.spring.datasources.topics;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Topic {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
private String title;
|
||||
|
||||
public Topic() {
|
||||
}
|
||||
|
||||
public Topic(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package com.baeldung.spring.datasources.topics;
|
||||
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
public class TopicDatasourceConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("spring.datasource.topics")
|
||||
public DataSourceProperties topicsDataSourceProperties() {
|
||||
return new DataSourceProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource topicsDataSource() {
|
||||
return topicsDataSourceProperties()
|
||||
.initializeDataSourceBuilder()
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
package com.baeldung.spring.datasources.topics;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Objects;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@EnableJpaRepositories(
|
||||
basePackageClasses = Topic.class,
|
||||
entityManagerFactoryRef = "topicsEntityManagerFactory",
|
||||
transactionManagerRef = "topicsTransactionManager"
|
||||
)
|
||||
public class TopicJpaConfiguration {
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean topicsEntityManagerFactory(
|
||||
@Qualifier("topicsDataSource") DataSource dataSource,
|
||||
EntityManagerFactoryBuilder builder
|
||||
) {
|
||||
return builder
|
||||
.dataSource(dataSource)
|
||||
.packages(Topic.class)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager topicsTransactionManager(
|
||||
@Qualifier("topicsEntityManagerFactory") LocalContainerEntityManagerFactoryBean topicsEntityManagerFactory) {
|
||||
return new JpaTransactionManager(Objects.requireNonNull(topicsEntityManagerFactory.getObject()));
|
||||
}
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
package com.baeldung.spring.datasources.topics;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface TopicRepository extends JpaRepository<Topic, Long> {
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
spring:
|
||||
datasource:
|
||||
todos:
|
||||
url: jdbc:h2:./.local-db/todos;DB_CLOSE_DELAY=-1;MODE=DB2;AUTO_SERVER=TRUE
|
||||
username: sa
|
||||
password: null
|
||||
driverClassName: org.h2.Driver
|
||||
topics:
|
||||
url: jdbc:h2:./.local-db/topics;DB_CLOSE_DELAY=-1;MODE=DB2;AUTO_SERVER=TRUE
|
||||
username: sa
|
||||
password: null
|
||||
driverClassName: org.h2.Driver
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
path: /h2-console
|
||||
jpa:
|
||||
generate-ddl: true
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
properties:
|
||||
hibernate:
|
||||
dialect: org.hibernate.dialect.H2Dialect
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package com.baeldung.spring.datasources;
|
||||
|
||||
import com.baeldung.spring.datasources.todos.Todo;
|
||||
import com.baeldung.spring.datasources.todos.TodoRepository;
|
||||
import com.baeldung.spring.datasources.topics.Topic;
|
||||
import com.baeldung.spring.datasources.topics.TopicRepository;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DataJpaTest // no test database!
|
||||
class MultipleDatasourcesIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
TodoRepository todoRepo;
|
||||
@Autowired
|
||||
TopicRepository topicRepo;
|
||||
|
||||
@Test
|
||||
void shouldSaveTodoToTodoDB() {
|
||||
Todo todo = new Todo("test");
|
||||
Todo saved =todoRepo.save(todo);
|
||||
Optional<Todo> result= todoRepo.findById(saved.getId());
|
||||
assertThat(result).isPresent();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSaveTopicToTopicDB() {
|
||||
Topic todo = new Topic("test");
|
||||
Topic saved =topicRepo.save(todo);
|
||||
Optional<Topic> result= topicRepo.findById(saved.getId());
|
||||
assertThat(result).isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<?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">
|
||||
<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>
|
||||
<artifactId>spring-boot-springdoc</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web-services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
@@ -43,13 +47,39 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>1.17.2</version>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.dasniko</groupId>
|
||||
<artifactId>testcontainers-keycloak</artifactId>
|
||||
<version>${testcontainers-keycloak.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.bom</groupId>
|
||||
<artifactId>keycloak-adapter-bom</artifactId>
|
||||
<version>${keycloak-adapter.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -77,6 +107,9 @@
|
||||
|
||||
<properties>
|
||||
<start-class>com.baeldung.boot.Application</start-class>
|
||||
<testcontainers.version>1.17.2</testcontainers.version>
|
||||
<testcontainers-keycloak.version>1.10.0</testcontainers-keycloak.version>
|
||||
<keycloak-adapter.version>13.0.1</keycloak-adapter.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
+3
-4
@@ -1,13 +1,12 @@
|
||||
package com.baeldung.spring.datasources;
|
||||
package com.baeldung.keycloaktestcontainers;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MultipleDatasourcesApplication {
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MultipleDatasourcesApplication.class, args);
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.keycloaktestcontainers.configuration;
|
||||
|
||||
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class KeycloakConfiguration {
|
||||
|
||||
@Bean
|
||||
public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
|
||||
return new KeycloakSpringBootConfigResolver();
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.baeldung.keycloaktestcontainers.configuration;
|
||||
|
||||
import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
|
||||
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||
|
||||
@KeycloakConfiguration
|
||||
@ConditionalOnProperty(name = "keycloak.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class KeycloakSecurityConfiguration extends KeycloakWebSecurityConfigurerAdapter {
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) {
|
||||
auth.authenticationProvider(keycloakAuthenticationProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Bean
|
||||
@Override
|
||||
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||
return new NullAuthenticatedSessionStrategy();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
super.configure(http);
|
||||
|
||||
http.csrf()
|
||||
.disable()
|
||||
.cors()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.anyRequest()
|
||||
.authenticated();
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.keycloaktestcontainers.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.keycloaktestcontainers.dto.UserDto;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/users")
|
||||
public class UserController {
|
||||
|
||||
@GetMapping("me")
|
||||
public UserDto getMe() {
|
||||
return new UserDto(1L, "janedoe", "Doe", "Jane", "jane.doe@baeldung.com");
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.baeldung.keycloaktestcontainers.dto;
|
||||
|
||||
public class UserDto {
|
||||
private long id;
|
||||
private String username;
|
||||
private String lastname;
|
||||
private String firstname;
|
||||
private String email;
|
||||
|
||||
public UserDto(long id, String username, String lastname, String firstname, String email) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.lastname = lastname;
|
||||
this.firstname = firstname;
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return lastname;
|
||||
}
|
||||
|
||||
public void setLastname(String lastname) {
|
||||
this.lastname = lastname;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return firstname;
|
||||
}
|
||||
|
||||
public void setFirstname(String firstname) {
|
||||
this.firstname = firstname;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,4 @@
|
||||
|
||||
keycloak.enabled=true
|
||||
keycloak.realm=baeldung
|
||||
keycloak.resource=baeldung-api
|
||||
keycloak.auth-server-url=http://localhost:8081
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.baeldung.keycloaktestcontainers;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.json.JacksonJsonParser;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import dasniko.testcontainers.keycloak.KeycloakContainer;
|
||||
import io.restassured.RestAssured;
|
||||
|
||||
@ContextConfiguration(initializers = { IntegrationTest.Initializer.class })
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public abstract class IntegrationTest {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationTest.class.getName());
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
static final KeycloakContainer keycloak = new KeycloakContainer().withRealmImportFile("keycloak/realm-export.json");
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
RestAssured.baseURI = "http://localhost:" + port;
|
||||
}
|
||||
|
||||
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
|
||||
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
|
||||
keycloak.start();
|
||||
TestPropertyValues.of("keycloak.auth-server-url=" + keycloak.getAuthServerUrl())
|
||||
.applyTo(configurableApplicationContext.getEnvironment());
|
||||
}
|
||||
}
|
||||
|
||||
protected String getJaneDoeBearer() {
|
||||
|
||||
try {
|
||||
URI authorizationURI = new URIBuilder(keycloak.getAuthServerUrl() + "/realms/baeldung/protocol/openid-connect/token").build();
|
||||
WebClient webclient = WebClient.builder()
|
||||
.build();
|
||||
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
|
||||
formData.put("grant_type", Collections.singletonList("password"));
|
||||
formData.put("client_id", Collections.singletonList("baeldung-api"));
|
||||
formData.put("username", Collections.singletonList("jane.doe@baeldung.com"));
|
||||
formData.put("password", Collections.singletonList("s3cr3t"));
|
||||
|
||||
String result = webclient.post()
|
||||
.uri(authorizationURI)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.body(BodyInserters.fromFormData(formData))
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.block();
|
||||
|
||||
JacksonJsonParser jsonParser = new JacksonJsonParser();
|
||||
|
||||
return "Bearer " + jsonParser.parseMap(result)
|
||||
.get("access_token")
|
||||
.toString();
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error("Can't obtain an access token from Keycloak!", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.keycloaktestcontainers;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class UserControllerIntegrationTest extends IntegrationTest {
|
||||
|
||||
@Test
|
||||
void givenAuthenticatedUser_whenGetMe_shouldReturnMyInfo() {
|
||||
|
||||
given().header("Authorization", getJaneDoeBearer())
|
||||
.when()
|
||||
.get("/users/me")
|
||||
.then()
|
||||
.body("username", equalTo("janedoe"))
|
||||
.body("lastname", equalTo("Doe"))
|
||||
.body("firstname", equalTo("Jane"))
|
||||
.body("email", equalTo("jane.doe@baeldung.com"));
|
||||
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.baeldung.redistestcontainers.service;
|
||||
|
||||
import com.baeldung.redistestcontainers.hash.Product;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
@SpringBootTest
|
||||
public class ProductServiceIntegrationTest {
|
||||
|
||||
static {
|
||||
GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:5.0.3-alpine"))
|
||||
.withExposedPorts(6379);
|
||||
redis.start();
|
||||
System.setProperty("spring.redis.host", redis.getHost());
|
||||
System.setProperty("spring.redis.port", redis.getMappedPort(6379).toString());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ProductService productService;
|
||||
|
||||
@Test
|
||||
void givenProductCreated_whenGettingProductById_thenProductExistsAndHasSameProperties() {
|
||||
Product product = new Product("1", "Test Product", 10.0);
|
||||
productService.createProduct(product);
|
||||
Product productFromDb = productService.getProduct("1");
|
||||
assertEquals("1", productFromDb.getId());
|
||||
assertEquals("Test Product", productFromDb.getName());
|
||||
assertEquals(10.0, productFromDb.getPrice());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenProductCreatedAndUpdated_whenGettingTheProduct_thenUpdatedProductReturned() {
|
||||
Product product = new Product("1", "Test Product", 10.0);
|
||||
productService.createProduct(product);
|
||||
Product productFromDb = productService.getProduct("1");
|
||||
assertEquals("1", productFromDb.getId());
|
||||
assertEquals("Test Product", productFromDb.getName());
|
||||
assertEquals(10.0, productFromDb.getPrice());
|
||||
productFromDb.setName("Updated Product");
|
||||
productFromDb.setPrice(20.0);
|
||||
productService.updateProduct(productFromDb);
|
||||
Product updatedProductFromDb = productService.getProduct("1");
|
||||
assertEquals("Updated Product", updatedProductFromDb.getName());
|
||||
assertEquals(20.0, updatedProductFromDb.getPrice());
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenProductCreatedAndDeleted_whenGettingTheProduct_thenNoProductReturned() {
|
||||
Product product = new Product("1", "Test Product", 10.0);
|
||||
productService.createProduct(product);
|
||||
Product productFromDb = productService.getProduct("1");
|
||||
assertEquals("1", productFromDb.getId());
|
||||
assertEquals("Test Product", productFromDb.getName());
|
||||
assertEquals(10.0, productFromDb.getPrice());
|
||||
productService.deleteProduct("1");
|
||||
Product deletedProductFromDb = productService.getProduct("1");
|
||||
assertNull(deletedProductFromDb);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenProductCreated_whenGettingProductById_thenSameProductReturned() {
|
||||
Product product = new Product("1", "Test Product", 10.0);
|
||||
productService.createProduct(product);
|
||||
Product productFromDb = productService.getProduct("1");
|
||||
assertEquals("1", productFromDb.getId());
|
||||
assertEquals("Test Product", productFromDb.getName());
|
||||
assertEquals(10.0, productFromDb.getPrice());
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
# logging.level.com.baeldung.testloglevel=DEBUG
|
||||
|
||||
# logging.level.root=INFO
|
||||
keycloak.enabled=true
|
||||
keycloak.realm=baeldung
|
||||
keycloak.resource=baeldung-api
|
||||
keycloak.auth-server-url=http://localhost:8081
|
||||
|
||||
+1803
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user