eureka搭建微服务框架

基于eureka+spring-boot+spring-cloud搭建 订单-商品 微服务框架

# 环境说明:
spring-boot version:2.5.3
java version:11
spring-cloud version 2020.0.3

# 笔记目的,熟悉、演示微服务系统架构的搭建步骤

# 节点服务搭建

## eureka
1、添加依赖
```
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.3</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-security</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>
```
2、配置属性
```
server.port=8091
spring.application.name=myeureka

# eureka server's configure
eureka.instance.hostname=127.0.0.1
eureka.instance.prefer-ip-address=true
eureka.instance.instance-id=${eureka.instance.hostname}:${server.port}/eureka

# eureka client's configure
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka/

#security
spring.security.user.name=mark6666
spring.security.user.password=markpasswd
```
3、主类注入eureka服务依赖
```
package com.demo.eureka2;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Hello world!
 *
 */
@EnableEurekaServer
@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }
}

```

4、关闭CSRF验证,不然服务注册不了
configuration/WebSecurityConfig.java
```
package com.demo.eureka2.configuration;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic()
                .and()
                .csrf().disable();//ignoringAntMatchers("/eureka/**");//不建议完全禁用掉csrf
    }
}
```
5、 启动服务

6、登录并查看控制台
登录地址:http://127.0.0.1:8091/
备注:控制台地址不带"eureka"后缀;但服务注册地址中需要带这个后缀


## product
1、添加依赖
```
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.3</version>
  </parent>
  
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
    </properties>
    
    <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>
    
  <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>                
                </exclusion>
            </exclusions>
        </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  </dependencies>
```
2、配置属性
```
server.port=8086
spring.application.name=product-service

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Asia/Shanghai

# database setting
spring.datasource.url=jdbc:mysql://localhost:3306/java_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

#mybatis mapper path
mybatis.mapper-locations: classpath:mybatis/*.xml

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka
# register itsself ip to eureka
eureka.instance.prefer-ip-address=true
# set ip of the service
# eureka.instance.ip-address=127.0.0.1
# set id of the instance
# eureka.instance.instance-id=${spring.application.name}:${server.port}/productSrv
```
3、主类注入eureka客户端发现服务依赖-@EnableDiscoveryClient
```
package com.demo.product_center;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

/**
 * Hello world!
 *
 */
@EnableDiscoveryClient
@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run( App.class, args );
    }
}
```
4、编写API控制器
controller/ApiController.java
```
@RestController
@RequestMapping("/product-service")
public class ProductController {

    @Autowired
    private ProductService productService;
    
    @RequestMapping("product/{id}")
    public Product getProduct(@PathVariable("id") int id) {
        return this.productService.getProduct(id);
    }
}
```
5、编写service
service/ProductService.java
```
@Service
public class ProductService {
    @Autowired
    private ProductMapper productMapper;
    
    public Product getProduct(int id) {
        return this.productMapper.getProduct(id);
    }
}
```
6、编写mapper Interface
mapper/ProductMapper.java
```
@Mapper
public interface ProductMapper {
    List<Product> products();
    Product getProduct(int id);
    int updateById(Product product);
    int deleteById(int id);
}
```
7、编写mybatis mapper
resources/mybatis/Product.xml
```
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.demo.product_center.mapper.ProductMapper" >
  <resultMap id="BaseResultMap" type="com.demo.product_center.bean.Product" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="quantity" property="quantity" jdbcType="INTEGER" />
    <result column="price" property="price" jdbcType="DECIMAL" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, name, quantity, price, create_time, update_time
  </sql>
  <sql id="Base_Table_Name" >
    `products`
  </sql>
  <select id="products" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
    order by id limit 10
  </select>
  <select id="getProduct" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteById" parameterType="java.lang.Integer" >
    delete from 
        <include refid="Base_Table_Name" />
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.demo.product_center.bean.Product" >
    insert into 
        <include refid="Base_Table_Name" />
         (id, name, quantity, price,create_time, update_time
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{quantity,jdbcType=INTEGER}, #{price,jdbcType=DECIMAL}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
      )
  </insert>
  <update id="updateById" parameterType="com.demo.product_center.bean.Product" >
    update product
    set quantity = #{quantity,jdbcType=INTEGER},
      update_time = #{updateTime,jdbcType=TIMESTAMP}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>
```
8、编写Product bean
bean/Product.java
```

public class Product {
    
    private Integer id;
    private String name;
    private Integer quantity;
    private Float price;
    private Date createTime;
    private Date updateTime;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getQuantity() {
        return quantity;
    }
    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }
    
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    
}
```

