JAVA-3541: Move spring-5-mvc into spring-web-modules
This commit is contained in:
20
spring-web-modules/spring-5-mvc/.gitignore
vendored
Normal file
20
spring-web-modules/spring-5-mvc/.gitignore
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
.settings/
|
||||
.classpath
|
||||
.project
|
||||
target/
|
||||
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
8
spring-web-modules/spring-5-mvc/README.md
Normal file
8
spring-web-modules/spring-5-mvc/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
## Spring 5 MVC
|
||||
|
||||
This module contains articles about Spring 5 model-view-controller (MVC) pattern
|
||||
|
||||
### Relevant Articles:
|
||||
- [Spring MVC Streaming and SSE Request Processing](https://www.baeldung.com/spring-mvc-sse-streams)
|
||||
- [Interface Driven Controllers in Spring](https://www.baeldung.com/spring-interface-driven-controllers)
|
||||
- [Returning Plain HTML From a Spring MVC Controller](https://www.baeldung.com/spring-mvc-return-html)
|
||||
99
spring-web-modules/spring-5-mvc/pom.xml
Normal file
99
spring-web-modules/spring-5-mvc/pom.xml
Normal file
@@ -0,0 +1,99 @@
|
||||
<?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-5-mvc</artifactId>
|
||||
<name>spring-5-mvc</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>spring 5 MVC sample project about new features</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<!-- utils -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</dependency>
|
||||
<!-- runtime and test scoped -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jayway.restassured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<version>${jayway-rest-assured.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.javafaker</groupId>
|
||||
<artifactId>javafaker</artifactId>
|
||||
<version>${javafaker.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<jayway-rest-assured.version>2.9.0</jayway-rest-assured.version>
|
||||
<httpclient.version>4.5.8</httpclient.version>
|
||||
<start-class>com.baeldung.Spring5Application</start-class>
|
||||
<javafaker.version>0.18</javafaker.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.baeldung;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String GENERIC_EXCEPTION = "Exception encountered!";
|
||||
|
||||
/**
|
||||
* API endpoints.
|
||||
*/
|
||||
public static final String API_RBE = "/rbe";
|
||||
public static final String API_SSE = "/sse";
|
||||
public static final String API_SRB = "/srb";
|
||||
|
||||
/**
|
||||
* API Responses.
|
||||
*/
|
||||
public static final String API_RBE_MSG = "I Was Sent From a Response Body Emitter!";
|
||||
public static final String API_SSE_MSG = "I Was Sent From a Sse!";
|
||||
public static final String API_SRB_MSG = "I Was Sent From a Streaming Response Body!";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
|
||||
@SpringBootApplication( exclude = SecurityAutoConfiguration.class)
|
||||
public class Spring5Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Spring5Application.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.baeldung.html;
|
||||
|
||||
import org.springframework.boot.*;
|
||||
import org.springframework.boot.autoconfigure.*;
|
||||
|
||||
@SpringBootApplication
|
||||
public class HtmlApplication
|
||||
{
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HtmlApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.html;
|
||||
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.stereotype.*;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Controller
|
||||
public class HtmlController
|
||||
{
|
||||
@GetMapping(value = "/welcome", produces = MediaType.TEXT_HTML_VALUE)
|
||||
@ResponseBody
|
||||
public String welcomeAsHTML()
|
||||
{
|
||||
return "<html>\n" + "<header><title>Welcome</title></header>\n" +
|
||||
"<body>\n" + "Hello world\n" + "</body>\n" + "</html>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.baeldung.idc;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.baeldung.idc;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Book {
|
||||
|
||||
private final int id;
|
||||
|
||||
private final String title;
|
||||
|
||||
private final String author;
|
||||
|
||||
private final String genre;
|
||||
|
||||
public Book() {
|
||||
this(-1, "", "", "");
|
||||
}
|
||||
|
||||
public Book(int id, String title, String author, String genre) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.author = author;
|
||||
this.genre = genre;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the title
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the author
|
||||
*/
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the genre
|
||||
*/
|
||||
public String getGenre() {
|
||||
return genre;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.baeldung.idc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/book")
|
||||
public class BookController implements BookOperations {
|
||||
|
||||
private BookRepository repo;
|
||||
|
||||
public BookController(BookRepository repo) {
|
||||
this.repo = repo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> getAll() {
|
||||
return repo.getItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Book> getById(int id) {
|
||||
return repo.getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(Book book, int id) {
|
||||
repo.save(id, book);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.idc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@RequestMapping("/default")
|
||||
public interface BookOperations {
|
||||
|
||||
@GetMapping("/")
|
||||
List<Book> getAll();
|
||||
|
||||
@GetMapping("/{id}")
|
||||
Optional<Book> getById(@PathVariable int id);
|
||||
|
||||
@PostMapping("/save/{id}")
|
||||
public void save(@RequestBody Book book, @PathVariable int id);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.baeldung.idc;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.github.javafaker.Faker;
|
||||
|
||||
/**
|
||||
* Repository for storing the books.
|
||||
*
|
||||
* It serves just for illustrative purposes and is completely in-memory. It uses Java Faker library in order to generate data.
|
||||
*
|
||||
* @author A.Shcherbakov
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class BookRepository {
|
||||
|
||||
private List<Book> items;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
Faker faker = new Faker(Locale.ENGLISH);
|
||||
final com.github.javafaker.Book book = faker.book();
|
||||
this.items = IntStream.range(1, faker.random()
|
||||
.nextInt(10, 20))
|
||||
.mapToObj(i -> new Book(i, book.title(), book.author(), book.genre()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
public List<Book> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public Optional<Book> getById(int id) {
|
||||
return this.items.stream()
|
||||
.filter(item -> id == item.getId())
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void save(int id, Book book) {
|
||||
IntStream.range(0, items.size())
|
||||
.filter(i -> items.get(i)
|
||||
.getId() == id)
|
||||
.findFirst()
|
||||
.ifPresent(i -> this.items.set(i, book));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.baeldung.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Foo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Foo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Foo(final String name) {
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Foo(final long id, final String name) {
|
||||
super();
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Foo other = (Foo) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Foo [name=" + name + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.persistence;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.baeldung.model.Foo;
|
||||
|
||||
@Component
|
||||
public class DataSetupBean implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private FooRepository repo;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
IntStream.range(1, 5).forEach(i -> repo.save(new Foo(randomAlphabetic(8))));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.persistence;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
import com.baeldung.model.Foo;
|
||||
|
||||
public interface FooRepository extends JpaRepository<Foo, Long>, JpaSpecificationExecutor<Foo> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.baeldung.web;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.baeldung.model.Foo;
|
||||
import com.baeldung.persistence.FooRepository;
|
||||
|
||||
@RestController
|
||||
public class FooController {
|
||||
|
||||
@Autowired
|
||||
private FooRepository repo;
|
||||
|
||||
// API - read
|
||||
|
||||
@GetMapping("/foos/{id}")
|
||||
@Validated
|
||||
public Foo findById(@PathVariable @Min(0) final long id) {
|
||||
return repo.findById(id).orElse(null);
|
||||
}
|
||||
|
||||
@GetMapping("/foos")
|
||||
public List<Foo> findAll() {
|
||||
return repo.findAll();
|
||||
}
|
||||
|
||||
@GetMapping( value="/foos", params = { "page", "size" })
|
||||
@Validated
|
||||
public List<Foo> findPaginated(@RequestParam("page") @Min(0) final int page, @Max(100) @RequestParam("size") final int size) {
|
||||
return repo.findAll(PageRequest.of(page, size)).getContent();
|
||||
}
|
||||
|
||||
// API - write
|
||||
|
||||
@PutMapping("/foos/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public Foo update(@PathVariable("id") final String id, @RequestBody final Foo foo) {
|
||||
return foo;
|
||||
}
|
||||
|
||||
@PostMapping("/foos")
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public void create( @RequestBody final Foo foo) {
|
||||
if (null == foo || null == foo.getName()) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST," 'name' is required");
|
||||
}
|
||||
repo.save(foo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.baeldung.web;
|
||||
|
||||
import com.baeldung.Constants;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
|
||||
|
||||
@Controller
|
||||
public class ResponseBodyEmitterController {
|
||||
private ExecutorService nonBlockingService = Executors.newCachedThreadPool();
|
||||
|
||||
@GetMapping(Constants.API_RBE)
|
||||
public ResponseEntity<ResponseBodyEmitter> handleRbe() {
|
||||
ResponseBodyEmitter emitter = new ResponseBodyEmitter();
|
||||
|
||||
nonBlockingService.execute(() -> {
|
||||
try {
|
||||
emitter.send(Constants.API_RBE_MSG + " @ " + new Date(), MediaType.TEXT_PLAIN);
|
||||
emitter.complete();
|
||||
} catch (Exception ex) {
|
||||
System.out.println(Constants.GENERIC_EXCEPTION);
|
||||
emitter.completeWithError(ex);
|
||||
}
|
||||
});
|
||||
|
||||
return new ResponseEntity(emitter, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.baeldung.web;
|
||||
|
||||
import java.time.LocalTime;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter.SseEventBuilder;
|
||||
|
||||
import com.baeldung.Constants;
|
||||
|
||||
@Controller
|
||||
public class SseEmitterController {
|
||||
private ExecutorService nonBlockingService = Executors.newCachedThreadPool();
|
||||
|
||||
@GetMapping(Constants.API_SSE)
|
||||
public SseEmitter handleSse() {
|
||||
SseEmitter emitter = new SseEmitter();
|
||||
|
||||
nonBlockingService.execute(() -> {
|
||||
try {
|
||||
emitter.send(Constants.API_SSE_MSG + " @ " + new Date());
|
||||
emitter.complete();
|
||||
} catch (Exception ex) {
|
||||
System.out.println(Constants.GENERIC_EXCEPTION);
|
||||
emitter.completeWithError(ex);
|
||||
}
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@GetMapping("/stream-sse-mvc")
|
||||
public SseEmitter streamSseMvc() {
|
||||
SseEmitter emitter = new SseEmitter();
|
||||
ExecutorService sseMvcExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
sseMvcExecutor.execute(() -> {
|
||||
try {
|
||||
for (int i = 0; true; i++) {
|
||||
SseEventBuilder event = SseEmitter.event()
|
||||
.data("SSE MVC - " + LocalTime.now()
|
||||
.toString())
|
||||
.id(String.valueOf(i))
|
||||
.name("sse event - mvc");
|
||||
emitter.send(event);
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
emitter.completeWithError(ex);
|
||||
}
|
||||
});
|
||||
return emitter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.baeldung.web;
|
||||
|
||||
import com.baeldung.Constants;
|
||||
import java.util.Date;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
|
||||
|
||||
@Controller
|
||||
public class StreamingResponseBodyController {
|
||||
|
||||
@GetMapping(Constants.API_SRB)
|
||||
public ResponseEntity<StreamingResponseBody> handleRbe() {
|
||||
StreamingResponseBody stream = out -> {
|
||||
String msg = Constants.API_SRB_MSG + " @ " + new Date();
|
||||
out.write(msg.getBytes());
|
||||
};
|
||||
return new ResponseEntity(stream, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
server.port=8081
|
||||
|
||||
logging.level.root=INFO
|
||||
@@ -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>
|
||||
@@ -0,0 +1,86 @@
|
||||
<%@taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
|
||||
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
|
||||
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
|
||||
|
||||
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Spring MVC Async</title>
|
||||
<link href="<c:url value="/resources/styles/style.css"/>" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h2>Spring MVC Async</h2>
|
||||
<div id="rbe"></div>
|
||||
<div id="sse"></div>
|
||||
<div id="srb"></div>
|
||||
</main>
|
||||
</body>
|
||||
<script>
|
||||
|
||||
/**
|
||||
* AJAX Helpers.
|
||||
*/
|
||||
|
||||
var xhr = function(url) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
try {
|
||||
var xmhr = new XMLHttpRequest();
|
||||
|
||||
//Listen for API Response
|
||||
xmhr.onreadystatechange = function() {
|
||||
if (xmhr.readyState == XMLHttpRequest.DONE && xmhr.status == 200) return resolve(xmhr.responseText);
|
||||
};
|
||||
|
||||
//Open connection
|
||||
xmhr.open("GET", url, true);
|
||||
//Additional headers as needed
|
||||
//x.withCredentials = true;
|
||||
//x.setRequestHeader("Accept", "application/json");
|
||||
//x.setRequestHeader("Content-Type", "text/plain");
|
||||
|
||||
//Perform the actual AJAX call
|
||||
xmhr.send();
|
||||
|
||||
} catch (ex) {
|
||||
reject("Exception: Oh CORS's you've made a mistake!");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* RBE
|
||||
*/
|
||||
|
||||
xhr('http://localhost:8080/rbe').then(function(success){
|
||||
var el = document.getElementById('rbe');
|
||||
el.appendChild(document.createTextNode(success));
|
||||
el.appendChild(document.createElement('br'))
|
||||
});
|
||||
|
||||
/**
|
||||
* SSE
|
||||
*/
|
||||
|
||||
var sse = new EventSource('http://localhost:8080/sse');
|
||||
sse.onmessage = function (evt) {
|
||||
var el = document.getElementById('sse');
|
||||
el.appendChild(document.createTextNode(evt.data));
|
||||
el.appendChild(document.createElement('br'))
|
||||
};
|
||||
|
||||
/**
|
||||
* SRB
|
||||
*/
|
||||
|
||||
xhr('http://localhost:8080/srb').then(function(success){
|
||||
var el = document.getElementById('srb');
|
||||
el.appendChild(document.createTextNode(success));
|
||||
el.appendChild(document.createElement('br'))
|
||||
});
|
||||
|
||||
</script>
|
||||
</html>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Spring Functional Application</display-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>functional</servlet-name>
|
||||
<servlet-class>com.baeldung.functional.RootServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
<async-supported>true</async-supported>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>functional</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.baeldung;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import com.jayway.restassured.RestAssured;
|
||||
import com.jayway.restassured.response.Response;
|
||||
import com.jayway.restassured.specification.RequestSpecification;
|
||||
|
||||
public class LiveTest {
|
||||
|
||||
private static String APP_ROOT = "http://localhost:8081";
|
||||
|
||||
@Test
|
||||
public void givenUser_whenResourceCreatedWithNullName_then400BadRequest() {
|
||||
final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString())
|
||||
.body(resourceWithNullName())
|
||||
.post(APP_ROOT + "/foos");
|
||||
assertEquals(400, response.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenUser_whenResourceCreated_then201Created() {
|
||||
final Response response = givenAuth("user", "pass").contentType(MediaType.APPLICATION_JSON.toString())
|
||||
.body(resourceString())
|
||||
.post(APP_ROOT + "/foos");
|
||||
assertEquals(201, response.getStatusCode());
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void givenUser_whenGetAllFoos_thenOK() {
|
||||
final Response response = givenAuth("user", "pass").get(APP_ROOT + "/foos");
|
||||
assertEquals(200, response.getStatusCode());
|
||||
}*/
|
||||
|
||||
//
|
||||
|
||||
private final String resourceWithNullName() {
|
||||
return "{\"name\":null}";
|
||||
}
|
||||
|
||||
private final String resourceString() {
|
||||
return "{\"name\":\"" + randomAlphabetic(8) + "\"}";
|
||||
}
|
||||
|
||||
private final RequestSpecification givenAuth(String username, String password) {
|
||||
return RestAssured.given()
|
||||
.auth()
|
||||
.preemptive()
|
||||
.basic(username, password);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = Spring5Application.class)
|
||||
public class Spring5ApplicationIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.baeldung.html;
|
||||
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.springframework.beans.factory.annotation.*;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.*;
|
||||
import org.springframework.test.web.servlet.*;
|
||||
import org.springframework.test.web.servlet.request.*;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@WebMvcTest(HtmlController.class)
|
||||
class HtmlControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private final String expectedHtmlResponse =
|
||||
"<html>\n" + "<header><title>Welcome</title></header>\n" +
|
||||
"<body>\n" + "Hello world\n" + "</body>\n" + "</html>";
|
||||
|
||||
@Test
|
||||
void whenGETRequestToCorrectURL_thenReturnCorrectWelcomeMessage() throws Exception {
|
||||
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/welcome"))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn();
|
||||
|
||||
String resultDOW = result.getResponse().getContentAsString();
|
||||
assertEquals(expectedHtmlResponse, resultDOW);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user