ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Springcloud开发之OpenFeign调用和认证

2022-02-27 14:34:00  阅读:425  来源: 互联网

标签:customer return OpenFeign Springcloud 认证 header PublicReturn new public


SpringCloud开发cloud具有巨大的灵活性。

在调用其它服务的时候有多种方式,虽然本质一样,但是细节还是有所差异。

一、概述

当a服务调用b服务的时候有多种方式进行:

1.通过openFeign接口方式

    优点:我们一般会使用这种方式,因为代码量相对少一些,安全可以通过openFeign拦截器来实现。

    缺点:无法在请求的时候直接设置请求头,请求体等

    总结:总体而言,还是推荐的。

2.通过RestTemplate的方式指定服务名调用

   优点:灵活度较高,可以自定义处理请求(头+参数等)和返回的操作,不需要定义openFeign接口

   确定:如果类似的请求比较多,则工作量还是有一些的。

   总结: 如果是最求灵活性,可以考虑。如果不做cloud开发,那么RestTemplate是非常不错的选择。

3.通过RestTemplate的方式指定ip方式调用

   第二种方式的变体,一般不那么做,因为这失去了cloud的优势-集群+负载均衡等等。

 

做工程,自然要兼顾效率和可维护性,所以一般我们都推荐使用第1种方式。技术总是要服务于工程和需求。

下面我使用例子来说明。

二、例子

2.1 概述

为了测试,我们构建了四个服务:

a.base(ConfigService) -负责认证 ,返回token

b.McService --管理中心,负责一些管理信息处理

c.CustomerService-负责客户有关信息

d.ConfigServiceTest-配置测试服务

测试的脚本写在服务ConfigServiceTest中。

为了解决篇幅,下文例子只是贴出了各个service的接口以及ConfigServiceTest的cloud有关配置。

 2.2 配置代码

a服务的接口-/api/services/app/Users/Login

    @RequestMapping(value="/api/services/app/Users/Login",method= {RequestMethod.POST,RequestMethod.GET})
    @ResponseBody
    public PublicReturn login(HttpServletRequest request,@RequestBody AuthParam input) {
        AuthParam auth=jwtUtil.parseAuthToken(request, "Authorization");
        
        if (auth!=null) {
            LOG.debug("token Value From header is:"+JSON.toJSONString(auth));
        }
        LOG.debug(JSON.toJSONString(input));
        LOG.debug(input.getCustomerSystemCode());
        try {
            PublicReturn result= this.authService.login(input);
            LOG.debug("result is:"+JSON.toJSONString(result));
            return result;
        }
        catch(Exception e) {
            return PublicReturn.getUnSuccessful("获取认证信息失败");
        }
        
    }

 

b 服务的接口-/api/services/app/test


/**
* 仅用于测试
* @param name
* @return
*/
@RequestMapping("/app/test")
@ResponseBody
public PublicReturn test(@RequestParam(value="name",required = true) String name){
return PublicReturn.getSuccessful(name);
}

 

 c服务的接口-/customer/list

@Controller
@RequestMapping(value="/customer")
public class TestController {
    /**
     * 返回list
     * @return
     */
    @RequestMapping(value = "/list")
    @ResponseBody
    public Object list() { // TODO:
        Map<String,Object> customer=new HashMap<String,Object>();
        customer.put("name","lzf");
        customer.put("sex","男");
        customer.put("age","99");
        customer.put("address","中华");
        return customer;
    }

}

 

以上三个服务的代码不用特别关注。

 

 d服务(ConfigServiceTest)的测试代码,分两大部分:配置和接口

  • 配置-OpenFeign接口和相关配置
  • 用于测试的接口

配置代码:

1.异常处理-ErrorHandler(ErrorDecoder)

2.openFeign拦截器等配置-ConfigServiceFeignInter,McServiceFeignInter

3.Spring-Mvc配置-CustomWebMvcConfigurer(WebMvcConfigurationSupport),负责定义RestTemplate bean等等

4.openFeign接口-ConfigServiceOpenFeignInterface、McServiceOpenFeignInterface

测试代码:

1.TestController

--------------------

下面逐一贴出以上代码(注:为了节约篇幅,部分代码只选择紧要部分)

d的两个拦截器代码

public class ConfigServiceFeignInter {
    @Bean
    public RequestInterceptor currentUserRequestInterceptor() {
        return (RequestTemplate template) -> {
            //Map<String, Collection<String>> header=template.request().headers();
            //System.out.println(JSON.toJSONString(header, true));
        };
    }

}

public class McServiceFeignInter {

    @Bean
    public ErrorDecoder feignErrorDecoder() {
        return new ErrorHandler();
    }