9、启动服务

10、访问API
http://10.12.30.49:8086/product-service/product/1

## order
1、添加依赖
```
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.3</version>
  </parent>
  
    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
    </properties>
    
    <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>
    
  <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.dataformat</groupId>
                    <artifactId>jackson-dataformat-xml</artifactId>                
                </exclusion>
            </exclusions>
        </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
  </dependencies>
```
2、配置属性
```
server.port=8085
spring.application.name=order-service
# debug=true

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=Asia/Shanghai

# database setting
spring.datasource.url=jdbc:mysql://localhost:3306/java_demo?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

#mybatis mapper path
mybatis.mapper-locations: classpath:mybatis/*.xml

eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://mark6666:markpasswd@127.0.0.1:8091/eureka

# register itsself ip to eureka
eureka.instance.prefer-ip-address=true
```
3、主类注入eureka客户端发现服务依赖-@EnableDiscoveryClient
```
@EnableDiscoveryClient
@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run( App.class, args );
    }
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
```
4、编写API控制器
```
package com.demo.order_center.controller;

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;

import com.demo.order_center.bean.Order;
import com.demo.order_center.service.OrderService;

@RestController
@RequestMapping("/order-service")
public class OrderController {
    
    @Autowired
    private OrderService orderService;
    
    @RequestMapping("order/{id}")
    public Order getProduct(@PathVariable("id") String id) {

        return this.orderService.getOrder(id);
        
    }
}
```
5、编写service
service/OrderService.java
```
@Service
public class OrderService {    
    
    @Autowired
    private OrderMapper orderMapper;
    
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    
    @Autowired
    private ProductService productService;
    
    public Order getOrder(String id) {
        
        Order order = orderMapper.getOrder(id);
        if(null == order) return null;

        List<OrderDetail>  orderDetails = orderDetailMapper.orderDetails(id);
        if(null == orderDetails) return null;
        
        for(OrderDetail orderDetail : orderDetails) {
            Product product = this.productService.getProduct(orderDetail.getProductId());
            if(null == product) continue;
            orderDetail.setProduct(product);
        }
        order.setOrderDetail(orderDetails);
        return order;
    }
}
```
service/ProductService.java
```
package com.demo.order_center.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.demo.order_center.bean.Product;

@Service
public class ProductService {
    
    @Autowired
    private RestTemplate restTemplate;
    
    @Autowired
    private DiscoveryClient discoveryClient;
    
    public Product getProduct(int id) {
        
        String serviceId = "product-service";
        List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
        if(instances.isEmpty()) return null;
        
        ServiceInstance serviceInstance = instances.get(0);
        
        String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/product-service/product/" + id;
        
        Product product = restTemplate.getForObject(url, Product.class);
        return product;
        
    }
}

```
6、编写mapper interface
mapper/OrderMapper.java
```
@Mapper
public interface OrderMapper {
    List<Order> orders();
    Order getOrder(String id);
    int deleteById(String id);
    int insert(Order order);
}
```
mapper/OrderDetailMapper.java
```
@Mapper
public interface OrderDetailMapper {
    List<OrderDetail> orderDetails(String orderId);
    OrderDetail getOrderDetail(String orderId);
    int deleteById(String orderId);
    int insert(OrderDetail orderDetail);
}
```
7、编写mybatis mapper
resources/mybatis/order.xml
```
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.demo.order_center.mapper.OrderMapper" >
  <resultMap id="BaseResultMap" type="com.demo.order_center.bean.Order" >
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="user_id" property="userId" jdbcType="INTEGER" />
    <result column="state" property="state" jdbcType="INTEGER" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, user_id, state, create_time, update_time
  </sql>
  <sql id="Base_Table_Name" >
    `orders`
  </sql>
  <select id="orders" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
    order by id limit 10
  </select>
  <select id="getOrder" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
    where id = #{id,jdbcType=VARCHAR}
  </select>
  <delete id="deleteById" parameterType="java.lang.String" >
    update  
        <include refid="Base_Table_Name" />
    set state = 0
    where id = #{id,jdbcType=VARCHAR}
  </delete>
  <insert id="insert" parameterType="com.demo.order_center.bean.Order" >
    insert into 
        <include refid="Base_Table_Name" />
         (id, user_id, state, create_time, update_time
      )
    values (#{id,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER}, #{state,jdbcType=INTEGER}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
      )
  </insert>
</mapper>
```
resources/mybatis/orderDetail.xml
```
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.demo.order_center.mapper.OrderDetailMapper" >
  <resultMap id="BaseResultMap" type="com.demo.order_center.bean.OrderDetail" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="order_id" property="orderId" jdbcType="VARCHAR" />
    <result column="product_id" property="productId" jdbcType="INTEGER" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, order_id, product_id
  </sql>
  <sql id="Base_Table_Name" >
    `order_details`
  </sql>
  <select id="orderDetails" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
        where order_id = #{orderId,jdbcType=VARCHAR}
    order by id limit 100
  </select>
  <select id="getOrderDetail" resultMap="BaseResultMap" parameterType="java.lang.String" >
    select 
    <include refid="Base_Column_List" />
    from 
        <include refid="Base_Table_Name" />
    where order_id = #{orderId,jdbcType=VARCHAR}
  </select>
  <delete id="deleteById" parameterType="java.lang.String" >
    update from 
        <include refid="Base_Table_Name" />
    set state = 0
    where id = #{orderId,jdbcType=VARCHAR}
  </delete>
  <insert id="insert" parameterType="com.demo.order_center.bean.OrderDetail" >
    insert into 
        <include refid="Base_Table_Name" />
         (id, order_id, product_id, state
      )
    values (#{id,jdbcType=INTEGER}, #{orderId,jdbcType=VARCHAR}, #{productId,jdbcType=INTEGER}, 1
      )
  </insert>
</mapper>
```
8、编写bean
bean/Order.java
```
public class Order{

    private String id;
    private int userId;
    private int state;
    private Date createTime;
    private Date updateTime;
    private List<OrderDetail> orderDetails;
    
    public Order() {
        
    }
    public Order(String id, int userId, Date createTime, Date updateTime) {
        this.id = id;
        this.userId = userId;
        this.createTime = createTime;
        this.updateTime = updateTime;
    }

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    
    public int getState() {
        return state;
    }
    public void setState(int state) {
        this.state = state;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public List<OrderDetail> getOrderDetail() {
        return orderDetails;
    }
    public void setOrderDetail(List<OrderDetail> orderDetails) {        
        this.orderDetails = orderDetails;
    }
    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append("[");
        sb.append("Hash =").append(hashCode());
        sb.append(", id=").append(id);
        sb.append(", userId=").append(userId);
        sb.append(", createTime=").append(createTime);
        sb.append(", updateTime=").append(updateTime);
        sb.append("]");
        return sb.toString();
    }
    
}
```
bean/OrderDetail.java
```

public class OrderDetail {
    private int id;
    private String orderId;
    private int productId;
    private Product product = new Product();
    public OrderDetail() {
        
    }
    public OrderDetail(String orderId, Product product) {
        this.orderId = orderId;
        this.product = product;
    }
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getOrderId() {
        return orderId;
    }
    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
    
    public int getProductId() {
        return productId;
    }
    public void setProductId(int productId) {
        this.productId = productId;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }

    @Override
    public String toString() {

        StringBuilder sb = new StringBuilder();
        sb.append(getClass().getSimpleName());
        sb.append("[");
        sb.append("Hash =").append(hashCode());
        sb.append(", orderId=").append(orderId);
        sb.append(", productId=").append(productId);
        sb.append(", products=").append(product.toString());
        sb.append("]");
        return sb.toString();
    }
}
```
bean/Product.java
```
public class Product {
    

    private Integer id;

    private String name;

    private Integer quantity;
    
    private Float price;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;
    
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updateTime;
    
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getQuantity() {
        return quantity;
    }
    public void setQuantity(Integer quantity) {
        this.quantity = quantity;
    }
    
    public Float getPrice() {
        return price;
    }
    public void setPrice(Float price) {
        this.price = price;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    
}
```
9、启动服务

10、访问API
http://127.0.0.1:8085/order-service/order/1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值