Nbosecker merge (#1989)

* Solr w Apache SolrJ

* Solr w Apache SolrJ

* updated test names and moved add to @before method

* create apache-solrj module, moved code from spring-data-solr

* More examples for indexing,delete,and query for solrj

* More examples for indexing,delete,and query for solrj

* Jackson Map Serialize/Deserialize

* Jackson Map Serialize/Deserialize

* Jackson version update

* keydeserializer code added

* keydeserializer code added

* remove explicit types from map instantion

* one objectmapper per class

* refactor to spring-rest-simple module

* Fix spring-rest-simple
This commit is contained in:
Grzegorz Piwowarek 2017-06-04 10:07:05 +02:00 committed by GitHub
parent 4b2e7a5e85
commit 29e3437545
34 changed files with 1248 additions and 123 deletions

View File

@ -174,6 +174,7 @@
<module>spring-rest-angular</module> <module>spring-rest-angular</module>
<module>spring-rest-docs</module> <module>spring-rest-docs</module>
<module>spring-rest</module> <module>spring-rest</module>
<module>spring-rest-simple</module>
<module>spring-security-cache-control</module> <module>spring-security-cache-control</module>
<module>spring-security-client/spring-security-jsp-authentication</module> <module>spring-security-client/spring-security-jsp-authentication</module>
<module>spring-security-client/spring-security-jsp-authorize</module> <module>spring-security-client/spring-security-jsp-authorize</module>

370
spring-rest-simple/pom.xml Normal file
View File

@ -0,0 +1,370 @@
<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</groupId>
<artifactId>spring-rest-simple</artifactId>
<version>0.1-SNAPSHOT</version>
<name>spring-rest-simple</name>
<packaging>war</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<dependencies>
<!-- Spring Boot Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</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-test</artifactId>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
<!-- web -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<scope>runtime</scope>
</dependency>
<!-- marshalling -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>${xstream.version}</version>
</dependency>
<!-- util -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<!-- logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<!-- <scope>runtime</scope> -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<!-- <scope>runtime</scope> --> <!-- some spring dependencies need to compile against jcl -->
</dependency>
<!-- okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${com.squareup.okhttp3.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
</dependency>
<!-- -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf-java.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.protobuf-java-format</groupId>
<artifactId>protobuf-java-format</artifactId>
<version>${protobuf-java-format.version}</version>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>${kryo.version}</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
</dependency>
</dependencies>
<build>
<finalName>spring-rest</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>3</forkCount>
<reuseForks>true</reuseForks>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
<exclude>**/*LongRunningUnitTest.java</exclude>
<exclude>**/*ManualTest.java</exclude>
<exclude>**/JdbcTest.java</exclude>
<exclude>**/*LiveTest.java</exclude>
</excludes>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>${cargo-maven2-plugin.version}</version>
<configuration>
<wait>true</wait>
<container>
<containerId>tomcat8x</containerId>
<type>embedded</type>
<systemProperties>
<!-- <provPersistenceTarget>cargo</provPersistenceTarget> -->
</systemProperties>
</container>
<configuration>
<properties>
<cargo.servlet.port>8082</cargo.servlet.port>
</properties>
</configuration>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-server</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
<includes>
<include>**/*LiveTest.java</include>
</includes>
<systemPropertyVariables>
<webTarget>cargo</webTarget>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<properties>
<commons-fileupload.version>1.3.2</commons-fileupload.version>
<kryo.version>4.0.0</kryo.version>
<protobuf-java-format.version>1.4</protobuf-java-format.version>
<protobuf-java.version>3.1.0</protobuf-java.version>
<commons-lang3.version>3.5</commons-lang3.version>
<xstream.version>1.4.9</xstream.version>
<!-- util -->
<guava.version>20.0</guava.version>
<rest-assured.version>2.9.0</rest-assured.version>
<!-- Maven plugins -->
<cargo-maven2-plugin.version>1.6.0</cargo-maven2-plugin.version>
<findbugs-maven-plugin.version>3.0.4</findbugs-maven-plugin.version>
<!-- okhttp -->
<com.squareup.okhttp3.version>3.4.1</com.squareup.okhttp3.version>
<json.path.version>2.2.0</json.path.version>
</properties>
</project>

View File

@ -0,0 +1,16 @@
package org.baeldung.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@EnableAutoConfiguration
@ComponentScan("org.baeldung")
public class Application extends WebMvcConfigurerAdapter {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}

View File

@ -0,0 +1,61 @@
package org.baeldung.config;
import java.text.SimpleDateFormat;
import java.util.List;
import org.baeldung.config.converter.KryoHttpMessageConverter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.xstream.XStreamMarshaller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/*
* Please note that main web configuration is in src/main/webapp/WEB-INF/api-servlet.xml
*/
@Configuration
@EnableWebMvc
@ComponentScan({ "org.baeldung.web" })
public class WebConfig extends WebMvcConfigurerAdapter {
public WebConfig() {
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"));
messageConverters.add(new MappingJackson2HttpMessageConverter(builder
.build()));
// messageConverters.add(new
// MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
// messageConverters.add(createXmlHttpMessageConverter());
// messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new ProtobufHttpMessageConverter());
messageConverters.add(new KryoHttpMessageConverter());
super.configureMessageConverters(messageConverters);
}
private HttpMessageConverter<Object> createXmlHttpMessageConverter() {
final MarshallingHttpMessageConverter xmlConverter = new MarshallingHttpMessageConverter();
final XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
xmlConverter.setMarshaller(xstreamMarshaller);
xmlConverter.setUnmarshaller(xstreamMarshaller);
return xmlConverter;
}
}

View File

@ -0,0 +1,60 @@
package org.baeldung.config.converter;
import java.io.IOException;
import org.baeldung.web.dto.Foo;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* An {@code HttpMessageConverter} that can read and write Kryo messages.
*/
public class KryoHttpMessageConverter extends
AbstractHttpMessageConverter<Object> {
public static final MediaType KRYO = new MediaType("application", "x-kryo");
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
final Kryo kryo = new Kryo();
kryo.register(Foo.class, 1);
return kryo;
}
};
public KryoHttpMessageConverter() {
super(KRYO);
}
@Override
protected boolean supports(final Class<?> clazz) {
return Object.class.isAssignableFrom(clazz);
}
@Override
protected Object readInternal(final Class<? extends Object> clazz,
final HttpInputMessage inputMessage) throws IOException {
final Input input = new Input(inputMessage.getBody());
return kryoThreadLocal.get().readClassAndObject(input);
}
@Override
protected void writeInternal(final Object object,
final HttpOutputMessage outputMessage) throws IOException {
final Output output = new Output(outputMessage.getBody());
kryoThreadLocal.get().writeClassAndObject(output, object);
output.flush();
}
@Override
protected MediaType getDefaultContentType(final Object object) {
return KRYO;
}
}

