β

一起来学SpringCloud之-服务消费者(Feign-下)

Harries Blog™ 1325 阅读

上一篇 文章 中已经讲述 Feign 的基本用法,本章主要概述 FeignClient GET/POST/PUT/DELETE restful写法以及 Feign 拦截器,与 配置 优化方案,关闭HttpClient开启OKHTTP…

- 准备工作

1.启动Consul,所有文章都将以Consul作为服务注册中心

2.创建 battcn-feign-hello,battcn-feign-hi(本文 代码 基于上篇改造)

3.服务(Hi)-> FeignClient -> 服务(Hello),通过实现 RequestInterceptor 传递 header 信息

- battcn-feign-hello

- 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>

    <groupId>com.battcn</groupId>
    <artifactId>battcn-feign-hello</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>battcn-feign-hello</name>
    <description>Feign请求</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</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>

- BattcnFeignHello App lication.java

package com.battcn;

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

@SpringBootApplication
@EnableDiscoveryClient
public class BattcnFeignHelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(BattcnFeignHelloApplication.class, args);
    }
}

- Student.java

package com.battcn.pojo;

/**
 * 学生表
 */
public class Student {

    private Long id;
    private String name;
    private String email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '/'' +
                ", email='" + email + '/'' +
                '}';
    }
    public Student(){}
    public Student(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
}

- HelloController.java

package com.battcn.controller;

import com.battcn.pojo.Student;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping("/hello")
public class HelloController {

    @Autowired
    HttpServletRequest request;

    static Logger LOGGER = LoggerFactory.getLogger(HelloController.class);

