微服务工程搭建

痛定思痛。 2022-05-15 17:56 320阅读 0赞

SpringCloud 2018

  • 微服务概述
  • SpringCloud 概述
  • 微服务工程搭建
  • Eureka 服务注册与发现
  • Ribbon 客户端负载均衡
  • Feign 服务接口调用
  • Hystrix 断路器
  • Zuul 路由网关
  • SpringCloud Config 分布式配置中心
  • SpringCloud 技术梳理

GitHub

  • https://github.com/hjyang19/microservicecloud.git
  • https://github.com/hjyang19/microservicecloud-config.git

微服务工程搭建

  • 1-总体概述
    • 1.1-版本信息
    • 1.2-案例说明
    • 1.3-Maven 模块化
  • 2-搭建步骤
    • 2.1-父工程 microservicecloud
    • 2.2-公共模块 microservicecloud-api
    • 2.3-提供者服务 microservicecloud-provider-dept-8001
    • 2.4-消费者服务 microservicecloud-consumer-dept-80

1-总体概述

1.1-版本信息

  • SpringBoot 版本:1.5.9.RELEASE
  • SpringCloud 版本:Dalston.SR1

1.2-案例说明

以 Dept 部门模块做一个微服务的通用案例,Consumer 消费者(Client)通过 Rest 调用 Provider 提供者(Server)提供服务。

1.3-Maven 模块化

简单的 Maven 模块结构是这样的:父项目(app-parent)聚合很多子项目(app-util、app-dao、app-service、app-web)。

  1. |------app-parent
  2. |---pom.xml(pom)
  3. |------app-util
  4. |---pom.xml(jar)
  5. |------app-dao
  6. |---pom.xml(jar)
  7. |------app-service
  8. |---pom.xml(jar)
  9. |------app-web
  10. |---pom.xml(war)

将案例拆分成如下模块:

microservicecloud:父工程(Project)下带着 3 个子模块(Module)

  • microservicecloud-api(封装整体 Entity、接口、公共配置等)
  • microservicecloud-provider-dept-8001(微服务服务提供者)
  • microservicecloud-consumer-dept-80(微服务服务消费者)

2-搭建步骤

2.1-父工程 microservicecloud

a、新建父工程 microservicecloud
在这里插入图片描述

  1. <groupId>com.atguigu.springcloud</groupId>
  2. <artifactId>microservicecloud</artifactId>
  3. <version>1.0-SNAPSHOT</version>

在这里插入图片描述
b、删除父工程 microservicecloud 中无用的 src 文件夹
在这里插入图片描述
c、修改父工程 microservicecloud 中 pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.atguigu.springcloud</groupId>
  5. <artifactId>microservicecloud</artifactId>
  6. <version>1.0-SNAPSHOT</version>
  7. <packaging>pom</packaging>
  8. <properties>
  9. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  10. <maven.compiler.source>1.8</maven.compiler.source>
  11. <maven.compiler.target>1.8</maven.compiler.target>
  12. <junit.version>4.12</junit.version>
  13. <log4j.version>1.2.17</log4j.version>
  14. <lombok.version>1.16.18</lombok.version>
  15. </properties>
  16. <dependencyManagement>
  17. <dependencies>
  18. <dependency>
  19. <groupId>org.springframework.cloud</groupId>
  20. <artifactId>spring-cloud-dependencies</artifactId>
  21. <version>Dalston.SR1</version>
  22. <type>pom</type>
  23. <scope>import</scope>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-dependencies</artifactId>
  28. <version>1.5.9.RELEASE</version>
  29. <type>pom</type>
  30. <scope>import</scope>
  31. </dependency>
  32. <dependency>
  33. <groupId>mysql</groupId>
  34. <artifactId>mysql-connector-java</artifactId>
  35. <version>5.0.4</version>
  36. </dependency>
  37. <dependency>
  38. <groupId>com.alibaba</groupId>
  39. <artifactId>druid</artifactId>
  40. <version>1.0.31</version>
  41. </dependency>
  42. <dependency>
  43. <groupId>org.mybatis.spring.boot</groupId>
  44. <artifactId>mybatis-spring-boot-starter</artifactId>
  45. <version>1.3.0</version>
  46. </dependency>
  47. <dependency>
  48. <groupId>ch.qos.logback</groupId>
  49. <artifactId>logback-core</artifactId>
  50. <version>1.2.3</version>
  51. </dependency>
  52. <dependency>
  53. <groupId>junit</groupId>
  54. <artifactId>junit</artifactId>
  55. <version>${junit.version}</version>
  56. <scope>test</scope>
  57. </dependency>
  58. <dependency>
  59. <groupId>log4j</groupId>
  60. <artifactId>log4j</artifactId>
  61. <version>${log4j.version}</version>
  62. </dependency>
  63. </dependencies>
  64. </dependencyManagement>
  65. </project>