View File

@ -0,0 +1,39 @@
package org.baeldung.web.controller;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import org.baeldung.web.dto.Foo;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
public class FooController {
public FooController() {
super();
}
// API - read
@RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
@ResponseBody
public Foo findById(@PathVariable final long id) {
return new Foo(id, randomAlphabetic(4));
}
// API - write
@RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Foo updateFoo(@PathVariable("id") final String id,
@RequestBody final Foo foo) {
return foo;
}
}

View File

@ -0,0 +1,45 @@
package org.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;
}
}

View File

@ -0,0 +1,36 @@
package org.baeldung.web.util;
import javax.servlet.http.HttpServletResponse;
/**
* Provides some constants and utility methods to build a Link Header to be stored in the {@link HttpServletResponse} object
*/
public final class LinkUtil {
public static final String REL_COLLECTION = "collection";
public static final String REL_NEXT = "next";
public static final String REL_PREV = "prev";
public static final String REL_FIRST = "first";
public static final String REL_LAST = "last";
private LinkUtil() {
throw new AssertionError();
}
//
/**
* Creates a Link Header to be stored in the {@link HttpServletResponse} to provide Discoverability features to the user
*
* @param uri
* the base uri
* @param rel
* the relative path
*
* @return the complete url
*/
public static String createLinkHeader(final String uri, final String rel) {
return "<" + uri + ">; rel=\"" + rel + "\"";
}
}

View File

@ -0,0 +1,2 @@
server.port= 8082
server.context-path=/spring-rest

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework" level="WARN" />
<logger name="org.springframework.transaction" level="WARN" />
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"
>
<context:component-scan base-package="org.baeldung.web" />
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" >
<mvc:message-converters register-defaults="true">
<!--
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
-->
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.baeldung.config.converter.KryoHttpMessageConverter"/>
<bean class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller" />
<!-- -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="location">
<value>/WEB-INF/spring-views.xml</value>
</property>
<property name="order" value="0" />
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- max upload size in bytes -->
<property name="maxUploadSize" value="20971520" /> <!-- 20MB -->
<!-- max size of file in memory (in bytes) -->
<property name="maxInMemorySize" value="1048576" /> <!-- 1MB -->
</bean>
<bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="defaultContentType" value="application/json" />
</bean>
</beans>

