导读
之前写过一篇SpringCloud从入门到精通的点我直达,微服务基础知识点我直达,今天我们使用Spring Cloud模拟一个电商项目。分别有以下2个服务,商品、订单。下面我们开始叭
技术栈
- SpringBoot整合SpringCloud
- 通信方式:http restful
- 注册中心:eruka
- 断路器:hystrix
- 网关:zuul
商品服务
功能点
- 商品列表
- 商品详情
订单服务
功能点
- 我的订单
- 下单接口
搭建Eureka Server
创建项目
项目结构
pom.<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>eureka_server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eureka_server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>eureka_server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eureka_server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
启动类上加注解
application.properties
# 服务端口号server.port=8761# eureka主机名eureka.instance.hostname=localhost# 指定当前主机是否需要向注册中心注册(不用,因为当前主机是Server,不是Client)eureka.client.register-with-eureka=false# 指定当前主机是否需要获取注册信息(不用,因为当前主机是Server,不是Client)eureka.client.fetch-registry=false# 注册中心地址eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
启动服务并查看监控台
搭建Eureka Client商品服务
创建项目
项目结构
pom.

<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>product_service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>product_service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
View Code
<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>product_service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>product_service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
application.properties
# 服务端口号server.port=8771# 服务名称spring.application.name=product_service# 将服务注册到注册中心,eureka_service的地址eureka.client.service-url.defaultZone >package com.ybchen.product_service.controller;import com.ybchen.product_service.service.ProductService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;/** * @ClassName:ProductController * @Description:商品 * @Author:chenyb * @Date:2020/11/1 8:42 下午 * @Versiion:1.0 */@RestController@RequestMapping("/api/v1/product")public class ProductController { @Autowired private ProductService productService; /** * 商品列表 * * @return */ @PostMapping("list") public Object list() { return productService.listProduct(); } /** * 根据id查询商品 * * @param id * @return */ @GetMapping("findById") public Object findById(@RequestParam("id") int id) { return productService.findById(id); }}
Product.java