切记 packaging 是 pom 模式:定义 pom 类型,将后续各个子模块公共的 jar 包等统一提取出来,类似抽象父类 pom 文件。
在这里插入图片描述

2.2-公共模块 microservicecloud-api

a、右击父工程 microservicecloud,新建子模块 microservicecloud-api
在这里插入图片描述
在这里插入图片描述
b、查看父工程 microservicecloud 中 pom.xml 变化
在这里插入图片描述
c、修改子模块 microservicecloud-api 中 pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <!-- 子类里显示声明才能有继承表现,无意外就是父类的默认版本,否则自己定义 -->
  5. <parent>
  6. <groupId>com.atguigu.springcloud</groupId>
  7. <artifactId>microservicecloud</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <artifactId>microservicecloud-api</artifactId>
  11. <!-- 当前 Module 所需 jar 包,按需求添加,若父类已包含可不写版本号 -->
  12. <dependencies>
  13. <dependency>
  14. <groupId>org.projectlombok</groupId>
  15. <artifactId>lombok</artifactId>
  16. </dependency>
  17. </dependencies>
  18. </project>

d、修改子模块 microservicecloud-api,目录 /src/main/java 中新建包 com.atguigu.springcloud.entities

e、修改子模块 microservicecloud-api,包 com.atguigu.springcloud.entities 中新建类 Dept.java

配合 Lombok 使用

  1. package com.atguigu.springcloud.entities;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. import lombok.experimental.Accessors;
  5. import java.io.Serializable;
  6. @Data
  7. @NoArgsConstructor
  8. @Accessors(chain = true)
  9. @SuppressWarnings("serial")
  10. public class Dept implements Serializable {// 必须序列化
  11. private Long deptno;// 主键
  12. private String dname;// 部门名称
  13. // 来自哪个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库
  14. private String db_source;
  15. public Dept(String dname) {
  16. super();
  17. this.dname = dname;
  18. }
  19. }

f、子模块 microservicecloud-api,执行 Maven 命令 mvn clean install
在这里插入图片描述
执行 mvn clean install 命令打包到 Maven 本地仓库,给其它模块引用达到通用目的。即需要用到部门实体的话,不用每个工程都定义一份,直接引用本模块即可。

2.3-提供者服务 microservicecloud-provider-dept-8001

a、新建 jdbc:mysql://localhost:3306/cloudDB01 数据库

子模块 microservicecloud-provider-dept-8001 连接 jdbc:mysql://localhost:3306/cloudDB01 数据库。

  1. DROP DATABASE IF EXISTS cloudDB01;
  2. CREATE DATABASE cloudDB01 CHARACTER SET UTF8;
  3. USE cloudDB01;
  4. CREATE TABLE dept (
  5. deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
  6. dname VARCHAR(60),
  7. db_source VARCHAR(60)
  8. );
  9. INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE());
  10. INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
  11. INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE());
  12. INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE());
  13. INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());
  14. SELECT * FROM dept;