    @ResponseStatus(HttpStatus.OK)
    @GetMapping
    public Student findStudentByName(@RequestParam("name") String name,@RequestHeader(name = "token",required = false)) {
        // TODO:不做具体代码实现,只打印Log
        LOGGER.info("[查询参数] - [{}]", name);
        LOGGER.info("[Token] - [{}]",token);
        LOGGER.info("[Auth] - [{}]",request.getHeader("Auth"));
        return new Student(1L,"挽歌-GET","1837307557@qq.com");
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping
    public Student addStudent(@RequestBody Student student) {
        // TODO:不做具体代码实现,只打印Log
        LOGGER.info("[添加信息] - [{}]", student.toString());
        return new Student(2L,"挽歌-SAVA","1837307557@qq.com");
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PutMapping("/{studentId}")
    public Student editStudent(@RequestBody Student student, @PathVariable("studentId") Long studentId) {
        // TODO:不做具体代码实现,只打印Log
        LOGGER.info("[修改信息] - [{}]", student.toString());
        return new Student(3L,"挽歌-EDIT","1837307557@qq.com");
    }

    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping("/{studentId}")
    public void deleteStudent(@PathVariable("studentId") Long studentId) {
        // TODO:不做具体代码实现,只打印Log
        LOGGER.info("[根据编号删除学生] - [{}]", studentId);
    }
}

- bootstrap.yml

server:
  port: 8765

spring:
  application:
    name: battcn-feign-hello
  cloud:
    consul:
      host: localhost
      port: 8500
      enabled: true
      discovery:
        enabled: true
        prefer-ip-address: true

- 测试

访问: http://localhost:8765/hello?name=Levin

显示: {"id":1,"name":"挽歌-GET","email":"1837307557@qq.com"} 代表我们服务启动成功

- battcn-feign-hi

- 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>

    <groupId>com.battcn</groupId>
    <artifactId>battcn-feign-hi</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>battcn-feign-hi</name>
    <description>Feign请求</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Dalston.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.battcn</groupId>
            <artifactId>battcn-starter-swagger</artifactId>
            <version>1.0.1</version>
        </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>

- BattcnFeignHiApplication.java

package com.battcn;

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

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class BattcnFeignHiApplication {

    public static void main(String[] args) {
        SpringApplication.run(BattcnFeignHiApplication.class, args);
    }

}

- HiController.java

package com.battcn.controller;

import com.battcn.client.HelloClient;
import com.battcn.pojo.Student;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/hi")
public class HiController {

    static Logger LOGGER = LoggerFactory.getLogger(HiController.class);

    @Autowired
    HelloClient helloClient;

    @ResponseStatus(HttpStatus.OK)
    @GetMapping
    public Student find(@RequestParam("name") String name,@RequestHeader(name="token",required = false)String token) {
        // TODO:只是演示Feign调用的方法
        LOGGER.info("[Token] - [{}]",token);
        return helloClient.findStudentByName(name,token);
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping
    public Student add(@RequestBody Student student) {
        // TODO:只是演示Feign调用的方法
        return helloClient.addStudent(student);
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PutMapping("/{studentId}")
    public Student edit(@RequestBody Student student, @PathVariable("studentId") Long studentId) {
        // TODO:只是演示Feign调用的方法
        return helloClient.editStudent(student, studentId);
    }

    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping("/{studentId}")
    public void delete(@PathVariable("studentId") Long studentId) {
        // TODO:只是演示Feign调用的方法
        helloClient.deleteStudent(studentId);
    }
}

- MyFeignInterceptor.java

package com.battcn.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;

/**
 * 传递Token
 * @author Levin
 * @date 2017-07-29.
 */
@Configuration
public class MyFeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("Auth","My Name's request header Auth");
    }
}

- HelloClient.java

package com.battcn.client;

import com.battcn.pojo.Student;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

/**
 * 模拟完整的CRUD操作
 */
@FeignClient(name = "battcn-feign-hello")
public interface HelloClient {

    @ResponseStatus(HttpStatus.OK)
    @GetMapping("/hello")
    Student findStudentByName(@RequestParam("name") String name,@RequestHeader(name="token",required = false)String token);

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping("/hello")
    Student addStudent(@RequestBody Student student);

    @ResponseStatus(HttpStatus.CREATED)
    @PutMapping("/hello/{studentId}")
    Student editStudent(@RequestBody Student student, @PathVariable("studentId") Long studentId);

    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping("/hello/{studentId}")
    void deleteStudent(@PathVariable("studentId") Long studentId);
}

- bootstrap.yml

server:
  port: 8766

spring:
  application:
    name: battcn-feign-hi
  cloud:
    consul:
      host: localhost
      port: 8500
      enabled: true
      discovery:
        enabled: true
        prefer-ip-address: true

#Hystrix支持,如果为true,hystrix库必须在classpath中
feign:
  okhttp:
    enabled: true #开启OKHTTP支持,依赖 (feign-okhttp)默认HttpClient
  #请求和响应GZIP压缩支持
  compression:
    request:
      enabled: true
      #支持压缩的mime types
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048
    response:
      enabled: true
  hystrix:
    enabled=false
# 日志支持
logging:
  level:
    project.com.battcn.UserClient: DEBUG


#以下就是需要写的配置,注意base-package就可以了
swagger:
  enable: true  #是否开启Swagger
  api-info:
    description: ${spring.application.name}
    license: ${spring.application.name}
    license-url: http://blog.battcn.com
    terms-of-service-url: http://blog.battcn.com
    title: 鏖战八方
    version: "@project.version@"
    contact:
      email: 1837307557@qq.com
      name: 挽歌
      url: http://blog.battcn.com
  docket:
    base-package: com.battcn.controller   #扫描路径,建议以Controller的父包为主
    group-name: ${spring.application.name}

- 测试

访问: http://localhost:8766/swagger-ui.html

使用Swagger做测试

一起来学SpringCloud之-服务消费者(Feign-下)

此处只演示GET,PUT,DELETE,POST 示例代码都包括,自行测试即可

日志:

-07-29 18:21:26.854  INFO 12620 --- [nio-8765-exec-2] com.battcn.controller.HelloController    : [查询参数] - [Levin]
-07-29 18:21:26.854  INFO 12620 --- [nio-8765-exec-2] com.battcn.controller.HelloController    : [Token] - [Token HA]
-07-29 18:21:26.854  INFO 12620 --- [nio-8765-exec-2] com.battcn.controller.HelloController    : [Auth] - [My Name's request header Auth]

如果未实现 RequestInterceptor 那么 LOGGER.info("[Auth] - [{}]",request.getHeader("Auth")); 就无法获取到 request 中的信息

- 流程图

画图工具: https ://www.processon.com/

一起来学SpringCloud之-服务消费者(Feign-下)

- 说点什么

全文代码: http://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-feign 本章代码,如有问题请及时与我联系

个人QQ:1837307557

Spring Cloud中国社区①:415028731

Spring For All 社区⑤:157525002

欢迎一起讨论与交流

转载标明出处,thanks


作者:Harries Blog™
追心中的海,逐世界的梦
原文地址:一起来学SpringCloud之-服务消费者(Feign-下), 感谢原作者分享。

发表评论