第一个Feign程序

 

编码器:如果服务端只接受JSON字符串格式/XML,那么我们客户端使用的是对象。在这种情况下,我们可以使用编码器将对象转换成JSON字符串/XML。
解码器:将服务端的响应结果对象,转换为客户端的对象。这个时候就需要用到解码器。

 

1. Feign被集成到SpringCloud Netflix模块,当Eureka,Ribbon集成的时候呢,Feign就具备了负载均衡的功能。Feign本身使用就很简便,再加上与SpringCloud的整合,将很大程度上降低我们开发的工作量。

2. 它是Github上面的一个开源项目,目的是为了简化WebService客户端的开发,在使用Feign的时候 可以使用注解来修饰接口,被修饰的接口就具有了访问webservice的能力,这些注解呢 可以使用Feign的自带注解,也可以支持使用第三方的注解。Feign还支持插件式的编码器和解码器,使用者可以通过这些特性,对请求和响应进行封装和解析。

Feign会更加的面向对象,下面我们使用Feign来对比一下CXF。在这之前我们需要准备对外提供接口。

如果没有接口等项目的朋友,可以参照前几章的“SpringCloud 中使用 Ribbon(默认轮询规则 + 自定义规则)”搭建(只搭建服务器与服务提供者即可)

 

这里我们一次把依赖CXF、Feign的依赖全部引入:pom.xml

<dependencies>
    <!-- CXF 依赖 -->
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-core</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-client</artifactId>
        <version>3.1.0</version>
    </dependency>

    <!-- Feign 依赖 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-core</artifactId>
        <version>9.5.0</version>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-gson</artifactId>
        <version>9.5.0</version>
    </dependency>
    <!-- 如果请求格式用XML的时候,需要加入以下XML依赖 -->
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-jaxb</artifactId>
        <version>9.5.0</version>
    </dependency>
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.8</version>
    </dependency>
</dependencies>

 

 下面我们编写一个CXF客户端,进行测试:CxfClient.java

public class CxfClient {
    
    public static void main(String[] args) throws IOException {
        // 创建 WebClient
        WebClient client = WebClient.create("http://localhost:9090/getPoliceById/123");
        // 获取响应
        Response response = client.get();
        // 获取响应内容
        InputStream is = (InputStream) response.getEntity();
        String content = IOUtils.readStringFromStream(is);
        // 打印结果
        System.out.println("请求结果:" + content);
    }

}

乱码的问题不用管,我们就看 WebClient.create 方法中的url,url多的话,维护起来也麻烦,而且还需要对流进行操作。。。接下来,我们编写一个Feign程序,与CXF进行一下对比

 

 在文章的一开始,提到了 Feign 程序会更加的面向对象,所以我们先创建一个实体类,用来接收结果对象:Police.java

public class Police {
    
    private String id;// 警察编号,用来保存用户输入的参数
    private String url;// 处理请求的服务器url
    private String message;// 提示信息
    
    
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    
}

 

 其次,我们创建一个接口类:FeignService.java

public interface FeignService {
    
    @RequestLine("GET /getPolice")
    public String getPolice();
    
    @RequestLine("GET /getPolice")
    public Police getPoliceObj();
    
    @RequestLine("GET /getPoliceById/{id}")
    public String getPoliceById(@Param("id") String id);
    
    /**
     * 发送JSON对象,返回字符串
     * @param police
     * @return
     */
    @RequestLine("POST /createPolice")
    @Headers("Content-Type: application/json")// 这里要指定请求类型
    public String createPolice(Police police);
    
    /**
     * 发送XML对象,返回字符串
     * @return
     */
    @RequestLine("POST /createXmlPolice")
    @Headers("Content-Type: application/xml")// 这里要指定请求类型
    public Police createXmlPolice(Police police);

}

 

 最后,我们再创建一个测试类,查看结果:TestMain.java

