openfeign本地试用

目的:在本地搭建一个简单的openfeign使用场景,测试查询、新增等功能

平台:win10

技术栈:Springboot, SpringCloud, Nacos, Mybatis, MySql, Logback

框架作用说明:

  1. Nacos用于服务注册,将provider应用注册到Nacos,
  2. 客户端订阅该服务,然后用openfeign调用provider提供的rest接口
  3. 数据库采用mysql,mybatis提供orm功能
  4. 日志用logback

项目架构如下:

总共启动了4个应用:

nacos server, feigndemo (provider), feignclientdemo(client), mysql server

Nacos server采用单机模式启动:

startup.cmd -m standalone

MySQL:

创建数据库、用户,给用户授权,然后建表

create database feigndemo default character set utf8mb4;
use feigndemo;
create user 'feigndemo'@'localhost' identified by '123456';
-- grant privileges
Grant SELECT, insert, create,delete,update,alter,drop on feigndemo.* to 'feigndemo'@'localhost' with grant option;

create table product (
    id int(16),
    name varchar(64),
    price double(10,2),
    delete_flag tinyint(1) not null default 0 comment '0:未删除,1:已删除',
    create_time datetime not null default CURRENT_TIMESTAMP comment '创建时间',
    update_time datetime not null default CURRENT_TIMESTAMP comment '更新时间'
) ENGINE=InnoDB DEFAULT charset=utf8mb4;

feigndemo主要源码

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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.6.6</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <groupId>org.example</groupId>
  <artifactId>feigndemo</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>feigndemo</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2021.0.3</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.7.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>3.1.3</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.2</version>
    </dependency>

    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>


  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

配置文件:

application.yml

server:
  port: 8088

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/feigndemo?characterEncoding=UTF-8
    username: feigndemo
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  application:
    name: feigndemo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: b2b3c55a-abe5-47a4-a47e-03c57138d1d7

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

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <contextName>${APP_NAME}</contextName>
    <springProperty name="APP_NAME" scope="context" source="spring.application.name"/>
    <springProperty name="LOG_FILE" scope="context" source="logging.file" defaultValue="../logs"/>
    <springProperty name="LOG_POINT_FILE" scope="context" source="logging.file" defaultValue="../logs/point"/>
    <springProperty name="LOG_MAXFILESIZE" scope="context" source="logback.filesize" defaultValue="50MB"/>
    <springProperty name="LOG_FILEMAXDAY" scope="context" source="logback.filemaxday" defaultValue="7"/>
    <springProperty name="ServerIP" scope="context" source="spring.cloud.client.ip-address" defaultValue="0.0.0.0"/>
    <springProperty name="ServerPort" scope="context" source="server.port" defaultValue="0000"/>

    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clrc" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="ewtpc"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>

    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%clrc(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} [%clrc(%X{traceId}){yellow},%clrc(%X{X-B3-TraceId}){yellow}] %clrc(%level){blue} %clrc(%logger){cyan} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ewtpc}"/>
    <property name="CONSOLE_LOG_PATTERN_NO_COLOR"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{traceId},%X{X-B3-TraceId}] %level %logger %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%ewtpc}"/>

    <!-- 控制台日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <withJansi>true</withJansi>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <!-- 按照每天生成常规日志文件 -->
    <appender name="DAILY_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}/${APP_NAME}/${APP_NAME}.log</file>
        <!-- 基于时间的分包策略 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}/${APP_NAME}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>100MB</maxFileSize>
            <!--保留时间,单位:天-->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN_NO_COLOR}</pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <logger name="com.ulisesbocchio" level="INFO"/>
    <logger name="com.netflix" level="INFO"/>
    <logger name="com.zaxxer.hikari" level="INFO"/>
    <logger name="com.baomidou" level="INFO"/>
    <logger name="org.example.spc" level="INFO"/>

    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DAILY_LOG"/>
    </root>
</configuration>

main方法类App.java:

@EnableDiscoveryClient
@SpringBootApplication
public class App 
{
    public static void main( String[] args )
    {
        SpringApplication.run(App.class, args);
    }
}