View File

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Company Data</title>
<script src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"></script>
<script>
$(document).ready(function(){
$('#REST-button').click(function() {
$.ajax({
url: 'http://localhost:8080/spring-rest/companyRest?callback=getCompanyData',
data: {
format: 'json'
},
type: 'GET',
jsonpCallback:'getCompanyData',
dataType: 'jsonp',
error: function() {
$('#infoREST').html('<p>An error has occurred</p>');
},
success: function(data) {
console.log("sucess");
}
});
});
});
function getCompanyData(data) {
document.write("<b>ID:</b> "+data.id+"<br/>");
document.write("<b>NAME:</b> "+data.name+"<br/>");
document.write("<br/>");
}
</script>
</head>
<body>
<!-- Using REST URL-->
<button id="REST-button">Test REST JSON-P!</button>
<div id="infoREST"></div>
</body>
</html>

View File

@ -0,0 +1,10 @@
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
>
<bean id="RedirectedUrl" class="org.springframework.web.servlet.view.RedirectView">
<property name="url" value="redirectedUrl" />
</bean>
</beans>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"
>
<display-name>Spring MVC Application</display-name>
<!-- Spring root -->
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>org.baeldung.config</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Spring child -->
<servlet>
<servlet-name>api</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>api</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file/>
</welcome-file-list>
</web-app>

View File