public static void main(String[] args) {
    /**
     * 根据ID获取派出警察,返回JSON字符串
     */
    FeignService client_1 = Feign.builder().target(FeignService.class, "http://localhost:9090");
    String policeStr = client_1.getPolice();
    System.out.println("返回JSON字符串:"+policeStr);
    String policeByIdStr = client_1.getPoliceById("123");
    System.out.println("根据ID获取派出警察,返回JSON字符串:"+policeByIdStr);
    
    /**
     * 返回警察对象
     */
    FeignService client_2 = Feign.builder().decoder(new GsonDecoder()).target(FeignService.class, "http://localhost:9090");
    Police police = client_2.getPoliceObj();
    System.out.println("返回警察对象:");
    System.out.println("  url:"+police.getUrl());
    System.out.println("  message:"+police.getMessage());
    
    /**
     * 发送JSON对象,返回字符串
     */
    FeignService client_3 = Feign.builder().encoder(new GsonEncoder()).target(FeignService.class, "http://localhost:9090");
    Police police_json = new Police();
    police_json.setMessage("你好");
    String createResult = client_3.createPolice(police_json);
    System.out.println("发送JSON格式参数,返回字符串:"+createResult);
    
    /**
     * 发送XML对象,返回字符串
     * 使用XML进行发送与接收时,实体类需要使用注解:
     * 类上注解:@XmlRootElement
     * 字段注解:@XmlElement
     * get方法使用注解:@XmlTransient
     */
    JAXBContextFactory encoder = new JAXBContextFactory.Builder().build();
    FeignService client_4 = Feign.builder()
            .encoder(new JAXBEncoder(encoder))
            .decoder(new JAXBDecoder(encoder))
            .target(FeignService.class, "http://localhost:9090");
    Police police_xml = new Police();
    police_xml.setMessage("你好");
    Police policeResult = client_4.createXmlPolice(police_xml);
    System.out.println("发送XML格式参数,返回字符串:"+policeResult.getMessage());
}

但是如果向接口传入xml格式值,那接口应该怎么定义呢?

// 接收xml,返回xml
@RequestMapping(value="/createXmlPolice", method=RequestMethod.POST, produces=MediaType.APPLICATION_XML_VALUE, consumes=MediaType.APPLICATION_XML_VALUE)
public String createXmlPolice(@RequestBody Police police){
    return "<police><message>"+police.getMessage()+"</message></police>";
}

OK,这样子就可以传递xml格式的参数了。。。那么下面贴一下以上main方法中的所有执行结果

 

 

额外再说一下,Feign的客服端 也是可插拔的,,下面教大家如何实现自定义客户端,并访问

首先需要自定义一个客户端,需要实现Feign的Client接口:MyClient.java

public class MyClient implements Client {

    @Override
    public Response execute(Request request, Options options) throws IOException {
        try {
            // 创建一个默认的客户端
            CloseableHttpClient httpClient = HttpClients.createDefault();
            // 获取调用的HTTP方法
            final String method = request.method();
            // 创建一个HttpClient的Request
            HttpRequestBase httpRequest = new HttpRequestBase() {
                @Override
                public String getMethod() {
                    return method;
                }
            };
            // 设置请求地址
            httpRequest.setURI(new URI(request.url()));
            // 执行请求,获取响应
            HttpResponse httpResponse = httpClient.execute(httpRequest);
            // 获取响应的主体内容
            byte[] body = EntityUtils.toByteArray(httpResponse.getEntity());
            // 将HttpClient的响应对象转换为Feign的Response
            Response feignResponse = Response.builder()
                    .body(body)
                    .headers(new HashMap<String, Collection<String>>())
                    .status(httpResponse.getStatusLine().getStatusCode())
                    .build();
            return feignResponse;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}

编写一个测试main方法:

/**
 * 使用可插拔式的自定义client客户端,进行请求访问
 */
FeignService client_5 = Feign.builder().client(new MyClient()).target(FeignService.class, "http://localhost:9090");
String policeStr = client_5.getPolice();
System.out.println("返回JSON字符串:"+policeStr);

下面贴上运行结果

 

posted on 2018-10-22 15:45  沛昕的博客  阅读(3140)  评论(0编辑  收藏  举报