b、右击父工程 microservicecloud,新建子模块 microservicecloud-provider-dept-8001
在这里插入图片描述
c、修改子模块 microservicecloud-provider-dept-8001 中 pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>com.atguigu.springcloud</groupId>
  6. <artifactId>microservicecloud</artifactId>
  7. <version>1.0-SNAPSHOT</version>
  8. </parent>
  9. <artifactId>microservicecloud-provider-dept-8001</artifactId>
  10. <dependencies>
  11. <!-- 引入自定义模块 microservicecloud-api 包,可使用 Dept 部门 Entity -->
  12. <dependency>
  13. <groupId>com.atguigu.springcloud</groupId>
  14. <artifactId>microservicecloud-api</artifactId>
  15. <version>${project.version}</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>junit</groupId>
  19. <artifactId>junit</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>mysql</groupId>
  23. <artifactId>mysql-connector-java</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>com.alibaba</groupId>
  27. <artifactId>druid</artifactId>
  28. </dependency>
  29. <dependency>
  30. <groupId>ch.qos.logback</groupId>
  31. <artifactId>logback-core</artifactId>
  32. </dependency>
  33. <dependency>
  34. <groupId>org.mybatis.spring.boot</groupId>
  35. <artifactId>mybatis-spring-boot-starter</artifactId>
  36. </dependency>
  37. <dependency>
  38. <groupId>org.springframework.boot</groupId>
  39. <artifactId>spring-boot-starter-jetty</artifactId>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.springframework.boot</groupId>
  43. <artifactId>spring-boot-starter-web</artifactId>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.springframework.boot</groupId>
  47. <artifactId>spring-boot-starter-test</artifactId>
  48. </dependency>
  49. <!-- 热部署:修改后立即生效 -->
  50. <dependency>
  51. <groupId>org.springframework</groupId>
  52. <artifactId>springloaded</artifactId>
  53. </dependency>
  54. <dependency>
  55. <groupId>org.springframework.boot</groupId>
  56. <artifactId>spring-boot-devtools</artifactId>
  57. </dependency>
  58. </dependencies>
  59. </project>

d、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/resources 中新建 application.yml

  1. server:
  2. port: 8001
  3. spring:
  4. application:
  5. name: microservicecloud-dept
  6. datasource:
  7. # 数据源操作类型
  8. type: com.alibaba.druid.pool.DruidDataSource
  9. # MySQL 驱动包
  10. driver-class-name: org.gjt.mm.mysql.Driver
  11. # 数据库名称
  12. url: jdbc:mysql://localhost:3306/cloudDB01
  13. username: root
  14. password: 123456
  15. dbcp2:
  16. # 数据库连接池的最小维持连接数
  17. min-idle: 5
  18. # 初始化连接数
  19. initial-size: 5
  20. # 最大连接数
  21. max-total: 5
  22. # 等待连接获取的最大超时时间
  23. max-wait-millis: 200
  24. mybatis:
  25. # Mybatis 配置文件路径
  26. config-location: classpath:mybatis/mybatis.cfg.xml
  27. # 所有 Entity 别名类所在包
  28. type-aliases-package: com.atguigu.springcloud.entities
  29. mapper-locations:
  30. # Mapper 映射文件
  31. - classpath:mybatis/mapper/**/*.xml

e、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/resources 中新建目录 mybatis

f、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/resources/mybatis 中新建 mybatis.cfg.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
  3. <configuration>
  4. <settings>
  5. <!-- 二级缓存开启 -->
  6. <setting name="cacheEnabled" value="true"/>
  7. </settings>
  8. </configuration>

g、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/java 中新建包 com.atguigu.springcloud.dao

h、修改子模块 microservicecloud-provider-dept-8001,包 com.atguigu.springcloud.dao 中新建接口 DeptDao.java

  1. package com.atguigu.springcloud.dao;
  2. import com.atguigu.springcloud.entities.Dept;
  3. import org.apache.ibatis.annotations.Mapper;
  4. import java.util.List;
  5. @Mapper
  6. public interface DeptDao {
  7. public boolean addDept(Dept dept);
  8. public Dept findById(Long id);
  9. public List<Dept> findAll();
  10. }

i、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/resources/mybatis 中新建目录 mapper

