fix live test (#2143)
* minor logging fix * spring security sso * use basic auth * use form login * cleanup * cleanup * final cleanup * second client app for sso * spring boot bootstrap * add logic * cleanup * add simple controller * add thymeleaf and security * minor fix * minor fix * add more boot properties * fix live test
This commit is contained in:
parent
61bea8493d
commit
ee2ed99ad9
@ -6,12 +6,16 @@ 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.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
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.MappingJackson2XmlHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
|
||||
import org.springframework.oxm.xstream.XStreamMarshaller;
|
||||
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
@ -30,21 +34,20 @@ public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
//
|
||||
|
||||
@Override
|
||||
public void configureMessageConverters(
|
||||
final List<HttpMessageConverter<?>> messageConverters) {
|
||||
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
|
||||
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(new
|
||||
// MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
|
||||
|
||||
// messageConverters.add(createXmlHttpMessageConverter());
|
||||
messageConverters.add(createXmlHttpMessageConverter());
|
||||
// messageConverters.add(new MappingJackson2HttpMessageConverter());
|
||||
|
||||
messageConverters.add(new ProtobufHttpMessageConverter());
|
||||
messageConverters.add(new KryoHttpMessageConverter());
|
||||
messageConverters.add(new StringHttpMessageConverter());
|
||||
super.configureMessageConverters(messageConverters);
|
||||
}
|
||||
|
||||
@ -58,4 +61,8 @@ public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
return xmlConverter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
|
||||
configurer.defaultContentType(MediaType.APPLICATION_JSON);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ 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;
|
||||
@ -32,8 +33,16 @@ public class FooController {
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/foos/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
@ResponseBody
|
||||
public Foo updateFoo(@PathVariable("id") final String id,
|
||||
@RequestBody final Foo foo) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1,56 +0,0 @@
|
||||
<?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>
|
||||
|
||||
|
@ -1,17 +1,11 @@
|
||||
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;
|
||||
@ -22,16 +16,8 @@ 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;
|
||||
@ -52,16 +38,6 @@ public class RestTemplateBasicLiveTest {
|
||||
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);
|
||||
@ -70,147 +46,19 @@ public class RestTemplateBasicLiveTest {
|
||||
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() {
|
||||
public void givenFooService_whenPutObject_thenUpdatedObjectIsReturned() {
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
final String encodedLogPass = getBase64EncodedLogPass();
|
||||
headers.add(HttpHeaders.AUTHORIZATION, "Basic " + encodedLogPass);
|
||||
return headers;
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
final Foo foo = new Foo(1, "newName");
|
||||
final String resourceUrl = fooResourceUrl + "/1";
|
||||
final HttpEntity<Foo> requestUpdate = new HttpEntity<>(foo, headers);
|
||||
final ResponseEntity<Foo> response = restTemplate.exchange(resourceUrl, HttpMethod.PUT, requestUpdate, Foo.class);
|
||||
|
||||
assertThat(foo.getName(), is(response.getBody()
|
||||
.getName()));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -3,61 +3,118 @@ package org.baeldung.web.test;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
||||
import com.jayway.restassured.RestAssured;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.jayway.restassured.RestAssured;
|
||||
|
||||
public class RequestMappingLiveTest {
|
||||
private static String BASE_URI = "http://localhost:8082/spring-rest/ex/";
|
||||
|
||||
@Test
|
||||
public void givenSimplePath_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "foos").then().assertThat().body(equalTo("Simple Get some Foos"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Simple Get some Foos"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPostFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").post(BASE_URI + "foos").then().assertThat().body(equalTo("Post some Foos"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.post(BASE_URI + "foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Post some Foos"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneHeader_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").header("key", "val").get(BASE_URI + "foos").then().assertThat().body(equalTo("Get some Foos with Header"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.header("key", "val")
|
||||
.get(BASE_URI + "foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get some Foos with Header"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleHeaders_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").headers("key1", "val1", "key2", "val2").get(BASE_URI + "foos").then().assertThat().body(equalTo("Get some Foos with Header"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.headers("key1", "val1", "key2", "val2")
|
||||
.get(BASE_URI + "foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get some Foos with Header"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenAcceptHeader_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("application/json").get(BASE_URI + "foos").then().assertThat().body(containsString("Get some Foos with Header New"));
|
||||
RestAssured.given()
|
||||
.accept("application/json")
|
||||
.get(BASE_URI + "foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(containsString("Get some Foos with Header New"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPathVariable_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "foos/1").then().assertThat().body(equalTo("Get a specific Foo with id=1"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "foos/1")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get a specific Foo with id=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplePathVariable_whenGetFoos_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "foos/1/bar/2").then().assertThat().body(equalTo("Get a specific Bar with id=2 from a Foo with id=1"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "foos/1/bar/2")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get a specific Bar with id=2 from a Foo with id=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenPathVariable_whenGetBars_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "bars/1").then().assertThat().body(equalTo("Get a specific Bar with id=1"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "bars/1")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get a specific Bar with id=1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenParams_whenGetBars_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "bars?id=100&second=something").then().assertThat().body(equalTo("Get a specific Bar with id=100"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "bars?id=100&second=something")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Get a specific Bar with id=100"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetFoosOrBars_thenOk() {
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "advanced/foos").then().assertThat().body(equalTo("Advanced - Get some Foos or Bars"));
|
||||
RestAssured.given().accept("text/html").get(BASE_URI + "advanced/bars").then().assertThat().body(equalTo("Advanced - Get some Foos or Bars"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "advanced/foos")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Advanced - Get some Foos or Bars"));
|
||||
RestAssured.given()
|
||||
.accept("text/html")
|
||||
.get(BASE_URI + "advanced/bars")
|
||||
.then()
|
||||
.assertThat()
|
||||
.body(equalTo("Advanced - Get some Foos or Bars"));
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,18 @@
|
||||
package org.baeldung.config;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Please note that main web configuration is in src/main/webapp/WEB-INF/api-servlet.xml
|
||||
*/
|
||||
@ -31,14 +30,15 @@ public class WebConfig extends WebMvcConfigurerAdapter {
|
||||
@Override
|
||||
public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
|
||||
final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
|
||||
builder.indentOutput(true).dateFormat(new SimpleDateFormat("dd-MM-yyyy hh:mm"));
|
||||
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 ProtobufHttpMessageConverter());
|
||||
super.configureMessageConverters(messageConverters);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
package org.baeldung.web.controller;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -58,12 +58,20 @@ public class MyFooController {
|
||||
return foo;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.PATCH, value = "/{id}")
|
||||
@ResponseStatus(HttpStatus.OK)
|
||||
public void updateFoo2(@PathVariable("id") final long id, @RequestBody final Foo foo) {
|
||||
myfoos.put(id, foo);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
@ResponseBody
|
||||
public Foo createFoo(@RequestBody final Foo foo, HttpServletResponse response) {
|
||||
myfoos.put(foo.getId(), foo);
|
||||
response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentRequest().path("/" + foo.getId()).toUriString());
|
||||
response.setHeader("Location", ServletUriComponentsBuilder.fromCurrentRequest()
|
||||
.path("/" + foo.getId())
|
||||
.toUriString());
|
||||
return foo;
|
||||
}
|
||||
|
||||
|
@ -19,9 +19,8 @@
|
||||
</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>
|
||||
<!-- <bean class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter"/>
|
||||
--> </mvc:message-converters>
|
||||
</mvc:annotation-driven>
|
||||
|
||||
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller" />
|
||||
|
@ -25,6 +25,7 @@ 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.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.RequestCallback;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@ -41,20 +42,22 @@ public class RestTemplateBasicLiveTest {
|
||||
@Before
|
||||
public void beforeTest() {
|
||||
restTemplate = new RestTemplate();
|
||||
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
|
||||
}
|
||||
|
||||
// GET
|
||||
|
||||
@Test
|
||||
public void givenResourceUrl_whenSendGetForRequestEntity_thenStatusOk() throws IOException {
|
||||
final ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "/1", String.class);
|
||||
final ResponseEntity<Foo> response = restTemplate.getForEntity(fooResourceUrl + "/1", Foo.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 RestTemplate template = new RestTemplate();
|
||||
final ResponseEntity<String> response = template.getForEntity(fooResourceUrl + "/1", String.class);
|
||||
|
||||
final ObjectMapper mapper = new ObjectMapper();
|
||||
final JsonNode root = mapper.readTree(response.getBody());
|
||||
@ -76,7 +79,8 @@ public class RestTemplateBasicLiveTest {
|
||||
public void givenFooService_whenCallHeadForHeaders_thenReceiveAllHeadersForThatResource() {
|
||||
final HttpHeaders httpHeaders = restTemplate.headForHeaders(fooResourceUrl);
|
||||
|
||||
assertTrue(httpHeaders.getContentType().includes(MediaType.APPLICATION_JSON));
|
||||
assertTrue(httpHeaders.getContentType()
|
||||
.includes(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
// POST
|
||||
@ -98,15 +102,13 @@ public class RestTemplateBasicLiveTest {
|
||||
|
||||
@Test
|
||||
public void givenFooService_whenPostResource_thenResourceIsCreated() {
|
||||
final RestTemplate template = new RestTemplate();
|
||||
final Foo foo = new Foo("bar");
|
||||
final ResponseEntity<Foo> response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class);
|
||||
|
||||
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"));
|
||||
final Foo fooResponse = response.getBody();
|
||||
assertThat(fooResponse, notNullValue());
|
||||
assertThat(fooResponse.getName(), is("bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -121,44 +123,46 @@ public class RestTemplateBasicLiveTest {
|
||||
|
||||
@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);
|
||||
final ResponseEntity<Foo> createResponse = restTemplate.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();
|
||||
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);
|
||||
restTemplate.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 ResponseEntity<Foo> updateResponse = restTemplate.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);
|
||||
ResponseEntity<Foo> response = restTemplate.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);
|
||||
updatedInstance.setId(response.getBody()
|
||||
.getId());
|
||||
final String resourceUrl = fooResourceUrl + '/' + response.getBody()
|
||||
.getId();
|
||||
restTemplate.execute(resourceUrl, HttpMethod.PUT, requestCallback(updatedInstance), clientHttpResponse -> null);
|
||||
|
||||
// Check that entity was updated
|
||||
response = template.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
|
||||
response = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
|
||||
final Foo foo = response.getBody();
|
||||
assertThat(foo.getName(), is(updatedInstance.getName()));
|
||||
}
|
||||
@ -167,22 +171,26 @@ public class RestTemplateBasicLiveTest {
|
||||
|
||||
@Test
|
||||
public void givenFooService_whenPatchExistingEntity_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);
|
||||
final ResponseEntity<Foo> createResponse = restTemplate.exchange(fooResourceUrl, HttpMethod.POST, request, Foo.class);
|
||||
|
||||
// Update Resource
|
||||
final Foo updatedResource = new Foo("newName");
|
||||
updatedResource.setId(createResponse.getBody().getId());
|
||||
final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody().getId();
|
||||
updatedResource.setId(createResponse.getBody()
|
||||
.getId());
|
||||
final String resourceUrl = fooResourceUrl + '/' + createResponse.getBody()
|
||||
.getId();
|
||||
final HttpEntity<Foo> requestUpdate = new HttpEntity<>(updatedResource, headers);
|
||||
final ClientHttpRequestFactory requestFactory = getSimpleClientHttpRequestFactory();
|
||||
final RestTemplate template = new RestTemplate(requestFactory);
|
||||
template.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
|
||||
template.patchForObject(resourceUrl, requestUpdate, Void.class);
|
||||
|
||||
// Check that Resource was updated
|
||||
final ResponseEntity<Foo> updateResponse = template.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
|
||||
final ResponseEntity<Foo> updateResponse = restTemplate.exchange(resourceUrl, HttpMethod.GET, new HttpEntity<>(headers), Foo.class);
|
||||
final Foo foo = updateResponse.getBody();
|
||||
assertThat(foo.getName(), is(updatedResource.getName()));
|
||||
}
|
||||
@ -195,7 +203,8 @@ public class RestTemplateBasicLiveTest {
|
||||
final ResponseEntity<Foo> response = restTemplate.postForEntity(fooResourceUrl, foo, Foo.class);
|
||||
assertThat(response.getStatusCode(), is(HttpStatus.CREATED));
|
||||
|
||||
final String entityUrl = fooResourceUrl + "/" + response.getBody().getId();
|
||||
final String entityUrl = fooResourceUrl + "/" + response.getBody()
|
||||
.getId();
|
||||
restTemplate.delete(entityUrl);
|
||||
try {
|
||||
restTemplate.getForEntity(entityUrl, Foo.class);
|
||||
@ -224,8 +233,10 @@ public class RestTemplateBasicLiveTest {
|
||||
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());
|
||||
clientHttpRequest.getHeaders()
|
||||
.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
clientHttpRequest.getHeaders()
|
||||
.add(HttpHeaders.AUTHORIZATION, "Basic " + getBase64EncodedLogPass());
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3,14 +3,14 @@ GET
|
||||
0
|
||||
HTTP/1.1 200 OK
|
||||
10
|
||||
Server: nginx/1.10.0 (Ubuntu)
|
||||
Date: Thu, 09 Mar 2017 10:17:25 GMT
|
||||
Content-Type: text/plain
|
||||
Content-Length: 1759
|
||||
Last-Modified: Tue, 27 May 2014 02:35:47 GMT
|
||||
Connection: keep-alive
|
||||
ETag: "5383fa03-6df"
|
||||
Accept-Ranges: bytes
|
||||
Server: nginx/1.10.0 (Ubuntu)
|
||||
Date: Fri, 23 Jun 2017 15:44:52 GMT
|
||||
Last-Modified: Tue, 27 May 2014 02:35:47 GMT
|
||||
ETag: "5383fa03-6df"
|
||||
OkHttp-Sent-Millis: 1489054646765
|
||||
OkHttp-Received-Millis: 1489054646966
|
||||
|
||||
|
@ -4,10 +4,10 @@ GET
|
||||
HTTP/1.1 301 Moved Permanently
|
||||
8
|
||||
Server: nginx/1.10.0 (Ubuntu)
|
||||
Date: Thu, 09 Mar 2017 10:17:25 GMT
|
||||
Date: Sat, 24 Jun 2017 01:06:43 GMT
|
||||
Content-Type: text/html
|
||||
Content-Length: 194
|
||||
Connection: keep-alive
|
||||
Location: https://publicobject.com/helloworld.txt
|
||||
OkHttp-Sent-Millis: 1489054646977
|
||||
OkHttp-Received-Millis: 1489054647185
|
||||
OkHttp-Sent-Millis: 1498266403462
|
||||
OkHttp-Received-Millis: 1498266403727
|
||||
|
51
spring-rest/src/test/resources/cache/journal
vendored
51
spring-rest/src/test/resources/cache/journal
vendored
@ -10,3 +10,54 @@ CLEAN 2d9345a30d2cc31bb3091d70a8ef6c18 7618 1759
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
DIRTY 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
CLEAN 2d9345a30d2cc31bb3091d70a8ef6c18 7618 1759
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
READ 2d9345a30d2cc31bb3091d70a8ef6c18
|
||||
READ 4b217e04ba52215f3a6b64d28f6729c6
|
||||
DIRTY 4b217e04ba52215f3a6b64d28f6729c6
|
||||
CLEAN 4b217e04ba52215f3a6b64d28f6729c6 333 194
|
||||
|
Loading…
x
Reference in New Issue
Block a user