package com.ybchen.product_service.domain;import java.io.Serializable;/** * @ClassName:Product * @Description:商品实体类 * @Author:chenyb * @Date:2020/11/1 8:43 下午 * @Versiion:1.0 */public class Product implements Serializable { /** * 内码 */ private String id; /** * 商品名称 */ private String name; /** * 价格,分为单位 */ private int price; /** * 库存 */ private int store; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getStore() { return store; } public void setStore(int store) { this.store = store; } public Product() { } public Product(String id, String name, int price, int store) { this.id = id; this.name = name; this.price = price; this.store = store; } @Override public String toString() { return "product{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", price=" + price + ", store=" + store + '}'; }}
View Code
ProductService.java
package com.ybchen.product_service.service;import com.ybchen.product_service.domain.Product;import java.util.List;/** * @ClassName:ProductService * @Description:商品service * @Author:chenyb * @Date:2020/11/1 8:45 下午 * @Versiion:1.0 */public interface ProductService { /** * 商品列表 * @return */ List<Product> listProduct(); /** * 根据id查询商品 * @param id * @return */ Product findById(int id);}
ProductServiceImpl.java
package com.ybchen.product_service.service.impl;import com.ybchen.product_service.domain.Product;import com.ybchen.product_service.service.ProductService;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import java.util.*;/** * @ClassName:ProductServiceImpl * @Description:ProductService实现类 * @Author:chenyb * @Date:2020/11/1 8:47 下午 * @Versiion:1.0 */@Servicepublic class ProductServiceImpl implements ProductService { //初始化内存商品数据。模拟数据库中存储的商品 private static final Map<Integer, Product> daoMap = new HashMap<>(); @Value("${server.port}") private String port; static { for (int i = 0; i < 5; i++) { daoMap.put(i, new Product(i + "", "iphone_" + i, 1000 * i, 10)); } } @Override public List<Product> listProduct() { Collection<Product> values = daoMap.values(); return new ArrayList<>(values); } @Override public Product findById(int id) { Product product = daoMap.get(id); product.setName(product.getName()+"_"+port); return product; }}
ProductServiceApplication.java
package com.ybchen.product_service;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class ProductServiceApplication { public static void main(String[] args) { SpringApplication.run(ProductServiceApplication.class, args); }}
启动并查看监控台
启动2个服务,并查看监控台
搭建Eureka Client订单服务
创建项目
项目结构
pom.<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>order_service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>order_service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>order_service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>order_service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
application.properties
# 服务端口号server.port=8781# 服务名称spring.application.name=order-service# 将服务注册到注册中心,eureka_service的地址eureka.client.service-url.defaultZone 启动类添加Ribbon注解 @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }
package com.ybchen.order_service;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.loadbalancer.LoadBalanced;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@SpringBootApplicationpublic class OrderServiceApplication { /** * 负载均衡Ribbon * @return */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); }}
OrderController.java
package com.ybchen.order_service.controller;import com.ybchen.order_service.service.ProductOrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("api/v1/order")public class OrderController { @Autowired private ProductOrderService productOrderService; @RequestMapping("save") public Object save(@RequestParam("user_id")int userId,@RequestParam("product_id")int productId){ return productOrderService.save(userId,productId); }}
ProductOrder.java


package com.ybchen.order_service.domain;import java.util.Date;/** * 商品订单实体类 */public class ProductOrder { /** * 主键 */ private int id; /** * 商品名称 */ private String productName; /** * 订单流水号 */ private String tradeNo; /** * 价格,以分位单位 */ private int price; /** * 创建时间 */ private Date createTime; /** * 用户id */ private String userId; /** * 用户名称 */ private String userName; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getProductName() { return productName; } public void setProductName(String productName) { this.productName = productName; } public String getTradeNo() { return tradeNo; } public void setTradeNo(String tradeNo) { this.tradeNo = tradeNo; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public String toString() { return "ProductOrder{" + "id=" + id + ", productName='" + productName + '\'' + ", tradeNo='" + tradeNo + '\'' + ", price=" + price + ", createTime=" + createTime + ", userId='" + userId + '\'' + ", userName='" + userName + '\'' + '}'; }}
View CodeProductOrderService.java
package com.ybchen.order_service.service;import com.ybchen.order_service.domain.ProductOrder;public interface ProductOrderService { ProductOrder save(int userId, int productId);}
ProductOrderServiceImpl.java
package com.ybchen.order_service.service.impl;import com.ybchen.order_service.domain.ProductOrder;import com.ybchen.order_service.service.ProductOrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.UUID;/** * @ClassName:ProductOrderServiceImpl * @Description:产品订单实现类 * @Author:chenyb * @Date:2020/11/2 11:34 下午 * @Versiion:1.0 */@Servicepublic class ProductOrderServiceImpl implements ProductOrderService { @Autowired private RestTemplate restTemplate; /** * 下单接口 * @param userId 用户id * @param productId 产品id * @return */ @Override public ProductOrder save(int userId, int productId) { Object obj=productId; //get方式 Object forObject = restTemplate.getForObject("http://product-service/api/v1/product/findById?id=" + productId, Object.class); //post方式// Map<String,String> map=new HashMap<>();// map.put("id","1");// String s = restTemplate.postForObject("", map, String.class);// System.out.println(s); System.out.println(forObject); //获取商品详情 ProductOrder productOrder=new ProductOrder(); productOrder.setTradeNo(UUID.randomUUID().toString()); productOrder.setCreateTime(new Date()); productOrder.setUserId(userId+""); return productOrder; }}
测试负载均衡


feign实战
简介
改造订单服务,调用商品服务获取商品信息
官网例子
点我直达
改造订单服务
添加feign依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<??><project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.18.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.ybchen</groupId> <artifactId>order_service</artifactId> <version>0.0.1-SNAPSHOT</version> <name>order_service</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--openfeign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build></project>
启动类上添加注解
启动类上添加:@EnableFeignClients

添加一个接口

ProductClient.java
package com.ybchen.order_service.service;import org.springframework.cloud.openfeign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;/** * 商品服务客户端 */// name=商品服务的服务名==========》[email protected](name = "product-service")@RequestMapping("/api/v1/product")public interface ProductClient { @GetMapping("findById") String findById(@RequestParam("id") int id);}
修改ProductOrderServiceImpl.java
原先
package com.ybchen.order_service.service.impl;import com.ybchen.order_service.domain.ProductOrder;import com.ybchen.order_service.service.ProductOrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.client.RestTemplate;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.UUID;/** * @ClassName:ProductOrderServiceImpl * @Description:产品订单实现类 * @Author:chenyb * @Date:2020/11/2 11:34 下午 * @Versiion:1.0 */@Servicepublic class ProductOrderServiceImpl implements ProductOrderService { @Autowired private RestTemplate restTemplate; /** * 下单接口 * @param userId 用户id * @param productId 产品id * @return */ @Override public ProductOrder save(int userId, int productId) { Object obj=productId; //get方式 Object forObject = restTemplate.getForObject("http://product-service/api/v1/product/findById?id=" + productId, Object.class); //post方式// Map<String,String> map=new HashMap<>();// map.put("id","1");// String s = restTemplate.postForObject("", map, String.class);// System.out.println(s); System.out.println(forObject); //获取商品详情 ProductOrder productOrder=new ProductOrder(); productOrder.setTradeNo(UUID.randomUUID().toString()); productOrder.setCreateTime(new Date()); productOrder.setUserId(userId+""); return productOrder; }}
修改为

package com.ybchen.order_service.service.impl;import com.ybchen.order_service.domain.ProductOrder;import com.ybchen.order_service.service.ProductClient;import com.ybchen.order_service.service.ProductOrderService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.Date;import java.util.UUID;/** * @ClassName:ProductOrderServiceImpl * @Description:产品订单实现类 * @Author:chenyb * @Date:2020/11/2 11:34 下午 * @Versiion:1.0 */@Servicepublic class ProductOrderServiceImpl implements ProductOrderService { @Autowired private ProductClient productClient; /** * 下单接口 * * @param userId 用户id * @param productId 产品id * @return */ @Override public ProductOrder save(int userId, int productId) { //-----------调用商品服务开始------------ String byId = productClient.findById(productId); System.out.println(byId); //-----------调用商品服务结束------------ //获取商品详情 ProductOrder productOrder = new ProductOrder(); productOrder.setTradeNo(UUID.randomUUID().toString()); productOrder.setCreateTime(new Date()); productOrder.setUserId(userId + ""); return productOrder; }}
测试商品服务