Skip to content

Commit

Permalink
Merge pull request geektime-geekbang#15 from digitalsonic/master
Browse files Browse the repository at this point in the history
第八章
  • Loading branch information
geektime-geekbang authored Mar 25, 2019
2 parents 3db798d + 39dca7b commit 2b7044a
Show file tree
Hide file tree
Showing 56 changed files with 1,905 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Chapter 8/hateoas-customer-service/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
HELP.md
/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
/build/
69 changes: 69 additions & 0 deletions Chapter 8/hateoas-customer-service/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>geektime.spring.springbucks</groupId>
<artifactId>customer-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>customer-service</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>

<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>1.0.1</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.7</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package geektime.spring.springbucks.customer;

import geektime.spring.springbucks.customer.model.Coffee;
import geektime.spring.springbucks.customer.model.CoffeeOrder;
import geektime.spring.springbucks.customer.model.OrderState;
import lombok.extern.slf4j.Slf4j;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.Resources;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

@Component
@Slf4j
public class CustomerRunner implements ApplicationRunner {
private static final URI ROOT_URI = URI.create("http://localhost:8080/");
@Autowired
private RestTemplate restTemplate;

@Override
public void run(ApplicationArguments args) throws Exception {
Link coffeeLink = getLink(ROOT_URI,"coffees");
readCoffeeMenu(coffeeLink);
Resource<Coffee> americano = addCoffee(coffeeLink);

Link orderLink = getLink(ROOT_URI, "coffeeOrders");
addOrder(orderLink, americano);
queryOrders(orderLink);
}

private Link getLink(URI uri, String rel) {
ResponseEntity<Resources<Link>> rootResp =
restTemplate.exchange(uri, HttpMethod.GET, null,
new ParameterizedTypeReference<Resources<Link>>() {});
Link link = rootResp.getBody().getLink(rel);
log.info("Link: {}", link);
return link;
}

private void readCoffeeMenu(Link coffeeLink) {
ResponseEntity<PagedResources<Resource<Coffee>>> coffeeResp =
restTemplate.exchange(coffeeLink.getTemplate().expand(),
HttpMethod.GET, null,
new ParameterizedTypeReference<PagedResources<Resource<Coffee>>>() {});
log.info("Menu Response: {}", coffeeResp.getBody());
}

private Resource<Coffee> addCoffee(Link link) {
Coffee americano = Coffee.builder()
.name("americano")
.price(Money.of(CurrencyUnit.of("CNY"), 25.0))
.build();
RequestEntity<Coffee> req =
RequestEntity.post(link.getTemplate().expand()).body(americano);
ResponseEntity<Resource<Coffee>> resp =
restTemplate.exchange(req,
new ParameterizedTypeReference<Resource<Coffee>>() {});
log.info("add Coffee Response: {}", resp);
return resp.getBody();
}

private void addOrder(Link link, Resource<Coffee> coffee) {
CoffeeOrder newOrder = CoffeeOrder.builder()
.customer("Li Lei")
.state(OrderState.INIT)
.build();
RequestEntity<?> req =
RequestEntity.post(link.getTemplate().expand()).body(newOrder);
ResponseEntity<Resource<CoffeeOrder>> resp =
restTemplate.exchange(req,
new ParameterizedTypeReference<Resource<CoffeeOrder>>() {});
log.info("add Order Response: {}", resp);

Resource<CoffeeOrder> order = resp.getBody();
Link items = order.getLink("items");
req = RequestEntity.post(items.getTemplate().expand()).body(coffee.getLink("self"));
ResponseEntity<String> itemResp = restTemplate.exchange(req, String.class);
log.info("add Order Items Response: {}", itemResp);
}

private void queryOrders(Link link) {
ResponseEntity<String> resp = restTemplate.getForEntity(link.getTemplate().expand(), String.class);
log.info("query Order Response: {}", resp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package geektime.spring.springbucks.customer;

import geektime.spring.springbucks.customer.support.CustomConnectionKeepAliveStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.boot.Banner;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.hateoas.hal.Jackson2HalModule;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
@Slf4j
public class CustomerServiceApplication {

public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(CustomerServiceApplication.class)
.bannerMode(Banner.Mode.OFF)
.web(WebApplicationType.NONE)
.run(args);
}

@Bean
public Jackson2HalModule jackson2HalModule() {
return new Jackson2HalModule();
}

@Bean
public HttpComponentsClientHttpRequestFactory requestFactory() {
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
connectionManager.setMaxTotal(200);
connectionManager.setDefaultMaxPerRoute(20);

CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.evictIdleConnections(30, TimeUnit.SECONDS)
.disableAutomaticRetries()
// 有 Keep-Alive 认里面的值,没有的话永久有效
//.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
// 换成自定义的
.setKeepAliveStrategy(new CustomConnectionKeepAliveStrategy())
.build();

HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory(httpClient);

return requestFactory;
}

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.setConnectTimeout(Duration.ofMillis(100))
.setReadTimeout(Duration.ofMillis(500))
.requestFactory(this::requestFactory)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package geektime.spring.springbucks.customer.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.joda.money.Money;

import java.io.Serializable;
import java.util.Date;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Coffee implements Serializable {
private String name;
private Money price;
private Date createTime;
private Date updateTime;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package geektime.spring.springbucks.customer.model;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CoffeeOrder {
private Long id;
private String customer;
private OrderState state;
private Date createTime;
private Date updateTime;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package geektime.spring.springbucks.customer.model;

public enum OrderState {
INIT, PAID, BREWING, BREWED, TAKEN, CANCELLED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package geektime.spring.springbucks.customer.support;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;

import java.util.Arrays;

public class CustomConnectionKeepAliveStrategy implements ConnectionKeepAliveStrategy {
private final long DEFAULT_SECONDS = 30;

@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
return Arrays.asList(response.getHeaders(HTTP.CONN_KEEP_ALIVE))
.stream()
.filter(h -> StringUtils.endsWithIgnoreCase(h.getName(), "timeout")
&& StringUtils.isNumeric(h.getValue()))
.findFirst()
.map(h -> NumberUtils.toLong(h.getValue(), DEFAULT_SECONDS))
.orElse(DEFAULT_SECONDS) * 1000;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package geektime.spring.springbucks.customer.support;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;

@JsonComponent
public class MoneyDeserializer extends StdDeserializer<Money> {
protected MoneyDeserializer() {
super(Money.class);
}

@Override
public Money deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return Money.of(CurrencyUnit.of("CNY"), p.getDecimalValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package geektime.spring.springbucks.customer.support;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import org.joda.money.Money;
import org.springframework.boot.jackson.JsonComponent;

import java.io.IOException;

@JsonComponent
public class MoneySerializer extends StdSerializer<Money> {
protected MoneySerializer() {
super(Money.class);
}

@Override
public void serialize(Money money, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeNumber(money.getAmount());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading

0 comments on commit 2b7044a

Please sign in to comment.