公共模块 cloudalibabacommon 依赖4.0.0 com.xysd.cloud cloudexecise2 pom 1.0-SNAPSHOT cloudalibabacommon cloudalibabauser cloudalibabaproduct cloudalibabaorder org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-logging org.projectlombok lombok 1.18.4 provided org.springframework.cloud spring-cloud-dependencies Greenwich.RELEASE pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import cloudexecise2 org.apache.maven.plugins maven-compiler-plugin ${java.version} ${java.version}
代码cloudexecise2 com.xysd.cloud 1.0-SNAPSHOT 4.0.0 cloudalibabacommon io.springfox springfox-swagger2 2.9.2 io.springfox springfox-swagger-ui 2.9.2 org.springframework.boot spring-boot-starter-data-jpa com.alibaba fastjson 1.2.47 mysql mysql-connector-java
package com.xysd.cloud.alibaba.config;
import springfox.documentation.service.Parameter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.documentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class SwaggerConfig {
@Bean
public Docket createRestApi() {
ParameterBuilder tokenPar = new ParameterBuilder();
List pars = new ArrayList();
tokenPar.parameterType("header")//参数类型支持header, cookie, body, query etc
.name("principalToken")//参数名
.defaultValue("")//默认值
.description("身份令牌")//描述信息
.modelRef(new ModelRef("string"))//指定参数值的类型
.required(false)//非必需,这里是全局配置
.build();
pars.add(tokenPar.build());
return new Docket(documentationType.SWAGGER_2)
.globalOperationParameters(pars)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.xysd.cloud.alibaba.resource"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("spring cloud alibaba")
.description("学习spring cloud alibaba")
.termsOfServiceUrl("")
.version("1.1")
.build();
}
}
package com.xysd.cloud.alibaba.domain;
import javax.persistence.*;
@Entity
@Table(name = "shop_order")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long oid;//订单id
private Integer uid;//用户id
private String username;//用户名
private Integer pid;//商品id
private String pname;//商品名称
private Double pprice;//商品单价
private Integer number;//购买数量
public Long getOid() {
return oid;
}
public Order(Integer pid, String pname, Double pprice) {
this.pid = pid;
this.pname = pname;
this.pprice = pprice;
}
public Integer getUid() {
return uid;
}
public String getUsername() {
return username;
}
public Integer getPid() {
return pid;
}
public String getPname() {
return pname;
}
public Double getPprice() {
return pprice;
}
public Integer getNumber() {
return number;
}
public Order() {
}
}
package com.xysd.cloud.alibaba.domain;
import javax.persistence.*;
@Entity
@Table(name = "shop_product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;//主键
private String pname;//商品名称
private Double pprice;//商品价格
private Integer stock;//库存
public Integer getPid() {
return pid;
}
public String getPname() {
return pname;
}
public Double getPprice() {
return pprice;
}
public Integer getStock() {
return stock;
}
public Product() {
}
}
package com.xysd.cloud.alibaba.domain;
import javax.persistence.*;
@Entity
@Table(name = "shop_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer uid;
private String username;
private String password;
private String telephone;
public Integer getUid() {
return uid;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getTelephone() {
return telephone;
}
public User() {
}
}
用户服务 cloudalibabauser
依赖
配置cloudexecise2 com.xysd.cloud 1.0-SNAPSHOT 4.0.0 cloudalibabauser com.xysd.cloud cloudalibabacommon 1.0-SNAPSHOT
server:
port: 8087
spring:
application:
name: cloudalibabauser
datasource:
password: root
username: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud?serverTimezone=GMT%2B8
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
代码
package com.xysd.cloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class,args);
}
}
商品服务
cloudexecise2 com.xysd.cloud 1.0-SNAPSHOT 4.0.0 cloudalibabaproduct com.xysd.cloud cloudalibabacommon 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery
server:
port: 8088
spring:
application:
name: cloudalibabaproduct
datasource:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/cloud?serverTimezone=GMT%2B8
jpa:
properties:
hibernate:
hbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
cloud:
nacos:
discovery:
server-addr: http://localhost:8848/
package com.xysd.cloud.alibaba.domain; import org.springframework.data.jpa.repository.JpaRepository; public interface ProductRepository extends JpaRepository{ }
package com.xysd.cloud.alibaba.application;
import com.xysd.cloud.alibaba.application.dto.ProductDTO;
import com.xysd.cloud.alibaba.domain.Product;
public interface IProductService {
public ProductDTO findProductById(Integer id);
}
package com.xysd.cloud.alibaba.application.impl;
import com.xysd.cloud.alibaba.application.IProductService;
import com.xysd.cloud.alibaba.application.assembler.ProductAssembler;
import com.xysd.cloud.alibaba.application.dto.ProductDTO;
import com.xysd.cloud.alibaba.domain.Product;
import com.xysd.cloud.alibaba.domain.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class ProductServiceImpl implements IProductService {
@Autowired
private ProductRepository productRepository;
@Override
public ProductDTO findProductById(Integer id) {
return new ProductAssembler().toDTO(Optional.ofNullable(productRepository.getOne(id)).orElse(new Product()));
}
}
package com.xysd.cloud.alibaba.application.dto;
public class ProductDTO {
private Integer pid;//主键
private String pname;//商品名称
private Double pprice;//商品价格
private Integer stock;//库存
public ProductDTO(Integer pid, String pname, Double pprice, Integer stock) {
this.pid = pid;
this.pname = pname;
this.pprice = pprice;
this.stock = stock;
}
public ProductDTO() {
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public Double getPprice() {
return pprice;
}
public void setPprice(Double pprice) {
this.pprice = pprice;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
}
package com.xysd.cloud.alibaba.application.assembler;
import com.xysd.cloud.alibaba.application.dto.ProductDTO;
import com.xysd.cloud.alibaba.domain.Product;
public class ProductAssembler {
public ProductDTO toDTO(Product product){
return new ProductDTO(product.getPid(),product.getPname(),product.getPprice(),product.getStock());
}
}
package com.xysd.cloud.alibaba.resource;
import com.alibaba.fastjson.JSON;
import com.xysd.cloud.alibaba.application.IProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private IProductService productService;
@RequestMapping("/find/{id}")
public String findById(@PathVariable(value = "id")Integer id){
return JSON.toJSONString(productService.findProductById(id));
}
}
package com.xysd.cloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@EnableDiscoveryClient
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class,args);
}
}
订单服务
cloudexecise2 com.xysd.cloud 1.0-SNAPSHOT 4.0.0 cloudalibabaorder com.xysd.cloud cloudalibabacommon 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-web com.alibaba.cloud spring-cloud-starter-alibaba-nacos-discovery
server:
port: 8089
spring:
application:
name: cloudalibabaorder
datasource:
url: jdbc:mysql://localhost:3306/cloud?serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
jpa:
properties:
hibernate:
bhbm2ddl:
auto: update
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
cloud:
nacos:
discovery:
server-addr: localhost:8848
package com.xysd.cloud.alibaba.domain; import org.springframework.data.jpa.repository.JpaRepository; public interface OrderRepository extends JpaRepository{ }
package com.xysd.cloud.alibaba.application;
import com.xysd.cloud.alibaba.domain.Order;
public interface IOrderService {
public void save(Order order);
}
package com.xysd.cloud.alibaba.application.impl;
import com.xysd.cloud.alibaba.application.IOrderService;
import com.xysd.cloud.alibaba.domain.Order;
import com.xysd.cloud.alibaba.domain.OrderRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl implements IOrderService {
@Autowired
private OrderRepository orderRepository;
@Override
public void save(Order order) {
orderRepository.save(order);
}
}
package com.xysd.cloud.alibaba.resource;
import com.alibaba.fastjson.JSON;
import com.xysd.cloud.alibaba.application.IOrderService;
import com.xysd.cloud.alibaba.domain.Order;
import com.xysd.cloud.alibaba.domain.Product;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Api(value = "订单管理接口",tags = {"订单管理接口"})
@RestController
@RequestMapping("/order")
public class OrderController {
private final static String PRODUCT_URL_FIND = "http://localhost:8088/product/find/";
@Autowired
private IOrderService orderService;
@Autowired
private RestTemplate restTemplate;
@Autowired
DiscoveryClient discoveryClient;
@ApiOperation(value = "根据id查询订单商品信息",response = String.class)
@ApiImplicitParam(name = "id",required = true,dataType = "Integer")
@RequestMapping("/find/{id}")
public String find(@PathVariable(value = "id")Integer id){
Product product = restTemplate.getForObject(PRODUCT_URL_FIND + id, Product.class);
Order order = new Order(product.getPid(),product.getPname(),product.getPprice());
return JSON.toJSONString(order);
}
@ApiOperation(value = "根据id查询订单商品信息",response = String.class)
@ApiImplicitParam(name = "id",required = true,dataType = "Integer")
@RequestMapping("/find/by/{id}")
public String findById(@PathVariable(value = "id")Integer id){
ServiceInstance cloudalibabaproduct = discoveryClient.getInstances("cloudalibabaproduct").get(0);
String url = "http://" + cloudalibabaproduct.getHost() + ":" + cloudalibabaproduct.getPort() + "/product/find/";
Product product = restTemplate.getForObject(url + id, Product.class);
Order order = new Order(product.getPid(),product.getPname(),product.getPprice());
return JSON.toJSONString(order);
}
}
package com.xysd.cloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
测试
1.需要下载nacos-server服务,一个压缩包,解压之后进入bin目录,双击startup.cmd,启动服务,访问http://localhost:8848/nacos
2.启动cloudalibabaproduct服务,然后再启动cloudalibabaorder服务,访问http://localhost:8089/order/find/1,http://localhost:8089/order/find/by/1
需要两个cloudalibabaproduct服务,只需要 先启动一个,另一个服务区idea 的 Edit Configurations 找到该服务,在VM options -Dserver.port=8090,然后apply,启动
修改cloudalibabaorder服务的启动类,添加@LoadBalanced
package com.xysd.cloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@ApiOperation(value = "根据id查询订单商品信息",response = String.class)
@ApiImplicitParam(name = "id",required = true,dataType = "Integer")
@RequestMapping("/find/by/order/{id}")
public String order(@PathVariable(value = "id")Integer id){
List instances = discoveryClient.getInstances("cloudalibabaproduct");
int index = new Random().nextInt(instances.size());
ServiceInstance serviceInstance = instances.get(index);
String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product/find/";
logger.warning(url);
Product product = restTemplate.getForObject(url + id, Product.class);
Order order = new Order(product.getPid(),product.getPname(),product.getPprice());
return JSON.toJSONString(order);
}
使用配置来实现负载均衡,修改cloudalibabaorder服务的配置文件application.yml,添加配置
cloudalibabaorder:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
package com.xysd.cloud.alibaba;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@ApiOperation(value = "根据id查询订单商品信息",response = String.class)
@ApiImplicitParam(name = "id",required = true,dataType = "Integer")
@RequestMapping("/find/by/order/{id}")
public String order(@PathVariable(value = "id")Integer id){
Product product = restTemplate.getForObject("http://cloudalibabaproduct/product/find/" + id, Product.class);
Order order = new Order(product.getPid(),product.getPname(),product.getPprice());
return JSON.toJSONString(order);
}
使用Feign负载均衡
在cloudalibabaorder服务添加feign依赖
org.springframework.cloud spring-cloud-starter-openfeign
添加注解
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
package com.xysd.cloud.alibaba.application;
import com.xysd.cloud.alibaba.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient("cloudalibabaproduct")
public interface IProductServiceFeign {
@RequestMapping("/product/find/{id}")
public String findById(@PathVariable(value = "id")int id);
}
package com.xysd.cloud.alibaba.resource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xysd.cloud.alibaba.application.IOrderService;
import com.xysd.cloud.alibaba.application.IProductServiceFeign;
import com.xysd.cloud.alibaba.domain.Order;
import com.xysd.cloud.alibaba.domain.Product;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
import java.util.Random;
import java.util.logging.Logger;
@Api(value = "订单管理接口",tags = {"订单管理接口"})
@RestController
@RequestMapping("/order")
public class OrderController {
private static Logger logger = Logger.getLogger("OrderController");
@Autowired
private IProductServiceFeign productServiceFeign;
@ApiOperation(value = "根据id查询订单商品信息",response = String.class)
@ApiImplicitParam(name = "id",required = true,dataType = "Integer")
@RequestMapping("/find/by/feign/{id}")
public String orderFeign(@PathVariable(value = "id")Integer id){
String pStr = productServiceFeign.findById(id);
logger.warning(pStr);
Product product = JSON.parseObject(pStr,Product.class);
logger.warning(product.toString());
Order order = new Order(product.getPid(),product.getPname(),product.getPprice());
return JSON.toJSONString(order);
}
}
测试
注意:Product实体必须要有setter方法,因为JSON.parseObject()方法转换需要
sentinel 限流熔断(hystrix)sentinel是一个jar,需要下载,使用java -jar xx.jar,访问localhost:8080,sentinel/sentinel登录
在cloudalibabaorder服务中导入依赖
com.alibaba.cloud spring-cloud-starter-alibaba-sentinel
配置
spring:
cloud:
sentinel:
transport:
port: 8176 #跟控制台交流的端口,随意指定一个未使用的端口即可
dashboard: localhost:8080 # 指定控制台服务的地址
在sentinel页面进行限流设置
package com.xysd.cloud.alibaba.application;
import com.xysd.cloud.alibaba.application.impl.ProductServiceSentinel;
import com.xysd.cloud.alibaba.domain.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "cloudalibabaproduct",fallback = ProductServiceSentinel.class)
public interface IProductServiceFeign {
@RequestMapping("/product/find/{id}")
public String findById(@PathVariable(value = "id")int id);
}
package com.xysd.cloud.alibaba.application.impl;
import com.alibaba.fastjson.JSON;
import com.xysd.cloud.alibaba.application.IProductServiceFeign;
import com.xysd.cloud.alibaba.domain.Product;
import org.springframework.stereotype.Component;
@Component
public class ProductServiceSentinel implements IProductServiceFeign {
@Override
public String findById(int id) {
Product product = new Product(500,"sentinel容错",0.0,1);
return JSON.toJSONString(product);
}
}
测试:连续访问则出现 sentinel容错