j、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/resources/mybatis/mapper 中新建 DeptMapper.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <mapper namespace="com.atguigu.springcloud.dao.DeptDao">
  5. <select id="findById" resultType="Dept" parameterType="Long">
  6. select deptno, dname, db_source from dept where deptno=#{deptno};
  7. </select>
  8. <select id="findAll" resultType="Dept">
  9. select deptno, dname, db_source from dept;
  10. </select>
  11. <insert id="addDept" parameterType="Dept">
  12. INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE());
  13. </insert>
  14. </mapper>

k、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/java 中新建包 com.atguigu.springcloud.service

l、修改子模块 microservicecloud-provider-dept-8001,包 com.atguigu.springcloud.service 中新建接口 DeptService.java

  1. package com.atguigu.springcloud.service;
  2. import com.atguigu.springcloud.entities.Dept;
  3. import java.util.List;
  4. public interface DeptService {
  5. public boolean add(Dept dept);
  6. public Dept get(Long id);
  7. public List<Dept> list();
  8. }

m、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/java 中新建包 com.atguigu.springcloud.service.impl

n、修改子模块 microservicecloud-provider-dept-8001,包 com.atguigu.springcloud.service.impl 中新建实现类 DeptServiceImpl.java

  1. package com.atguigu.springcloud.service.impl;
  2. import com.atguigu.springcloud.dao.DeptDao;
  3. import com.atguigu.springcloud.entities.Dept;
  4. import com.atguigu.springcloud.service.DeptService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import java.util.List;
  8. @Service
  9. public class DeptServiceImpl implements DeptService {
  10. @Autowired
  11. private DeptDao dao;
  12. @Override
  13. public boolean add(Dept dept) {
  14. return dao.addDept(dept);
  15. }
  16. @Override
  17. public Dept get(Long id) {
  18. return dao.findById(id);
  19. }
  20. @Override
  21. public List<Dept> list() {
  22. return dao.findAll();
  23. }
  24. }

o、修改子模块 microservicecloud-provider-dept-8001,目录 /src/main/java 中新建包 com.atguigu.springcloud.controller

p、修改子模块 microservicecloud-provider-dept-8001,包 com.atguigu.springcloud.controller 中新建类 DeptController.java

  1. package com.atguigu.springcloud.controller;
  2. import com.atguigu.springcloud.entities.Dept;
  3. import com.atguigu.springcloud.service.DeptService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.*;
  6. import java.util.List;
  7. @RestController
  8. public class DeptController {
  9. @Autowired
  10. private DeptService service;
  11. @RequestMapping(value = "/dept/add", method = RequestMethod.POST)
  12. public boolean add(@RequestBody Dept dept) {
  13. return service.add(dept);
  14. }
  15. @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
  16. public Dept get(@PathVariable("id") Long id) {
  17. return service.get(id);
  18. }
  19. @RequestMapping(value = "/dept/list", method = RequestMethod.GET)
  20. public List<Dept> list() {
  21. return service.list();
  22. }
  23. }

q、修改子模块 microservicecloud-provider-dept-8001,包 com.atguigu.springcloud 中新建启动类 DeptProvider8001_App.java

  1. package com.atguigu.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class DeptProvider8001_App {
  6. public static void main(String[] args) {
  7. SpringApplication.run(DeptProvider8001_App.class, args);
  8. }
  9. }

r、测试子模块 microservicecloud-provider-dept-8001

  • 启动子模块 microservicecloud-provider-dept-8001
  • http://localhost:8001/dept/get/2
    在这里插入图片描述
  • http://localhost:8001/dept/list
    在这里插入图片描述

2.4-消费者服务 microservicecloud-consumer-dept-80

a、右击父工程 microservicecloud,新建子模块 microservicecloud-consumer-dept-80
在这里插入图片描述
b、修改子模块 microservicecloud-consumer-dept-80 中 pom.xml

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <parent>
  5. <groupId>com.atguigu.springcloud</groupId>
  6. <artifactId>microservicecloud</artifactId>
  7. <version>1.0-SNAPSHOT</version>
  8. </parent>
  9. <artifactId>microservicecloud-consumer-dept-80</artifactId>
  10. <dependencies>
  11. <!-- 引入自定义模块 -->
  12. <dependency>
  13. <groupId>com.atguigu.springcloud</groupId>
  14. <artifactId>microservicecloud-api</artifactId>
  15. <version>${project.version}</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <!-- 热部署:修改后立即生效 -->
  22. <dependency>
  23. <groupId>org.springframework</groupId>
  24. <artifactId>springloaded</artifactId>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-devtools</artifactId>
  29. </dependency>
  30. </dependencies>
  31. </project>

