分享

Spring Boot Maven多模块项目搭建

 quasiceo 2018-08-18

Spring Boot(2.0) Maven多模块项目搭建简介

版本号 说明 创建时间 创建人
1.0 创建 2018-05-15 吴桂镇




一、搭建环境

-编译器:Eclipse Oxygen.1a (4.7.1a)

-jdk:1.8

-Maven : 3.0

-操作系统:win10

二、项目创建

1.parent

新建一个maven project 如下图

点击next

填写相关信息,点击finish。注意Packaging 应选择pom

创建之后效果如下图

删除 src文件夹,并修改pom.xml。修改后修过如下图,

其中<parent></parent>中是对spring boot的集成

<modules></modules>是对maven子模块项目的引用,正常情况下创建子模块后才在parent的pom.xml中添加一条对应的module,此处预先添加好。

2.core

创建maven项目

点击finish 创建完毕。

修改pom.xml

添加<parent>对父模块的依赖,修改后如下图

3.api

创建过程类似于core 但是在pom.xml中添加对core的依赖

4.service

Service 为springboot项目,使用eclipse创建时应先添加spring sts插件,或者去 http://start.下载完成后导入进来,下面介绍使用sts插件创建的。

创建完毕之后修pom.xml,修改<parent>里的引用,从spring-boot-starter-parent 到 demo-parent,再引用api和core。

因为service不是一个web应用,可以不依赖spring-boot-starter-web

5.web

Web也是一个springboot的项目,创建过程与service类似,只是在pom.xml中增加了下面的依赖。

三、集成dubbo

1.在api中添加接口和对应的实体类

demo以themis数据库intf_fee表为例

实体类:

@SuppressWarnings("serial")

