Merge branch 'master' into JAVA-3524
This commit is contained in:
@@ -23,8 +23,10 @@
|
||||
<module>spring-mvc-forms-thymeleaf</module>
|
||||
<module>spring-mvc-java</module>
|
||||
<module>spring-mvc-java-2</module>
|
||||
<module>spring-rest-http</module>
|
||||
<module>spring-thymeleaf</module>
|
||||
<module>spring-thymeleaf-2</module>
|
||||
<module>spring-thymeleaf-3</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
## Spring REST HTTP
|
||||
|
||||
This module contains articles about HTTP in REST APIs with Spring
|
||||
|
||||
### The Course
|
||||
The "REST With Spring" Classes: http://bit.ly/restwithspring
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Guide to UriComponentsBuilder in Spring](https://www.baeldung.com/spring-uricomponentsbuilder)
|
||||
- [How to Set a Header on a Response with Spring 5](https://www.baeldung.com/spring-response-header) - The tests contained for this article rely on the sample application within the [spring-resttemplate](/spring-resttemplate) module
|
||||
- [Returning Custom Status Codes from Spring Controllers](https://www.baeldung.com/spring-mvc-controller-custom-http-status-code)
|
||||
- [Spring RequestMapping](https://www.baeldung.com/spring-requestmapping)
|
||||
- [Guide to DeferredResult in Spring](https://www.baeldung.com/spring-deferred-result)
|
||||
- [Using JSON Patch in Spring REST APIs](https://www.baeldung.com/spring-rest-json-patch)
|
||||
- [OpenAPI JSON Objects as Query Parameters](https://www.baeldung.com/openapi-json-query-parameters)
|
||||
- [Dates in OpenAPI Files](https://www.baeldung.com/openapi-dates)
|
||||
@@ -0,0 +1,62 @@
|
||||
<?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-rest-http</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<name>spring-rest-http</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<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-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-oxm</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>${xstream.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.java-json-tools</groupId>
|
||||
<artifactId>json-patch</artifactId>
|
||||
<version>${jsonpatch.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
<properties>
|
||||
<xstream.version>1.4.9</xstream.version>
|
||||
<jsonpatch.version>1.12</jsonpatch.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class CustomerSpringBootRestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CustomerSpringBootRestApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.baeldung.config;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
import org.springframework.oxm.xstream.XStreamMarshaller;
|
||||
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Please note that main web configuration is in src/main/webapp/WEB-INF/api-servlet.xml
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@ComponentScan({ "com.baeldung.web.controller.status", "com.baeldung.requestmapping" })
|
||||
public class MvcConfig implements WebMvcConfigurer {
|
||||
|
||||
public MvcConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
|
||||
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
|
||||
builder.indentOutput(true)
|
||||
.dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
|
||||
configurer.defaultContentType(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**");
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.baeldung.controllers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
|
||||
@RestController
|
||||
public class DeferredResultController {
|
||||
|
||||
private final static Logger LOG = LoggerFactory.getLogger(DeferredResultController.class);
|
||||
|
||||
@GetMapping("/async-deferredresult")
|
||||
public DeferredResult<ResponseEntity<?>> handleReqDefResult(Model model) {
|
||||
LOG.info("Received async-deferredresult request");
|
||||
DeferredResult<ResponseEntity<?>> output = new DeferredResult<>();
|
||||
ForkJoinPool.commonPool().submit(() -> {
|
||||
LOG.info("Processing in separate thread");
|
||||
try {
|
||||
Thread.sleep(6000);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
output.setResult(ResponseEntity.ok("ok"));
|
||||
});
|
||||
LOG.info("servlet thread freed");
|
||||
return output;
|
||||
}
|
||||
|
||||
public DeferredResult<ResponseEntity<?>> handleReqWithTimeouts(Model model) {
|
||||
LOG.info("Received async request with a configured timeout");
|
||||
DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>(500l);
|
||||
deferredResult.onTimeout(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deferredResult.setErrorResult(
|
||||
ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body("Request timeout occurred."));
|
||||
}
|
||||
});
|
||||
ForkJoinPool.commonPool().submit(() -> {
|
||||
LOG.info("Processing in separate thread");
|
||||
try {
|
||||
Thread.sleep(600l);
|
||||
deferredResult.setResult(ResponseEntity.ok("ok"));
|
||||
} catch (InterruptedException e) {
|
||||
LOG.info("Request processing interrupted");
|
||||
deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("INTERNAL_SERVER_ERROR occurred."));
|
||||
}
|
||||
|
||||
});
|
||||
LOG.info("servlet thread freed");
|
||||
return deferredResult;
|
||||
}
|
||||
|
||||
public DeferredResult<ResponseEntity<?>> handleAsyncFailedRequest(Model model) {
|
||||
DeferredResult<ResponseEntity<?>> deferredResult = new DeferredResult<>();
|
||||
ForkJoinPool.commonPool().submit(() -> {
|
||||
try {
|
||||
// Exception occurred in processing
|
||||
throw new Exception();
|
||||
} catch (Exception e) {
|
||||
LOG.info("Request processing failed");
|
||||
deferredResult.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body("INTERNAL_SERVER_ERROR occurred."));
|
||||
}
|
||||
});
|
||||
return deferredResult;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.baeldung.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Customer {
|
||||
private String id;
|
||||
private String telephone;
|
||||
private List<String> favorites;
|
||||
private Map<String, Boolean> communicationPreferences;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String id, String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
|
||||
this(telephone, favorites, communicationPreferences);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer(String telephone, List<String> favorites, Map<String, Boolean> communicationPreferences) {
|
||||
this.telephone = telephone;
|
||||
this.favorites = favorites;
|
||||
this.communicationPreferences = communicationPreferences;
|
||||
}
|
||||
|
||||
public static Customer fromCustomer(Customer customer) {
|
||||
return new Customer(customer.getId(), customer.getTelephone(), customer.getFavorites(), customer.getCommunicationPreferences());
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTelephone() {
|
||||
return telephone;
|
||||
}
|
||||
|
||||
public void setTelephone(String telephone) {
|
||||
this.telephone = telephone;
|
||||
}
|
||||
|
||||
public Map<String, Boolean> getCommunicationPreferences() {
|
||||
return communicationPreferences;
|
||||
}
|
||||
|
||||
public void setCommunicationPreferences(Map<String, Boolean> communicationPreferences) {
|
||||
this.communicationPreferences = communicationPreferences;
|
||||
}
|
||||
|
||||
public List<String> getFavorites() {
|
||||
return favorites;
|
||||
}
|
||||
|
||||
public void setFavorites(List<String> favorites) {
|
||||
this.favorites = favorites;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof Customer)) {
|
||||
return false;
|
||||
}
|
||||
Customer customer = (Customer) o;
|
||||
return Objects.equals(id, customer.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.baeldung.requestmapping;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/ex")
|
||||
public class BarMappingExamplesController {
|
||||
|
||||
public BarMappingExamplesController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// with @RequestParam
|
||||
|
||||
@RequestMapping(value = "/bars")
|
||||
@ResponseBody
|
||||
public String getBarBySimplePathWithRequestParam(@RequestParam("id") final long id) {
|
||||
return "Get a specific Bar with id=" + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/bars", params = "id")
|
||||
@ResponseBody
|
||||
public String getBarBySimplePathWithExplicitRequestParam(@RequestParam("id") final long id) {
|
||||
return "Get a specific Bar with id=" + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/bars", params = { "id", "second" })
|
||||
@ResponseBody
|
||||
public String getBarBySimplePathWithExplicitRequestParams(@RequestParam("id") final long id) {
|
||||
return "Get a specific Bar with id=" + id;
|
||||
}
|
||||
|
||||
// with @PathVariable
|
||||
|
||||
@RequestMapping(value = "/bars/{numericId:[\\d]+}")
|
||||
@ResponseBody
|
||||
public String getBarsBySimplePathWithPathVariable(@PathVariable final long numericId) {
|
||||
return "Get a specific Bar with id=" + numericId;
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.baeldung.requestmapping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.baeldung.web.dto.Bazz;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/bazz")
|
||||
public class BazzNewMappingsExampleController {
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> getBazzs() throws JsonProcessingException{
|
||||
List<Bazz> data = Arrays.asList(
|
||||
new Bazz("1", "Bazz1"),
|
||||
new Bazz("2", "Bazz2"),
|
||||
new Bazz("3", "Bazz3"),
|
||||
new Bazz("4", "Bazz4"));
|
||||
return new ResponseEntity<>(data, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<?> getBazz(@PathVariable String id){
|
||||
return new ResponseEntity<>(new Bazz(id, "Bazz"+id), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> newBazz(@RequestParam("name") String name){
|
||||
return new ResponseEntity<>(new Bazz("5", name), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<?> updateBazz(@PathVariable String id,
|
||||
@RequestParam("name") String name){
|
||||
return new ResponseEntity<>(new Bazz(id, name), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<?> deleteBazz(@PathVariable String id){
|
||||
return new ResponseEntity<>(new Bazz(id), HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
package com.baeldung.requestmapping;
|
||||
|
||||
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.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value = "/ex")
|
||||
public class FooMappingExamplesController {
|
||||
|
||||
public FooMappingExamplesController() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
// mapping examples
|
||||
|
||||
@RequestMapping(value = "/foos")
|
||||
@ResponseBody
|
||||
public String getFoosBySimplePath() {
|
||||
return "Simple Get some Foos";
|
||||
}
|
||||
|
||||
// with @PathVariable
|
||||
|
||||
@RequestMapping(value = "/foos/{id}")
|
||||
@ResponseBody
|
||||
public String getFoosBySimplePathWithPathVariable(@PathVariable final long id) {
|
||||
return "Get a specific Foo with id=" + id;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/foos/{fooid}/bar/{barid}")
|
||||
@ResponseBody
|
||||
public String getFoosBySimplePathWithPathVariables(@PathVariable final long fooid, @PathVariable final long barid) {
|
||||
return "Get a specific Bar with id=" + barid + " from a Foo with id=" + fooid;
|
||||
}
|
||||
|
||||
// other HTTP verbs
|
||||
|
||||
@RequestMapping(value = "/foos", method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public String postFoos() {
|
||||
return "Post some Foos";
|
||||
}
|
||||
|
||||
// with headers
|
||||
|
||||
@RequestMapping(value = "/foos", headers = "key=val")
|
||||
@ResponseBody
|
||||
public String getFoosWithHeader() {
|
||||
return "Get some Foos with Header";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/foos", headers = { "key1=val1", "key2=val2" })
|
||||
@ResponseBody
|
||||
public String getFoosWithHeaders() {
|
||||
return "Get some Foos with Header";
|
||||
}
|
||||
|
||||
// @RequestMapping(value = "/foos", method = RequestMethod.GET, headers = "Accept=application/json")
|
||||
// @ResponseBody
|
||||
// public String getFoosAsJsonFromBrowser() {
|
||||
// return "Get some Foos with Header Old";
|
||||
// }
|
||||
|
||||
@RequestMapping(value = "/foos", produces = { "application/json", "application/xml" })
|
||||
@ResponseBody
|
||||
public String getFoosAsJsonFromREST() {
|
||||
return "Get some Foos with Header New";
|
||||
}
|
||||
|
||||
// advanced - multiple mappings
|
||||
|
||||
@RequestMapping(value = { "/advanced/bars", "/advanced/foos" })
|
||||
@ResponseBody
|
||||
public String getFoosOrBarsByPath() {
|
||||
return "Advanced - Get some Foos or Bars";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "*")
|
||||
@ResponseBody
|
||||
public String getFallback() {
|
||||
return "Fallback for GET Requests";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "*", method = { RequestMethod.GET, RequestMethod.POST })
|
||||
@ResponseBody
|
||||
public String allFallback() {
|
||||
return "Fallback for All Requests";
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/foos/multiple", method = { RequestMethod.PUT, RequestMethod.POST })
|
||||
@ResponseBody
|
||||
public String putAndPostFoos() {
|
||||
return "Advanced - PUT and POST within single method";
|
||||
}
|
||||
|
||||
// --- Ambiguous Mapping
|
||||
|
||||
@GetMapping(value = "foos/duplicate" )
|
||||
public ResponseEntity<String> duplicate() {
|
||||
return new ResponseEntity<>("Duplicate", HttpStatus.OK);
|
||||
}
|
||||
|
||||
// uncomment for exception of type java.lang.IllegalStateException: Ambiguous mapping
|
||||
|
||||
// @GetMapping(value = "foos/duplicate" )
|
||||
// public String duplicateEx() {
|
||||
// return "Duplicate";
|
||||
// }
|
||||
|
||||
@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_XML_VALUE)
|
||||
public ResponseEntity<String> duplicateXml() {
|
||||
return new ResponseEntity<>("<message>Duplicate</message>", HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(value = "foos/duplicate", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<String> duplicateJson() {
|
||||
return new ResponseEntity<>("{\"message\":\"Duplicate\"}", HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
package com.baeldung.service;
|
||||
|
||||
public interface CustomerIdGenerator {
|
||||
int generateNextId();
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CustomerService {
|
||||
|
||||
Customer createCustomer(Customer customer);
|
||||
|
||||
Optional<Customer> findCustomer(String id);
|
||||
|
||||
void updateCustomer(Customer customer);
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Component
|
||||
public class CustomerIdGeneratorImpl implements CustomerIdGenerator {
|
||||
private static final AtomicInteger SEQUENCE = new AtomicInteger();
|
||||
|
||||
@Override
|
||||
public int generateNextId() {
|
||||
return SEQUENCE.incrementAndGet();
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class CustomerServiceImpl implements CustomerService {
|
||||
private CustomerIdGenerator customerIdGenerator;
|
||||
private List<Customer> customers = new ArrayList<>();
|
||||
|
||||
@Autowired
|
||||
public CustomerServiceImpl(CustomerIdGenerator customerIdGenerator) {
|
||||
this.customerIdGenerator = customerIdGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Customer createCustomer(Customer customer) {
|
||||
customer.setId(Integer.toString(customerIdGenerator.generateNextId()));
|
||||
customers.add(customer);
|
||||
return customer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Customer> findCustomer(String id) {
|
||||
return customers.stream()
|
||||
.filter(customer -> customer.getId().equals(id))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCustomer(Customer customer) {
|
||||
customers.set(customers.indexOf(customer), customer);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.baeldung.web.controller.customer;
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerService;
|
||||
import com.baeldung.web.exception.CustomerNotFoundException;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.fge.jsonpatch.JsonPatch;
|
||||
import com.github.fge.jsonpatch.JsonPatchException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(value = "/customers")
|
||||
public class CustomerRestController {
|
||||
private CustomerService customerService;
|
||||
private ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Autowired
|
||||
public CustomerRestController(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
|
||||
public ResponseEntity<Customer> createCustomer(@RequestBody Customer customer) {
|
||||
Customer customerCreated = customerService.createCustomer(customer);
|
||||
URI location = ServletUriComponentsBuilder.fromCurrentRequest()
|
||||
.path("/{id}")
|
||||
.buildAndExpand(customerCreated.getId())
|
||||
.toUri();
|
||||
return ResponseEntity.created(location).build();
|
||||
}
|
||||
|
||||
@PatchMapping(path = "/{id}", consumes = "application/json-patch+json")
|
||||
public ResponseEntity<Customer> updateCustomer(@PathVariable String id,
|
||||
@RequestBody JsonPatch patch) {
|
||||
try {
|
||||
Customer customer = customerService.findCustomer(id).orElseThrow(CustomerNotFoundException::new);
|
||||
Customer customerPatched = applyPatchToCustomer(patch, customer);
|
||||
customerService.updateCustomer(customerPatched);
|
||||
|
||||
return ResponseEntity.ok(customerPatched);
|
||||
} catch (CustomerNotFoundException e) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
|
||||
} catch (JsonPatchException | JsonProcessingException e) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
private Customer applyPatchToCustomer(JsonPatch patch, Customer targetCustomer) throws JsonPatchException, JsonProcessingException {
|
||||
JsonNode patched = patch.apply(objectMapper.convertValue(targetCustomer, JsonNode.class));
|
||||
return objectMapper.treeToValue(patched, Customer.class);
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.baeldung.web.controller.status;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class ExampleController {
|
||||
|
||||
@RequestMapping(value = "/controller", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public ResponseEntity sendViaResponseEntity() {
|
||||
return new ResponseEntity(HttpStatus.NOT_ACCEPTABLE);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/exception", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
public ResponseEntity sendViaException() {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.baeldung.web.controller.status;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "To show an example of a custom message")
|
||||
public class ForbiddenException extends RuntimeException {
|
||||
private static final long serialVersionUID = 6826605655586311552L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.baeldung.web.dto;
|
||||
|
||||
public class Bazz {
|
||||
|
||||
|
||||
public String id;
|
||||
public String name;
|
||||
|
||||
public Bazz(String id){
|
||||
this.id = id;
|
||||
}
|
||||
public Bazz(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Bazz [id=" + id + ", name=" + name + "]";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.baeldung.web.dto;
|
||||
|
||||
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||
|
||||
@XStreamAlias("Foo")
|
||||
public class Foo {
|
||||
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 long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.baeldung.web.exception;
|
||||
|
||||
public class CustomerNotFoundException extends RuntimeException {
|
||||
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: API Title
|
||||
description: This is a sample API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://host/
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Get Users
|
||||
operationId: getUsers
|
||||
responses:
|
||||
200:
|
||||
description: Valid input
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
components:
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
createdAt:
|
||||
type: string
|
||||
format: date
|
||||
description: Creation date
|
||||
example: "2021-01-30"
|
||||
username:
|
||||
type: string
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: API Title
|
||||
description: This is a sample API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://host/
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Get Users
|
||||
operationId: getUsers
|
||||
responses:
|
||||
200:
|
||||
description: Valid input
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
components:
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
customDate:
|
||||
type: string
|
||||
pattern: '^\d{4}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])$'
|
||||
description: Custom date
|
||||
example: "20210130"
|
||||
username:
|
||||
type: string
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: API Title
|
||||
description: This is a sample API.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: https://host/
|
||||
paths:
|
||||
/users:
|
||||
get:
|
||||
summary: Get Users
|
||||
operationId: getUsers
|
||||
responses:
|
||||
200:
|
||||
description: Valid input
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
components:
|
||||
schemas:
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Creation date and time
|
||||
example: "2021-01-30T08:30:00Z"
|
||||
username:
|
||||
type: string
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
swagger: "2.0"
|
||||
info:
|
||||
description: "This is a sample server."
|
||||
version: "1.0.0"
|
||||
title: "Sample API to send JSON objects as query parameters using OpenAPI 2"
|
||||
tags:
|
||||
- name: "tickets"
|
||||
description: "Send Tickets as JSON Objects"
|
||||
schemes:
|
||||
- "https"
|
||||
- "http"
|
||||
paths:
|
||||
/tickets:
|
||||
get:
|
||||
tags:
|
||||
- "tickets"
|
||||
summary: "Send an JSON Object as a query param"
|
||||
parameters:
|
||||
- name: "params"
|
||||
in: "path"
|
||||
description: "{\"type\":\"foo\",\"color\":\"green\"}"
|
||||
required: true
|
||||
type: "string"
|
||||
responses:
|
||||
"200":
|
||||
description: "Successful operation"
|
||||
"401":
|
||||
description: "Unauthorized"
|
||||
"403":
|
||||
description: "Forbidden"
|
||||
"404":
|
||||
description: "Not found"
|
||||
post:
|
||||
tags:
|
||||
- "tickets"
|
||||
summary: "Send an JSON Object in body"
|
||||
parameters:
|
||||
- name: "params"
|
||||
in: "body"
|
||||
description: "Parameter is an JSON object with the `type` and `color` properties that should be serialized as JSON {\"type\":\"foo\",\"color\":\"green\"}"
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: "Successful operation"
|
||||
"401":
|
||||
description: "Unauthorized"
|
||||
"403":
|
||||
description: "Forbidden"
|
||||
"404":
|
||||
description: "Not found"
|
||||
"405":
|
||||
description: "Invalid input"
|
||||
/tickets2:
|
||||
get:
|
||||
tags:
|
||||
- "tickets"
|
||||
summary: "Send an JSON Object in body of get reqest"
|
||||
parameters:
|
||||
- name: "params"
|
||||
in: "body"
|
||||
description: "Parameter is an JSON object with the `type` and `color` properties that should be serialized as JSON {\"type\":\"foo\",\"color\":\"green\"}"
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: "Successful operation"
|
||||
"401":
|
||||
description: "Unauthorized"
|
||||
"403":
|
||||
description: "Forbidden"
|
||||
"404":
|
||||
description: "Not found"
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Sample API to send JSON objects as query parameters using OpenAPI 3
|
||||
description: This is a sample server.
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: /api
|
||||
tags:
|
||||
- name: tickets
|
||||
description: Send Tickets as JSON Objects
|
||||
paths:
|
||||
/tickets:
|
||||
get:
|
||||
tags:
|
||||
- tickets
|
||||
summary: Send an JSON Object as a query param
|
||||
parameters:
|
||||
- name: params
|
||||
in: query
|
||||
description: '{"type":"foo","color":"green"}'
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: "string"
|
||||
color:
|
||||
type: "string"
|
||||
responses:
|
||||
200:
|
||||
description: Successful operation
|
||||
401:
|
||||
description: Unauthorized
|
||||
403:
|
||||
description: Forbidden
|
||||
404:
|
||||
description: Not found
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
|
||||
package com.baeldung.requestmapping;
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.baeldung.config.MvcConfig;
|
||||
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = MvcConfig.class)
|
||||
@WebAppConfiguration
|
||||
@AutoConfigureWebClient
|
||||
public class BazzNewMappingsExampleIntegrationTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGettingAllBazz_thenSuccess() throws Exception{
|
||||
mockMvc.perform(get("/bazz"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", hasSize(4)))
|
||||
.andExpect(jsonPath("$[1].id", is("2")))
|
||||
.andExpect(jsonPath("$[1].name", is("Bazz2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGettingABazz_thenSuccess() throws Exception{
|
||||
mockMvc.perform(get("/bazz/1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", is("1")))
|
||||
.andExpect(jsonPath("$.name", is("Bazz1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenAddingABazz_thenSuccess() throws Exception{
|
||||
mockMvc.perform(post("/bazz").param("name", "Bazz5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", is("5")))
|
||||
.andExpect(jsonPath("$.name", is("Bazz5")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdatingABazz_thenSuccess() throws Exception{
|
||||
mockMvc.perform(put("/bazz/5").param("name", "Bazz6"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", is("5")))
|
||||
.andExpect(jsonPath("$.name", is("Bazz6")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeletingABazz_thenSuccess() throws Exception{
|
||||
mockMvc.perform(delete("/bazz/5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.id", is("5")));
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.baeldung.requestmapping;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(FooMappingExamplesController.class)
|
||||
public class FooMappingExamplesControllerUnitTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void givenAcceptsJson_whenGetDuplicate_thenJsonResponseReturned() throws Exception {
|
||||
mvc.perform(get("/ex/foos/duplicate")
|
||||
.accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("{\"message\":\"Duplicate\"}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAcceptsXml_whenGetDuplicate_thenXmlResponseReturned() throws Exception {
|
||||
mvc.perform(get("/ex/foos/duplicate")
|
||||
.accept(MediaType.APPLICATION_XML))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string("<message>Duplicate</message>"));
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.baeldung.responseheaders;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class ResponseHeaderLiveTest {
|
||||
|
||||
private static final String BASE_URL = "http://localhost:8082/spring-rest";
|
||||
private static final String SINGLE_BASE_URL = BASE_URL + "/single-response-header";
|
||||
private static final String FILTER_BASE_URL = BASE_URL + "/filter-response-header";
|
||||
private static final String SERVICE_SINGLE_RESPONSE_HEADER = "Baeldung-Example-Header";
|
||||
private static final String SERVICE_FILTER_RESPONSE_HEADER = "Baeldung-Example-Filter-Header";
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate template;
|
||||
|
||||
@Test
|
||||
public void whenHttpServletResponseRequest_thenObtainResponseWithCorrectHeader() {
|
||||
final String requestUrl = "/http-servlet-response";
|
||||
ResponseEntity<String> response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-HttpServletResponse"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResponseEntityConstructorRequest_thenObtainResponseWithCorrectHeader() {
|
||||
final String requestUrl = "/response-entity-constructor";
|
||||
ResponseEntity<String> response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityContructor"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResponseEntityConstructorAndMultipleHeadersRequest_thenObtainResponseWithCorrectHeaders() {
|
||||
final String requestUrl = "/response-entity-contructor-multiple-headers";
|
||||
ResponseEntity<String> response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityConstructorAndHeaders"));
|
||||
assertThat(responseHeaders).containsEntry("Accept", Arrays.asList(MediaType.APPLICATION_JSON.toString()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResponseEntityBuilderRequest_thenObtainResponseWithCorrectHeader() {
|
||||
final String requestUrl = "/response-entity-builder";
|
||||
ResponseEntity<String> response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityBuilder"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenResponseEntityBuilderAndHttpHeadersRequest_thenObtainResponseWithCorrectHeader() {
|
||||
final String requestUrl = "/response-entity-builder-with-http-headers";
|
||||
ResponseEntity<String> response = template.getForEntity(SINGLE_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ResponseEntityBuilderWithHttpHeaders"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenFilterWithNoExtraHeaderRequest_thenObtainResponseWithCorrectHeader() {
|
||||
final String requestUrl = "/no-extra-header";
|
||||
ResponseEntity<String> response = template.getForEntity(FILTER_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_FILTER_RESPONSE_HEADER, Arrays.asList("Value-Filter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenFilterWithExtraHeaderRequest_thenObtainResponseWithCorrectHeaders() {
|
||||
final String requestUrl = "/extra-header";
|
||||
ResponseEntity<String> response = template.getForEntity(FILTER_BASE_URL + requestUrl, String.class);
|
||||
HttpHeaders responseHeaders = response.getHeaders();
|
||||
|
||||
assertThat(responseHeaders).isNotEmpty();
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_FILTER_RESPONSE_HEADER, Arrays.asList("Value-Filter"));
|
||||
assertThat(responseHeaders).containsEntry(SERVICE_SINGLE_RESPONSE_HEADER, Arrays.asList("Value-ExtraHeader"));
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class CustomerIdGeneratorImplUnitTest {
|
||||
|
||||
@Test
|
||||
public void givenIdGeneratedPreviously_whenGenerated_thenIdIsIncremented(){
|
||||
CustomerIdGenerator customerIdGenerator = new CustomerIdGeneratorImpl();
|
||||
int firstId = customerIdGenerator.generateNextId();
|
||||
assertThat(customerIdGenerator.generateNextId()).isEqualTo(++firstId);
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package com.baeldung.service.impl;
|
||||
|
||||
|
||||
import com.baeldung.model.Customer;
|
||||
import com.baeldung.service.CustomerIdGenerator;
|
||||
import com.baeldung.service.CustomerService;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import static com.baeldung.model.Customer.fromCustomer;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Optional.empty;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CustomerServiceImplUnitTest {
|
||||
|
||||
@Mock
|
||||
private CustomerIdGenerator mockCustomerIdGenerator;
|
||||
|
||||
private CustomerService customerService;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
customerService = new CustomerServiceImpl(mockCustomerIdGenerator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerIsCreated_thenNewCustomerDetailsAreCorrect() {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(1);
|
||||
|
||||
Customer newCustomer = customerService.createCustomer(customer);
|
||||
|
||||
assertThat(newCustomer.getId()).isEqualTo("1");
|
||||
assertThat(newCustomer.getTelephone()).isEqualTo("001-555-1234");
|
||||
assertThat(newCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(newCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenNonExistentCustomer_whenCustomerIsLookedUp_thenCustomerCanNotBeFound() {
|
||||
assertThat(customerService.findCustomer("CUST12345")).isEqualTo(empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerIsCreated_thenCustomerCanBeFound() {
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(7890);
|
||||
|
||||
customerService.createCustomer(customer);
|
||||
Customer lookedUpCustomer = customerService.findCustomer("7890").get();
|
||||
|
||||
assertThat(lookedUpCustomer.getId()).isEqualTo("7890");
|
||||
assertThat(lookedUpCustomer.getTelephone()).isEqualTo("001-555-1234");
|
||||
assertThat(lookedUpCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(lookedUpCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCustomerUpdated_thenDetailsUpdatedCorrectly() {
|
||||
given(mockCustomerIdGenerator.generateNextId()).willReturn(7890);
|
||||
Map<String, Boolean> communicationPreferences = new HashMap<>();
|
||||
communicationPreferences.put("post", true);
|
||||
communicationPreferences.put("email", true);
|
||||
Customer customer = new Customer("001-555-1234", asList("Milk", "Eggs"), communicationPreferences);
|
||||
Customer newCustomer = customerService.createCustomer(customer);
|
||||
|
||||
Customer customerWithUpdates = fromCustomer(newCustomer);
|
||||
customerWithUpdates.setTelephone("001-555-6789");
|
||||
customerService.updateCustomer(customerWithUpdates);
|
||||
Customer lookedUpCustomer = customerService.findCustomer("7890").get();
|
||||
|
||||
assertThat(lookedUpCustomer.getId()).isEqualTo("7890");
|
||||
assertThat(lookedUpCustomer.getTelephone()).isEqualTo("001-555-6789");
|
||||
assertThat(lookedUpCustomer.getFavorites()).containsExactly("Milk", "Eggs");
|
||||
assertThat(lookedUpCustomer.getCommunicationPreferences()).isEqualTo(communicationPreferences);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user