    @Bean
    public RequestInterceptor currentUserRequestInterceptor() {
        return (RequestTemplate template) -> {
            //Map<String, Collection<String>> header=template.request().headers();
            //System.out.println(JSON.toJSONString(header, true));
            String token = LoginCache.get();
            System.out.println(token);
            template.header("Authorization", token);
        };
    }

}

 

d的两个openFeign接口

@FeignClient(value = "ConfigService",configuration= ConfigServiceFeignInter.class)
@Component
public interface ConfigServiceOpenFeignInterface {
    @PostMapping("/api/services/app/Users/Login")
    @ResponseBody
    PublicReturn login(@RequestBody AuthParam input);
}

@FeignClient(value = "McService",configuration= McServiceFeignInter.class)
@Component
public interface McServiceOpenFeignInterface {
   @RequestMapping(value = "/api/services/app/test")
   public PublicReturn test(@RequestParam(value="name",required = true) String name);
}

 

d的mvc配置(局部)

@LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        // 把自定义的ClientHttpRequestInterceptor添加到RestTemplate,可添加多个
        //restTemplate.setInterceptors(Collections.singletonList(actionTrackInterceptor));
        return restTemplate;
    }

 

注意:

1.springMvc的RestTemplate功能还是很强大的,可以设定拦截器等等。

2.我们并没有为服务c(CustomerService)定义标准的OpenFeign接口

 

2.3 测试代码

@RequestMapping(value = "/login_and_request")
    @ResponseBody
    public Object loginAndRequest() { // TODO:
        AuthParam authParam=new AuthParam();
        //此处略
        PublicReturn loginResult=configService.login(authParam);
        if (loginResult.isSuccessful()){
            String token=loginResult.getDateItem("token").toString();
            LoginCache.set(token);
            try{
                PublicReturn result=mcService.test("this is luzhifei");
                return result;
            }
            catch(Exception e){
                return PublicReturn.getUnSuccessful(e.getMessage());
            }
        }
        else{
            return PublicReturn.getUnSuccessful("登录失败");
        }
    }

    /**
     * 使用RestTemplate来调用
     * @return
     */
    @RequestMapping(value = "/request3srv")
    @ResponseBody
    public Object request3srv() { // TODO:
        AuthParam authParam=new AuthParam();
        //此处略...
        PublicReturn loginResult=configService.login(authParam);
        if (loginResult.isSuccessful()){
            String token=loginResult.getDateItem("token").toString();
            String url="http://McService/api/services/app/test";
            MultiValueMap<String, String> header=new LinkedMultiValueMap<>();
            header.add("Authorization",token);
            MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
            param.add("name","lzf");
            HttpEntity<MultiValueMap<String, String>> requst=new HttpEntity<>(param,header);
            try{
                PublicReturn result=restTemplate.postForObject(url,requst,PublicReturn.class);
                return result;
            }
            catch(Exception e){
                return PublicReturn.getUnSuccessful(e.getMessage());
            }

        }
        else{
            return PublicReturn.getUnSuccessful("登录失败");
        }
    }

    @RequestMapping(value = "/list-customer")
    @ResponseBody
    public Object listCustomer() { // TODO:
        String url="http://CustomerService/customer/list";
        MultiValueMap<String, String> header=new LinkedMultiValueMap<>();
        header.add("Authorization","青山遮不住,毕竟东流去!");
        MultiValueMap<String, String> param = new LinkedMultiValueMap<>();
        param.add("name","lzf");
        HttpEntity<MultiValueMap<String, String>> requst=new HttpEntity<>(param,header);
        Object result=restTemplate.postForObject(url,requst,Object.class);
        return result;
    }

 

2.4测试

编写完成后,启动a,b,c,d服务。

之后通过浏览器执行:

#通过原生openFeign接口调用
http://localhost:9081/test/login_and_request

#混合调用(原生openFeign+无openFeign方式调用)
http://localhost:9081/test/request3srv

#不需要定义OpenFeign接口的测试
http://localhost:9081/test/list-customer

 

通过上文list-customer的例子可以看到:不需要专门定义OpenFeign接口,也可以直接调用(通过服务名称而不是ip+url)来实现对其它

服务的调用。

 

测试的时候发现,如果故意停止服务b.McService,那么会等待比较长一段时间才能返回。

如果觉得这个TimeOut时间太长,那么可以设置OpenFeign调用的TimeOut参数

feign:
  client:
    config:
      default:
        connectTimeout: 30000

注意:这影响所有的Client

---

 

标签:customer,return,OpenFeign,Springcloud,认证,header,PublicReturn,new,public
来源: https://www.cnblogs.com/lzfhope/p/15940140.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有