ProductMapper.java

package org.example.spc.consumer.mapper;

import org.apache.ibatis.annotations.Param;
import org.example.spc.consumer.model.Product;
import org.springframework.stereotype.Repository;

import java.util.List;

//@Mapper
@Repository
public interface ProductMapper {
    Product findById(@Param("id") int id);
  
    void insert(Product product);
  
    List<Product> findAll();
}

ProductMapper.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="org.example.spc.consumer.mapper.ProductMapper">
    <select id="findById" parameterType="int" resultType="org.example.spc.consumer.model.Product">
        SELECT id, name, price FROM product WHERE id = #{id}
    </select>

    <select id="findAll" resultType="org.example.spc.consumer.model.Product">
        SELECT id, name, price FROM product
    </select>

    <insert id="insert" parameterType="org.example.spc.consumer.model.Product">
        INSERT into product (id, name, price)
        VALUES (#{id}, #{name}, #{price})
    </insert>
</mapper>

ProductServiceImpl.java

@Service
public class ProductServiceImpl implements ProductService {

    private static final Logger logger = LoggerFactory.getLogger(ProductServiceImpl.class);

    @Autowired
    private ProductMapper productMapper;

    @Override
    public Product getProduct(int id) {
        logger.info("Find product by id : {}", id);
        return productMapper.findById(id);
    }
...
}

ProductController.java

@RestController
@RequestMapping("/product")
public class ProductController {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProductController.class);

    @Autowired
    private ProductService productService;

    @GetMapping("/{id}")
    @ResponseBody
    public Product find(@PathVariable("id") int id) {
        return productService.getProduct(id);
    }

    @GetMapping("/all")
    @ResponseBody
    public List<Product> findAll() {
        return productService.findAll();
    }

    @PostMapping("/add")
    public ResponseEntity addProduct(@RequestBody Product product) {
        return productService.addProduct(product);
    }

}

feignclientdemo重要源码和配置:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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.6.6</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <groupId>org.example</groupId>
  <artifactId>feignclientdemo</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>feignclientdemo</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>2021.0.3</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>

      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>2.2.7.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
      <version>3.1.3</version>
    </dependency>

    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
      <exclusions>
        <exclusion>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>

  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

application.yml

server:
  port: 18728

spring:
  application:
    name: feignclientdemo
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        namespace: b2b3c55a-abe5-47a4-a47e-03c57138d1d7

FeignClientDemoApp.java (入口类)

package org.example;

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.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@EnableFeignClients
@EnableDiscoveryClient(autoRegister = false)
@SpringBootApplication
public class FeignClientDemoApp
{
    public static void main( String[] args )
    {
        SpringApplication.run(FeignClientDemoApp.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

ProductService.java

package org.example.spc.consumer.service;

import org.example.spc.consumer.model.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.util.List;

@FeignClient("feigndemo")	// 括号中的值必须和provider注册的应用名一致
public interface ProductService {

    @GetMapping("/product/{id}")
    Product getProduct(@PathVariable int id);

    @GetMapping("/product/all")
    List<Product> findAll();

    @PostMapping("/product/add")
    ResponseEntity addProduct(@RequestBody Product product);

}

ProductController.java

package org.example.spc.consumer.controller;

import org.example.spc.consumer.model.Product;
import org.example.spc.consumer.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * 功能描述
 *
 * @auhtor sunlei
 * @since 2024/7/28 17:38
 */
@RestController
@RequestMapping("/product")
public class ProductController {

    private ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @GetMapping("/{id}")
    @ResponseBody
    public Product find(@PathVariable("id") int id) {
        return productService.getProduct(id);
    }

    @GetMapping("/all")
    @ResponseBody
    public List<Product> findAll() {
        return productService.findAll();
    }

    @PostMapping("/add")
    public ResponseEntity addProduct(@RequestBody Product product) {
        return productService.addProduct(product);
    }

}

部署好后的调用结果如下:

GET请求:

POST请求:(用ApiFox调用)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值