@ -0,0 +1,216 @@
package org.baeldung.client;
import static org.apache.commons.codec.binary.Base64.encodeBase64;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Set;
import org.baeldung.web.dto.Foo;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
public class RestTemplateBasicLiveTest {
private RestTemplate restTemplate;
private static final String fooResourceUrl = String.format("http://localhost:%d/spring-rest/myfoos", 8082);
@Before
public void beforeTest() {
restTemplate = new RestTemplate();
}
// GET
@Test
public void givenResourceUrl_whenSendGetForRequestEntity_thenStatusOk() throws IOException {
final ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenResourceUrl_whenSendGetForRequestEntity_thenBodyCorrect() throws IOException {
final ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
final ObjectMapper mapper = new ObjectMapper();
final JsonNode root = mapper.readTree(response.getBody());
final JsonNode name = root.path("name");
assertThat(name.asText(), notNullValue());
}
@Test
public void givenResourceUrl_whenRetrievingResource_thenCorrect() throws IOException {
final Foo foo = restTemplate.getForObject(fooResourceUrl + "/1", Foo.class);
assertThat(foo.getName(), notNullValue());
assertThat(foo.getId(), is(1L));
}
// HEAD, OPTIONS
@Test
public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeadersForThatResource() {
final HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
}
// POST
@Test
public void givenFooService_whenPostForObject_thenCreatedObjectIsReturned() {
final HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
final Foo foo = restTemplate.postForObject(fooResourceUrl, request, Foo.class);
assertThat(foo, notNullValue());
assertThat(foo.getName(), is("bar"));
}
@Test
public void givenFooService_whenPostForLocation_thenCreatedLocationIsReturned() {
final HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
final URI location = restTemplate.postForLocation(fooResourceUrl, request);
assertThat(location, notNullValue());
}
@Test
public void givenFooService_whenPostResource_thenResourceIsCreated() {
final RestTemplate template = new RestTemplate();
final HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"));
final ResponseEntity<Foo> response = template.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
final Foo foo = response.getBody();
assertThat(foo, notNullValue());
assertThat(foo.getName(), is("bar"));
}
@Test
public void givenFooService_whenCallOptionsForAllow_thenReceiveValueOfAllowHeader() {
final Set<HttpMethod> optionsForAllow = restTemplate.optionsForAllow(fooResourceUrl);
final HttpMethod[] supportedMethods = { HttpMethod.GET, HttpMethod.POST, HttpMethod.HEAD };
assertTrue(optionsForAllow.containsAll(Arrays.asList(supportedMethods)));
}
// PUT
@Test
public void givenFooService_whenPutExistingEntity_thenItIsUpdated() {
final RestTemplate template = new RestTemplate();
final HttpHeaders headers = prepareBasicAuthHeaders();
final HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"), headers);
// Create Resource
final ResponseEntity<Foo> createResponse = template.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
// Update Resource
final Foo updatedInstance = new Foo("newName");
updatedInstance.setId(createResponse.getBody().getId());
final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody().getId();
final HttpEntity<Foo> requestUpdate = new HttpEntity<>(updatedInstance, headers);
template.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Void.class);
// Check that Resource was updated
final ResponseEntity<Foo> updateResponse = template.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
final Foo foo = updateResponse.getBody();
assertThat(foo.getName(), is(updatedInstance.getName()));
}
@Test
public void givenFooService_whenPutExistingEntityWithCallback_thenItIsUpdated() {
final RestTemplate template = new RestTemplate();
final HttpHeaders headers = prepareBasicAuthHeaders();
final HttpEntity<Foo> request = new HttpEntity<>(new Foo("bar"), headers);
// Create entity
ResponseEntity<Foo> response = template.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
// Update entity
final Foo updatedInstance = new Foo("newName");
updatedInstance.setId(response.getBody().getId());
final String resourceUrl = fooResourceUrl + '/' + response.getBody().getId();
template.execute(resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null);
// Check that entity was updated
response = template.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
final Foo foo = response.getBody();
assertThat(foo.getName(), is(updatedInstance.getName()));
}
// DELETE
@Test
public void givenFooService_whenCallDelete_thenEntityIsRemoved() {
final Foo foo = new Foo("remove me");
final ResponseEntity<Foo> response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class);
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
final String entityUrl = fooResourceUrl + "/" + response.getBody().getId();
restTemplate.delete(entityUrl);
try {
restTemplate.getForEntity(entityUrl, Foo.class);
fail();
} catch (final HttpClientErrorException ex) {
assertThat(ex.getStatusCode(), is(HttpStatus.NOT_FOUND));
}
}
//
private HttpHeaders prepareBasicAuthHeaders() {
final HttpHeaders headers = new HttpHeaders();
final String encodedLogPass = getBase64EncodedLogPass();
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encodedLogPass);
return headers;
}
private String getBase64EncodedLogPass() {
final String logPass = "user1:user1Pass";
final byte[] authHeaderBytes = encodeBase64(logPass.getBytes(Charsets.US_ASCII));
return new String(authHeaderBytes, Charsets.US_ASCII);
}
private RequestCallback requestCallback(final Foo updatedInstance) {
return clientHttpRequest -> {
final ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(clientHttpRequest.getBody(), updatedInstance);
clientHttpRequest.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
clientHttpRequest.getHeaders().add(HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass());
};
}
// Simply setting restTemplate timeout using ClientHttpRequestFactory
ClientHttpRequestFactory getSimpleClientHttpRequestFactory() {
final int timeout = 5;
final HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout * 1000);
return clientHttpRequestFactory;
}
}

View File

@ -0,0 +1,117 @@
package org.baeldung.client;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.junit.Before;
import org.junit.Test;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
public class TestRestTemplateBasicLiveTest {
private RestTemplate restTemplate;
private static final String FOO_RESOURCE_URL = "http://localhost:" + 8082 + "/spring-rest/myfoos";
private static final String URL_SECURED_BY_AUTHENTICATION = "http://httpbin.org/basic-auth/user/passwd";
private static final String BASE_URL = "http://localhost:" + 8082 + "/spring-rest";
@Before
public void beforeTest() {
restTemplate = new RestTemplate();
}
// GET
@Test
public void givenTestRestTemplate_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate();
ResponseEntity<String> response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenRestTemplateWrapper_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate);
ResponseEntity<String> response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenRestTemplateBuilderWrapper_whenSendGetForEntity_thenStatusOk() {
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
restTemplateBuilder.build();
TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder);
ResponseEntity<String> response = testRestTemplate.getForEntity(FOO_RESOURCE_URL + "/1", String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenRestTemplateWrapperWithCredentials_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplate, "user", "passwd");
ResponseEntity<String> response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION,
String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenTestRestTemplateWithCredentials_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd");
ResponseEntity<String> response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION,
String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenTestRestTemplateWithBasicAuth_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate();
ResponseEntity<String> response = testRestTemplate.withBasicAuth("user", "passwd").
getForEntity(URL_SECURED_BY_AUTHENTICATION, String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
@Test
public void givenTestRestTemplateWithCredentialsAndEnabledCookies_whenSendGetForEntity_thenStatusOk() {
TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd", TestRestTemplate.
HttpClientOption.ENABLE_COOKIES);
ResponseEntity<String> response = testRestTemplate.getForEntity(URL_SECURED_BY_AUTHENTICATION,
String.class);
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
}
// HEAD
@Test
public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeaders() {
TestRestTemplate testRestTemplate = new TestRestTemplate();
final HttpHeaders httpHeaders = testRestTemplate.headForHeaders(FOO_RESOURCE_URL);
assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
}
// POST
@Test
public void givenService_whenPostForObject_thenCreatedObjectIsReturned() {
TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd");
final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"),
"{\"id\":1,\"name\":\"Jim\"}");
final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build();
testRestTemplate.postForObject(URL_SECURED_BY_AUTHENTICATION, request, String.class);
}
// PUT
@Test
public void givenService_whenPutForObject_thenCreatedObjectIsReturned() {
TestRestTemplate testRestTemplate = new TestRestTemplate("user", "passwd");
final RequestBody body = RequestBody.create(okhttp3.MediaType.parse("text/html; charset=utf-8"),
"{\"id\":1,\"name\":\"Jim\"}");
final Request request = new Request.Builder().url(BASE_URL + "/users/detail").post(body).build();
testRestTemplate.put(URL_SECURED_BY_AUTHENTICATION, request, String.class);
}
}