c、修改子模块 microservicecloud-consumer-dept-80,目录 /src/main/resources 中新建 application.yml

  1. server:
  2. port: 80

d、修改子模块 microservicecloud-consumer-dept-80,目录 /src/main/java 中新建包 com.atguigu.springcloud.cfgbeans

e、修改子模块 microservicecloud-consumer-dept-80,包 com.atguigu.springcloud.cfgbeans 中新建类 ConfigBean.java

类似 Spring 里面 applicationContext.xml 写的注入 Bean。

  1. package com.atguigu.springcloud.cfgbeans;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.web.client.RestTemplate;
  5. @Configuration
  6. public class ConfigBean {
  7. @Bean
  8. public RestTemplate getRestTemplate() {
  9. return new RestTemplate();
  10. }
  11. }

RestTemplate 是什么?

RestTemplate 提供了多种便捷访问远程 Http 服务的方法,是一种简单便捷的访问 Restful 服务模板类,是 Spring 提供的用于访问 Rest 服务的客户端模板工具集

RestTemplate 官网及使用

  • 官网:https://docs.spring.io/spring-framework/docs/4.3.7.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
  • 使用:使用 RestTemplate 访问 Restful 接口非常的简单粗暴无脑(url, requestMap, ResponseBean.class),这三个参数分别代表 Rest 请求地址、请求参数、Http 响应转换被转换成的对象类型。

f、修改子模块 microservicecloud-consumer-dept-80,目录 /src/main/java 中新建包 com.atguigu.springcloud.controller

g、修改子模块 microservicecloud-consumer-dept-80,包 com.atguigu.springcloud.controller 中新建类 DeptController_Consumer.java

  1. package com.atguigu.springcloud.controller;
  2. import com.atguigu.springcloud.entities.Dept;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.web.bind.annotation.PathVariable;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import org.springframework.web.client.RestTemplate;
  8. import java.util.List;
  9. @RestController
  10. public class DeptController_Consumer {
  11. private static final String REST_URL_PREFIX = "http://localhost:8001";
  12. @Autowired
  13. private RestTemplate restTemplate;
  14. @RequestMapping(value = "/consumer/dept/add")
  15. public boolean add(Dept dept) {
  16. return restTemplate.postForObject(REST_URL_PREFIX + "/dept/add", dept, Boolean.class);
  17. }
  18. @RequestMapping(value = "/consumer/dept/get/{id}")
  19. public Dept get(@PathVariable("id") Long id) {
  20. return restTemplate.getForObject(REST_URL_PREFIX + "/dept/get/" + id, Dept.class);
  21. }
  22. @SuppressWarnings("unchecked")
  23. @RequestMapping(value = "/consumer/dept/list")
  24. public List<Dept> list() {
  25. return restTemplate.getForObject(REST_URL_PREFIX + "/dept/list", List.class);
  26. }
  27. }

h、修改子模块 microservicecloud-consumer-dept-80,包 com.atguigu.springcloud 中新建启动类 DeptConsumer80_App.java

  1. package com.atguigu.springcloud;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class DeptConsumer80_App {
  6. public static void main(String[] args) {
  7. SpringApplication.run(DeptConsumer80_App.class, args);
  8. }
  9. }

i、测试子模块 microservicecloud-consumer-dept-80

  • 启动子模块 microservicecloud-provider-dept-8001
  • 启动子模块 microservicecloud-consumer-dept-80
  • http://localhost/consumer/dept/get/2
    在这里插入图片描述
  • http://localhost/consumer/dept/list
    在这里插入图片描述
  • http://localhost/consumer/dept/add?dname=AI
    在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,320人围观)

还没有评论,来说两句吧...

相关阅读