public** class IntfFee implements** Serializable{

    **private** String intfId;

**private** String plateCde;

    **private** String intfName;

**private** BigDecimal intfCost;

**private** BigDecimal intfPrice;

**private** String classType;

**private** String intfStatus;

**private** String remark;

**private** BigDecimal feeRowBegin;

**private** BigDecimal feeRowEnd;

**public** String getIntfId() {

    **return** intfId;

}

**public**** void** setIntfId(String intfId) {

    **this**.intfId = intfId;

}

**public** String getPlateCde() {

    **return** plateCde;

}

**public**** void** setPlateCde(String plateCde) {

    **this**.plateCde = plateCde;

}

**public** String getIntfName() {

    **return** intfName;

}

**public**** void** setIntfName(String intfName) {

    **this**.intfName = intfName;

}

**public** BigDecimal getIntfCost() {

    **return** intfCost;

}

**public**** void** setIntfCost(BigDecimal intfCost) {

    **this**.intfCost = intfCost;

}

**public** BigDecimal getIntfPrice() {

    **return** intfPrice;

}

**public**** void** setIntfPrice(BigDecimal intfPrice) {

    **this**.intfPrice = intfPrice;

}

**public** String getClassType() {

    **return** classType;

}

**public**** void** setClassType(String classType) {

    **this**.classType = classType;

}

**public** String getIntfStatus() {

    **return** classType;

}

**public**** void** setIntfStatus(String intfStatus) {

    **this**.intfStatus = intfStatus;

}

**public** String getRemark() {

    **return** remark;

}

**public**** void** setRemark(String remark) {

    **this**.remark = remark;

}

**public** BigDecimal getFeeRowBegin() {

            **return** feeRowBegin;

    }

    **public**** void** setFeeRowBegin(BigDecimal feeRowBegin) {

            **this**.feeRowBegin = feeRowBegin;

    }

    **public** BigDecimal getFeeRowEnd() {

            **return** feeRowEnd;

    }

    **public**** void** setFeeRowEnd(BigDecimal feeRowEnd) {

            **this**.feeRowEnd = feeRowEnd;

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140

接口

public** interface** IDemoService {

    String sayHello(String message);
  • 1
  • 2

}

2.配置服务端

在demo-service pom.xml中增加dubbo的依赖,如下

<!–dubbo-springBoot依赖–>

     <dependency>

               <groupId>com.alibaba.spring.boot</groupId>

               <artifactId>dubbo-spring-boot-starter</artifactId>

               <version>2.0.0</version>

     </dependency>

     <dependency>

         <groupId>com.101tec</groupId>

         <artifactId>zkclient</artifactId>

         <version>0.2</version>

  </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在application.properties中添加dubbo的相关配置,如下

dubbospringboot 配置

spring.dubbo.application.id=provider

spring.dubbo.application.name=provider

spring.dubbo.registry.address=zookeeper://127.0.0.1:2181

spring.dubbo.server=true

spring.dubbo.protocol.name=dubbo

spring.dubbo.protocol.port=20880

在启动类中添加@EnableDubboConfiguration注解

编写service

3.配置消费端

在demo-web的pom.xml添加依赖

     <!--dubbo-springBoot依赖-->

     <dependency>

               <groupId>com.alibaba.spring.boot</groupId>

               <artifactId>dubbo-spring-boot-starter</artifactId>

               <version>${dubbo-spring-boot.version}</version>

     </dependency>

     <dependency>

         <groupId>com.101tec</groupId>

         <artifactId>zkclient</artifactId>

         <version>${zk-client.version}</version>

  </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在application.properties中添加dubbo的配置

Dubbo 服务消费者配置

spring.dubbo.application.name=consumer

spring.dubbo.application.id=consumer

spring.dubbo.protocol.port=20800

spring.dubbo.protocol.name=dubbo

spring.dubbo.registry.address=zookeeper://127.0.0.1:2181

注册中心请求超时时间

设置操作设置消费者超时时间(通过DubboConfig去读取,配置),默认使用服务端的超时时间,客户端配置时间则需要读取配置

然后新增dubboContext.xml 其中配置<dubbo:consumer timeout="${spring.dubbo.consumer.timeout}" cluster="failfast"/>

此项目使用服务端配置超时时间,故没有新增dubboContext.xml文件

spring.dubbo.consumer.timeout=300006

包路径也可以单独配置出dubbo包,将与dubbo交互的内容都存放在此处,分层明确

spring.dubbo.scan=com.caxs

在启动类中添加 @EnableDubboConfiguration 注解

编写测试controller

@RestController

public** class** TestController {

    @Reference

    **private** IDemoService demoService;

    @RequestMapping("/")

    **public** String sayHello(String msg) {

            **return** demoService.sayHello(msg);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

}

注:使用@Reference来引用服务端提供的服务

四、集成mybatis

使用mysql 数据库

在demo-service中添加相应的依赖(mybatis,mysql,连接池)

     <dependency>

             <groupId>com.alibaba</groupId>

             <artifactId>druid</artifactId>

             <version>${druid.version}</version>

     </dependency>

     <dependency>

                    <groupId>org.mybatis.spring.boot</groupId>

                    <artifactId>mybatis-spring-boot-starter</artifactId>

                    <version>1.3.2</version>

     </dependency>

     <dependency>

                    <groupId>mysql</groupId>

                    <artifactId>mysql-connector-java</artifactId>

                    <scope>runtime</scope>

     </dependency>

     <dependency>

               <groupId>org.mybatis</groupId>

               <artifactId>mybatis</artifactId>

               <version>${mybatis.version}</version>

     </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

在配置文件中添加配置,采用yml格式的如下

spring:

application:

name: demo-service

#DATABASE CONFIG
  • 1
  • 2
  • 3
  • 4

datasource:

driver-class-name: com.mysql.jdbc.Driver

url: your url

username: your username

password: your password

type: com.alibaba.druid.pool.DruidDataSource   #这里是配置druid连接池,以下都是druid的配置信息

filters: stat,wall,log4j

maxActive: 20

initialSize: 1

maxWait: 60000

minIdle: 1

timeBetweenEvictionRunsMillis: 60000

minEvictableIdleTimeMillis: 300000

validationQuery: select 'x'

testWhileIdle: **true**

testOnBorrow: **false**

testOnReturn: **false**

poolPreparedStatements: **true**

maxOpenPreparedStatements: 20

connection-properties: druid.stat.merggSql=ture;druid.stat.slowSqlMillis=5000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

mybatis

mybatis:

mapper-locations: classpath*:/daos/**Dao.xml #把xml文件放在com.XX.mapper.*中可能会出现找到的问题,这里把他放在resource下的mapper中

#实体扫描,多个package用逗号或者分号分隔

#typeAliasesPackage: com.tdx.account_service.entity #这里是实体类的位置

configuration:

map-underscore-to-camel-case: **true**

cache-enabled: **false**
  • 1
  • 2
  • 3
  • 4

logging 不同的目录不同的日志输出级别

logging:

level:

root: info
  • 1
  • 2

com.wugz.demo: debug

添加dao层的接口和xml文件(此处示例使用注解的方式代替xml)

接口:

@Mapper

public interface IntfFeeDao {

    /\*\*

    \* 方式1:使用注解编写SQL。

    \*/

    //@Select("select \* from intf\_fee")

    List<Map<String,Object>> list();



    /\*\*

    \*

    \* PS:如果符合下划线转驼峰的匹配项可以直接省略不写。

    \* 不匹配的例子  比如数据库字段为 PHONE\_NUM 实体类字段为mobileNum

    \* 即可以做一个强行映射

    \*

    \*/

    @Results({ @Result(property = "id", column = "ID"), @Result(property = "name", column = "Name"),

                    @Result(property = "countryCode", column = "CountryCode"),

                    @Result(property = "district", column = "District"),

                    @Result(property = "population", column = "Population")})

    @Select("select \* from intf\_fee")

    List<City> listSample();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

}

在对应的service中注入dao层(使用@Autowired自动注入)

五、集成activeMQ

在demo-web中添加对应的依赖

 <dependency>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-activemq</artifactId>

  </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在配置文件中添加mq的配置

spring.activemq.broker-url=tcp://127.0.0.1:61616

spring.activemq.user=admin

spring.activemq.password=admin

spring.activemq.in-memory=false

mq生产者类:

@Component("queueSender")

public** class** QueueSender {

    @Autowired

    **private** JmsMessagingTemplate jmsMessagingTemplate;



    /\*\*\*

    \*

    \* **@Description** (功能描述)    :  发送消息

    \* **@author** (作者)             :  吴桂镇

    \* **@date** (开发日期)          :  2018年5月9日 下午5:11:46

    \* **@exception**                :

    \* **@param** queueName

    \* **@param** message  void

    \*/

    **public**** void**sendString(String queueName,**final** String message){

            jmsMessagingTemplate.convertAndSend(queueName, message);

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

}

mq消费者:

    // 使用JmsListener配置消费者监听的队列,其中text是接收到的消息

@JmsListener(destination = "test.queue")

**public**** void** receiveQueue(String text) {

        **LOGGER**.info("Consumer收到的报文为:"+text);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

}

六、集成redis

Windows本地redis创建参考

https://www.cnblogs.com/sxdcgaq8080/p/7204878.html

在service中添加相应的依赖

  <!-- Spring Boot Reids 依赖 -->

     <dependency>

                    <groupId>org.springframework.boot</groupId>

                    <artifactId>spring-boot-starter-data-redis</artifactId>

  </dependency>

     <!--spring2.0集成redis所需common-pool2-->

     <dependency>

         <groupId>org.apache.commons</groupId>

         <artifactId>commons-pool2</artifactId>

         <version>2.4.2</version>

     </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在配置文件中添加相应配置

spring:

redis:

  #数据库索引

  database: 0

  host: 127.0.0.1

  port: 6379

  password:

  jedis:

    pool:

      #最大连接数

      max-active: 8

      #最大阻塞等待时间(负数表示没限制)

      max-wait: -1

      #最大空闲

      max-idle: 8

      #最小空闲

      min-idle: 0

  #连接超时时间

  timeout: 10000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

添加redis的配置类和自定义序列化类

@Configuration

@ConditionalOnClass(RedisOperations.class)

@EnableConfigurationProperties(RedisProperties.class)

public class RedisConfig {

@Bean

@ConditionalOnMissingBean(name = "redisTemplate")

public RedisTemplate<Object, Object> redisTemplate(

        RedisConnectionFactory redisConnectionFactory) {

    RedisTemplate<Object, Object> template = new RedisTemplate<>();

    //使用fastjson序列化

    FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<Object>(Object.class);

    // value值的序列化采用fastJsonRedisSerializer

    template.setValueSerializer(fastJsonRedisSerializer);

    template.setHashValueSerializer(fastJsonRedisSerializer);

    // key的序列化采用StringRedisSerializer

    template.setKeySerializer(new StringRedisSerializer());

    template.setHashKeySerializer(new StringRedisSerializer());

    template.setConnectionFactory(redisConnectionFactory);

    return template;

}

@Bean

@ConditionalOnMissingBean(StringRedisTemplate.class)

public StringRedisTemplate stringRedisTemplate(

        RedisConnectionFactory redisConnectionFactory) {

    StringRedisTemplate template = new StringRedisTemplate();

    template.setConnectionFactory(redisConnectionFactory);

    return template;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

}

public** class FastJsonRedisSerializer<T> implements** RedisSerializer<T> {

**public**** static ****final** Charset **DEFAULT\_CHARSET** = Charset._forName_("UTF-8");

**private** Class<T> clazz;

**public** FastJsonRedisSerializer(Class<T> clazz) {

    **super** ();

    **this**.clazz = clazz;

}

@Override

**public**** byte**[] serialize(T t)**throws** SerializationException {

    **if** ( **null** == t) {

        **return**** new ****byte** [0];

    }

    **return** JSON._toJSONString_(t, SerializerFeature. **WriteClassName** ).getBytes( **DEFAULT\_CHARSET** );

}

@Override

**public** T deserialize( **byte** [] bytes) **throws** SerializationException {

    **if** ( **null** == bytes || bytes.length <= 0) {

        **return**** null**;

    }

    String str = **new** String(bytes, **DEFAULT\_CHARSET** );

    **return** (T) JSON._parseObject_(str, clazz);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

}

编写操作redis的类

@Service

@org.springframework.stereotype.Service

public class RedisService implements IRedisService{

@Autowired

private RedisTemplate redisTemplate;

/\*\*

 \* 写入缓存

 \* @param key

 \* @param value

 \* @return

 \*/

@Override

public boolean set(final String key, Object value) {

    boolean result = false;

    try {

        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

        operations.set(key, value);

        result = true;

    } catch (Exception e) {

        e.printStackTrace();

    }

    return result;

}

/\*\*

 \* 写入缓存设置时效时间

 \* @param key

 \* @param value

 \* @return

 \*/

@Override

public boolean set(final String key, Object value, Long expireTime) {

    boolean result = false;

    try {

        ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

        operations.set(key, value);

        redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);

        result = true;

    } catch (Exception e) {

        e.printStackTrace();

    }

    return result;

}

/\*\*

 \* 批量删除对应的value

 \* @param keys

 \*/

@Override

public void remove(final String... keys) {

    for (String key : keys) {

        remove(key);

    }

}

/\*\*

 \* 批量删除key

 \* @param pattern

 \*/

@Override

public void removePattern(final String pattern) {

    Set<Serializable> keys = redisTemplate.keys(pattern);

    if (keys.size() > 0)

        redisTemplate.delete(keys);

}

/\*\*

 \* 删除对应的value

 \* @param key

 \*/

@Override

public void remove(final String key) {

    if (exists(key)) {

        redisTemplate.delete(key);

    }

}

/\*\*

 \* 判断缓存中是否有对应的value

 \* @param key

 \* @return

 \*/

@Override

public boolean exists(final String key) {

    return redisTemplate.hasKey(key);

}

/\*\*

 \* 读取缓存

 \* @param key

 \* @return

 \*/

@Override

public Object get(final String key) {

    Object result = null;

    ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();

    result = operations.get(key);

    return result;

}

/\*\*

 \* 哈希 添加

 \* @param key

 \* @param hashKey

 \* @param value

 \*/

@Override

public void hmSet(String key, Object hashKey, Object value){

    HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();

    hash.put(key,hashKey,value);

}

/\*\*

 \* 哈希获取数据

 \* @param key

 \* @param hashKey

 \* @return

 \*/

@Override

public Object hmGet(String key, Object hashKey){

    HashOperations<String, Object, Object>  hash = redisTemplate.opsForHash();

    return hash.get(key,hashKey);

}

/\*\*

 \* 列表添加

 \* @param k

 \* @param v

 \*/

@Override

public void listPush(String k,Object v){

    ListOperations<String, Object> list = redisTemplate.opsForList();

    list.rightPush(k,v);

}

/\*\*

 \* 列表获取

 \* @param k

 \* @param l

 \* @param l1

 \* @return

 \*/

@Override

public List<Object> lRange(String k, long l, long l1){

    ListOperations<String, Object> list = redisTemplate.opsForList();

    return list.range(k,l,l1);

}

/\*\*

 \* 集合添加

 \* @param key

 \* @param value

 \*/

@Override

public void add(String key,Object value){

    SetOperations<String, Object> set = redisTemplate.opsForSet();

    set.add(key,value);

}

/\*\*

 \* 集合获取

 \* @param key

 \* @return

 \*/

@Override

public Set<Object> setMembers(String key){

    SetOperations<String, Object> set = redisTemplate.opsForSet();

    return set.members(key);

}

/\*\*

 \* 有序集合添加

 \* @param key

 \* @param value

 \* @param scoure

 \*/

@Override

public void zAdd(String key,Object value,double scoure){

    ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();

    zset.add(key,value,scoure);

}

/\*\*

 \* 有序集合获取

 \* @param key

 \* @param scoure

 \* @param scoure1

 \* @return

 \*/

@Override

public Set<Object> rangeByScore(String key,double scoure,double scoure1){

    ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();

    return zset.rangeByScore(key, scoure, scoure1);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约