View File

@ -0,0 +1,11 @@
package org.baeldung.web.controller.mediatypes;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({ "org.baeldung.web" })
public class TestConfig {
}

View File

@ -1,6 +1,15 @@
package org.baeldung.web.test; package org.baeldung.web.test;
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.baeldung.config.WebConfig; import org.baeldung.config.WebConfig;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -13,17 +22,11 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = WebConfig.class) @ContextConfiguration(classes = WebConfig.class)
@WebAppConfiguration @WebAppConfiguration
public class BazzNewMappingsExampleControllerIntegrationTest { public class BazzNewMappingsExampleIntegrationTest {
private MockMvc mockMvc; private MockMvc mockMvc;

View File

@ -3,9 +3,9 @@ package org.baeldung.web.test;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import com.jayway.restassured.RestAssured;
import org.junit.Test; import org.junit.Test;
import io.restassured.RestAssured;
public class RequestMappingLiveTest { public class RequestMappingLiveTest {
private static String BASE_URI = "http://localhost:8082/spring-rest/ex/"; private static String BASE_URI = "http://localhost:8082/spring-rest/ex/";

View File

@ -0,0 +1,69 @@
package org.baeldung.web.util;
import java.util.List;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
public final class HTTPLinkHeaderUtil {
private HTTPLinkHeaderUtil() {
throw new AssertionError();
}
//
/**
* ex. <br>
* https://api.github.com/users/steveklabnik/gists?page=2>; rel="next", <https://api.github.com/users/steveklabnik/gists?page=3>; rel="last"
*/
public static List<String> extractAllURIs(final String linkHeader) {
Preconditions.checkNotNull(linkHeader);
final List<String> linkHeaders = Lists.newArrayList();
final String[] links = linkHeader.split(", ");
for (final String link : links) {
final int positionOfSeparator = link.indexOf(';');
linkHeaders.add(link.substring(1, positionOfSeparator - 1));
}
return linkHeaders;
}
public static String extractURIByRel(final String linkHeader, final String rel) {
if (linkHeader == null) {
return null;
}
String uriWithSpecifiedRel = null;
final String[] links = linkHeader.split(", ");
String linkRelation = null;
for (final String link : links) {
final int positionOfSeparator = link.indexOf(';');
linkRelation = link.substring(positionOfSeparator + 1, link.length()).trim();
if (extractTypeOfRelation(linkRelation).equals(rel)) {
uriWithSpecifiedRel = link.substring(1, positionOfSeparator - 1);
break;
}
}
return uriWithSpecifiedRel;
}
static Object extractTypeOfRelation(final String linkRelation) {
final int positionOfEquals = linkRelation.indexOf('=');
return linkRelation.substring(positionOfEquals + 2, linkRelation.length() - 1).trim();
}
/**
* ex. <br>
* https://api.github.com/users/steveklabnik/gists?page=2>; rel="next"
*/
public static String extractSingleURI(final String linkHeader) {
Preconditions.checkNotNull(linkHeader);
final int positionOfSeparator = linkHeader.indexOf(';');
return linkHeader.substring(1, positionOfSeparator - 1);
}
}

View File

@ -0,0 +1,13 @@
*.class
#folders#
/target
/neoDb*
/data
/src/main/webapp/WEB-INF/classes
*/META-INF/*
# Packaged files #
*.jar
*.war
*.ear

View File

@ -1,6 +1,5 @@
package org.baeldung.config; package org.baeldung.config;
import org.baeldung.config.converter.KryoHttpMessageConverter;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
@ -40,7 +39,6 @@ public class WebConfig extends WebMvcConfigurerAdapter {
// messageConverters.add(new MappingJackson2HttpMessageConverter()); // messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new ProtobufHttpMessageConverter()); messageConverters.add(new ProtobufHttpMessageConverter());
messageConverters.add(new KryoHttpMessageConverter());
super.configureMessageConverters(messageConverters); super.configureMessageConverters(messageConverters);
} }

View File

@ -1,57 +0,0 @@
package org.baeldung.config.converter;
import java.io.IOException;
import org.baeldung.web.dto.Foo;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/**
* An {@code HttpMessageConverter} that can read and write Kryo messages.
*/
public class KryoHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
public static final MediaType KRYO = new MediaType("application", "x-kryo");
private static final ThreadLocal<Kryo> kryoThreadLocal = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
final Kryo kryo = new Kryo();
kryo.register(Foo.class, 1);
return kryo;
}
};
public KryoHttpMessageConverter() {
super(KRYO);
}
@Override
protected boolean supports(final Class<?> clazz) {
return Object.class.isAssignableFrom(clazz);
}
@Override
protected Object readInternal(final Class<? extends Object> clazz, final HttpInputMessage inputMessage) throws IOException {
final Input input = new Input(inputMessage.getBody());
return kryoThreadLocal.get().readClassAndObject(input);
}
@Override
protected void writeInternal(final Object object, final HttpOutputMessage outputMessage) throws IOException {
final Output output = new Output(outputMessage.getBody());
kryoThreadLocal.get().writeClassAndObject(output, object);
output.flush();
}
@Override
protected MediaType getDefaultContentType(final Object object) {
return KRYO;
}
}

View File

@ -1,10 +1,9 @@
package org.baeldung.repository; package org.baeldung.repository;
import java.util.Map;
import org.baeldung.web.dto.HeavyResource; import org.baeldung.web.dto.HeavyResource;
import org.baeldung.web.dto.HeavyResourceAddressOnly; import org.baeldung.web.dto.HeavyResourceAddressOnly;
import org.baeldung.web.dto.HeavyResourceAddressPartialUpdate;
import java.util.Map;
public class HeavyResourceRepository { public class HeavyResourceRepository {

View File

@ -1,45 +0,0 @@
package org.baeldung.web.controller;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import org.baeldung.web.dto.Foo;
import org.baeldung.web.dto.FooProtos;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
@Controller
public class FooController {
public FooController() {
super();
}
// API - read
@RequestMapping(method = RequestMethod.GET, value = "/foos/{id}")
@ResponseBody
public Foo findById(@PathVariable final long id) {
return new Foo(id, randomAlphabetic(4));
}
// API - write
@RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}")
@ResponseStatus(HttpStatus.OK)
@ResponseBody
public Foo updateFoo(@PathVariable("id") final String id, @RequestBody final Foo foo) {
return foo;
}
@RequestMapping(method = RequestMethod.GET, value = "/foos/{id}", produces = { "application/x-protobuf" })
@ResponseBody
public FooProtos.Foo findProtoById(@PathVariable final long id) {
return FooProtos.Foo.newBuilder().setId(1).setName("Foo Name").build();
}
}

View File

@ -1,6 +1,11 @@
package org.baeldung.web.controller; package org.baeldung.web.controller;
import com.fasterxml.jackson.databind.ObjectMapper; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.HashMap;
import org.baeldung.config.WebConfig; import org.baeldung.config.WebConfig;
import org.baeldung.web.dto.HeavyResource; import org.baeldung.web.dto.HeavyResource;
import org.baeldung.web.dto.HeavyResourceAddressOnly; import org.baeldung.web.dto.HeavyResourceAddressOnly;
@ -16,11 +21,7 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import java.util.HashMap; import com.fasterxml.jackson.databind.ObjectMapper;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)