Spring cloud restTemplate 传递复杂参数的方式(多个对象)

使用微服务的时候往往服务之间调用比较麻烦,spring cloud提供了Feign接口调用,RestTemplate调用的方式

这里我探讨下RestTemplate调用的方式:

服务A:接收三个对象参数  这三个参数的是通过数据库查询出来的

服务B:要调用服务A 服务B提供了查询三个参数的方法,后面要使用三个参数

对于服务A,处理的方式有两中

1. 服务B提供一个Feign接口将查询三个参数的方法公开,服务A直接引用Feign来查询参数,服务B只需要将三个查询关键字传递过去即可

服务A action

 @PostMapping("/import/{busiCode}/{filePath}")
 public Map<String,String> importExcel(@PathVariable("filePath") String filePath,@PathVariable("busiCode") String busiCode,@RequestBody Map<String, String> params,
                    HttpServletRequest request,HttpServletResponse response) {
   response.setCharacterEncoding("UTF-8");
   UserInfo user = UserUtil.getUser();
   return excelService.importExcel(filePath,busiCode,params,user);
 }

服务A service 

//引入Feign接口
private ExcelFreign excelFreign;
public Map<String,String> importExcel(String filePath, String busiCode,Map<String, String> params,UserInfo user ) {
    Map<String,String> result=new HashMap<String,String>();
    excelFreign = SpringTool.getApplicationContext().getBean(ExcelFreign.class);
    CmdImportConfigDto configDto = excelFreign.getCmdImportConfigByBusiCode(busiCode);
    CmdImportDto importDto=new CmdImportDto();
    importDto.setImportConfigId(configDto.getId());
    importDto.setExcelPath(filePath);
    importDto.setParam(new GsonBuilder().create().toJson(params));
    importDto.setLog("");
    Long impId=null;
    try {
      impId= Long.valueOf(excelFreign.saveCmdImportDto(importDto));
    } catch (Exception e1) {
      e1.printStackTrace();
      result.put("error", "保存出现异常");
      result.put("message", e1.getMessage());
      return result;
    }
    try{
      excelFreign.updateImportStatus(impId, ImportConstant.ImportStatus.SUBMIT, "提交成功");
    }catch(Exception e){
        e.printStackTrace();
    }
    ValidateTask validateTask=new ValidateTask();
    validateTask.init(impId,filePath, busiCode, params,user);
    String message;
    try {
      message = validateTask.call();
    } catch (Exception e) {
      e.printStackTrace();
      result.put("error", "验证出现异常");
      result.put("message", e.getMessage());
      return result;
    }
    if(message!=null){
      result.put("error", "验证不通过");
      result.put("message", message);
      return result;
    }
    PersistTask persistTask=new PersistTask();
    persistTask.init(impId,filePath, busiCode, params,user);
    result.putAll(ImportQueue.submit(persistTask));
    return result;
  } 

服务B 提供的B-Fegin

@FeignClient(value = "frame-service",path = "/excelApi/v1")
public interface ExcelFreign extends ExcelApi {
}

服务B api层 B-api

public interface ExcelApi {
/**
   * 更新状态
   * @param impId
   * @param importType
   * @param result
   */
  @PostMapping("/updateImportStatus/{impId}/{importType}/{result}")
  void updateImportStatus(@PathVariable("impId") Long impId, @PathVariable("importType") String importType, @PathVariable("result") String result) throws Exception;
/**
   * 获取导入配置项
   * @param busiCode
   * @return
   */
  @GetMapping("/getImportConfig/{busicode}")
  CmdImportConfigDto getCmdImportConfigByBusiCode(@PathVariable("busicode") String busiCode);
  /**
   * 保存信息
   * @param importDto
   * @return
   */
  @PostMapping("/saveImport")
  String saveCmdImportDto(@RequestBody CmdImportDto importDto);
} 

服务B 实现api接口的action

@RestController
@RequestMapping("/excelApi/v1")
public class ExcelFeignAction implements ExcelApi {
@Autowired
  private CmdExportService exportService;
 /**
   * 获取导入配置项
   * @param busiCode
   * @return
   */
  @GetMapping("/getImportConfig/{busicode}")
  public CmdImportConfigDto getCmdImportConfigByBusiCode(@PathVariable("busicode") String busiCode){
    return cmdImportConfigService.getCmdImportConfigByBusiCode(busiCode);
  }
 /**
   * 更新状态
   * @param impId
   * @param importStatus
   * @param result
   */
  @PostMapping("/updateImportStatus/{impId}/{importType}/{result}")
  public void updateImportStatus(@PathVariable("impId") Long impId, @PathVariable("importType") String importStatus, @PathVariable("result") String result) throws Exception{
    cmdImportService.updateImportStatus(impId,importStatus,new Date() , result);
  }
/**
   * 保存信息
   * @param importDto
   * @return
   */
  @PostMapping("/saveImport")
  public String saveCmdImportDto(@RequestBody CmdImportDto importDto){
    try{
      cmdImportService.saveCmdImportDto(importDto);
      return importDto.getId();
    }catch (Exception e){
      e.printStackTrace();
      throw new BusinessRuntimeException("系统出现异常");
    }
  }
}

服务B 调用服务A  action层

/**
   *
   * @param busicode 导出的业务编码 能确定某个模块做导出操作
   * @param values 请求参数
   *
   *        通过restTemplate 传递复杂参数
   * @return
   * 返回 文件流 让浏览器弹出下载
   */
  @PostMapping(value = "/export/v3/{busicode}")
  @ResponseBody
  public ResponseEntity<byte[]> expDownLoadV3(@PathVariable("busicode") String busicode , @RequestBody Map<String,Object> values, HttpServletRequest request)throws Exception {
   if(StringUtils.isBlank(busicode)){
      throw new BusinessRuntimeException("参数错误,请检查参数是否正确,busicode ?");
    }
    // 获取执行过程
    Map map = restTemplate.postForObject("http://" + serviceId + "/excelApi/v1/文件名"/"+busicode,values,Map.class);
    String path = (String)map.get("filepath");
    byte[] excel = FastDFSClient.downloadToBytes(path);
    CmdExportConfigDto cmdExportConfig = exportService.getCmdExportConfigByBusiCode(busicode);
    //获取文件名
    String fileName = cmdExportConfig.getReportName();
    // 获取文件后缀名
    String extFileName = path.substring(path.lastIndexOf('.')+1);
    HttpHeaders headers = new HttpHeaders();
    // 获取用户浏览器的种类 对不同的浏览器进行编码处理
    final String userAgent = request.getHeader("USER-AGENT");
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    headers.setContentDispositionFormData("attachment", FrameUrlConstants.transFromFileName(userAgent,fileName) + "." + extFileName);
    return new ResponseEntity<byte[]>(excel,headers,HttpStatus.OK);
  } 

2.服务B将查询出来的参数直接传递给服务A

服务A:

/**
   * 接收参数传递
   * 分别接收下面三种key value的键值对
   * cmdExportConfig:CmdExportConfigDto
   * exportFieldList:List<CmdExportFieldConfigDto>
   * params:Map
   * @param params
   * @param request
   * @param response
   * @return
   */
  @PostMapping("/export/v2")
  public ResponseEntity exportExcel(@RequestBody Map<String,Object> params,HttpServletRequest request,HttpServletResponse response) {
    response.setCharacterEncoding("UTF-8");
    try {
      // 将文件的路径获取到
      ObjectMapper mapper = new ObjectMapper();
      LinkedHashMap requestParMap = (LinkedHashMap)params.get("cmdExportConfig");
      CmdExportConfigDto cmdExportConfigDto = null;
      List<CmdExportFieldConfigDto> exportFieldList = null;
      if(requestParMap.size()>0){
        cmdExportConfigDto = mapper.convertValue(requestParMap,CmdExportConfigDto.class);
      }
      ArrayList arrayList = (ArrayList)params.get("exportFieldList");
      if(arrayList.size()>0){
        exportFieldList = mapper.convertValue(arrayList, new TypeReference<CmdExportFieldConfigDto>() {});
      }
      Map values = (Map)params.get("params");
      String filePath = excelService.exportExcel(cmdExportConfigDto,exportFieldList,params,request.getServletContext().getRealPath("/"));
      Map<String,String> map = new HashMap<String, String>();
      map.put("filepath", filePath);
      return new ResponseEntity(map,HttpStatus.OK);
    }catch (IOException e){
      throw new RuntimeException("输出文件出错");
    }
  } 

服务B:

/**
   *
   * @param busicode 导出的业务编码 能确定某个模块做导出操作
   * @param values 请求参数
   *
   *        通过restTemplate 传递复杂参数
   * @return
   * 返回 文件流 让浏览器弹出下载 目前需要解决 将字节流响应到浏览器的控制台了 后面均采用url下载的方式
   */
  @PostMapping(value = "/export/v3/{busicode}",produces = MediaType.TEXT_PLAIN_VALUE)
  @ResponseBody
  public ResponseEntity<byte[]> expDownLoadV3(@PathVariable("busicode") String busicode , @RequestBody Map<String,Object> values, HttpServletRequest request)throws Exception {
    String busiCode = values.get("busiCode").toString();
    if(StringUtils.isBlank(busiCode)){
      throw new BusinessRuntimeException("参数错误,请检查参数是否正确,busiCode ?");
    }
    // 获取执行过程
    Map map = excuteRestTemplate(busiCode,values);
    String path = (String)map.get("filepath");
    byte[] excel = FastDFSClient.downloadToBytes(path);
    CmdExportConfigDto cmdExportConfig = exportService.getCmdExportConfigByBusiCode(busiCode);
    //获取文件名
    String fileName = cmdExportConfig.getReportName();
    // 获取文件后缀名
    String extFileName = path.substring(path.lastIndexOf('.')+1);
    HttpHeaders headers = new HttpHeaders();erAgent = request.getHeader("USER-AGENT");
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    headers.setContentDispositionFormData("attachment", FrameUrlConstants.transFromFileName(userAgent,fileName) + "." + extFileName);
    return new ResponseEntity<byte[]>(excel,headers,HttpStatus.OK);
  }
  /**
   * 执行请求调用
   * @param busiCode
   * @param variables
   * @return
   */
   private Map excuteRestTemplate(String busiCode,Map variables){
     String serviceId="";
     //查询导出配置
     CmdExportConfigDto cmdExportConfig = exportService.getCmdExportConfigByBusiCode(busiCode);
     serviceId = cmdExportConfig.getSystemType();
     if(cmdExportConfig==null){
       throw new BusinessRuntimeException("没有导出配置无法导出");
     }
     //根据导出配置id获取导出字段信息
     List<CmdExportFieldConfigDto> exportFieldList = exportService.getAllCmdExportFieldConfigDtoByConfigId(cmdExportConfig.getId());
     if(StringUtils.isBlank(serviceId)){
       throw new BusinessRuntimeException("未配置导出的服务");
     }
     Map<String, Object> uriVariables = new HashMap<>();
     uriVariables.put("cmdExportConfig",cmdExportConfig);
     uriVariables.put("exportFieldList",exportFieldList);
     uriVariables.put("params",variables);
    return restTemplate.postForObject("http://" + serviceId + "/excelService/export/v2",new HttpEntity(uriVariables),Map.class);
   } 

设置浏览器头

/**
   * 根据不同的浏览器类型设置下载文件的URL编码
   * @param userAgent
   * @param fileName
   * @return
   * @throws Exception
   */
  public static String transFromFileName(String userAgent,String fileName) throws Exception{
    String finalFileName = "";
    if(StringUtils.contains(userAgent, "MSIE")){//IE浏览器
      finalFileName = URLEncoder.encode(fileName,"UTF-8");
    }else if(StringUtils.contains(userAgent, "Mozilla")){//google,火狐浏览器
      finalFileName = new String(fileName.getBytes("GBK"), "ISO8859-1");
    }else{
      finalFileName = URLEncoder.encode(fileName,"UTF-8");//其他浏览器
    }
    return finalFileName;
  } 

总结

以上所述是小编给大家介绍的Spring cloud restTemplate 传递复杂参数的方式(多个对象),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

时间: 2018-05-19

Spring使用RestTemplate模拟form提交示例

RestTemplate是用来在客户端访问Web服务的类.和其他的Spring中的模板类(如JdbcTemplate.JmsTemplate)很相似,我们还可以通过提供回调方法和配置HttpMessageConverter类来客户化该模板.客户端的操作可以完全使用RestTemplate和HttpMessageConveter类来执行. 1.声明RestTemplate的bean @Bean public RestTemplate restTemplate(){ return new RestT

springMVC中RestTemplate传值接值方法

我们需要给接口推送数据以及接口接收数据的时候,可以用springmvc中的一种简单方法 1.需要在spring-mvc.xml中配置信息转化器. <bean id = "stringHttpMessageConverter" class = "org.springframework.http.converter.StringHttpMessageConverter"/> <bean id="jsonHttpMessageConverter

详解SpringBoot通过restTemplate实现消费服务

一.RestTemplate说明 RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率.前面的博客中http://www.jb51.net/article/132885.htm,已经使用Jersey客户端来实现了消费spring boot的Restful服务,接下来,我们使用RestTemplate来消费前面示例中的Restful服务,前面的示例: springboot整合H2内存

Spring Boot使用RestTemplate消费REST服务的几个问题记录

我们可以通过Spring Boot快速开发REST接口,同时也可能需要在实现接口的过程中,通过Spring Boot调用内外部REST接口完成业务逻辑. 在Spring Boot中,调用REST Api常见的一般主要有两种方式,通过自带的RestTemplate或者自己开发http客户端工具实现服务调用. RestTemplate基本功能非常强大,不过某些特殊场景,我们可能还是更习惯用自己封装的工具类,比如上传文件至分布式文件系统.处理带证书的https请求等. 本文以RestTemplate来

Spring Boot RestTemplate提交表单数据的三种方法

在REST接口的设计中,利用RestTemplate进行接口测试是种常见的方法,但在使用过程中,由于其方法参数众多,很多同学又混淆了表单提交与Payload提交方式的差别,而且接口设计与传统的浏览器使用的提交方式又有差异,经常出现各种各样的错误,如405错误,或者根本就得不到提交的数据,错误样例如下: Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 405 Metho

Spring学习笔记之RestTemplate使用小结

前言 作为一个Java后端,需要通过HTTP请求其他的网络资源可以说是一个比较常见的case了:一般怎么做呢? 可能大部分的小伙伴直接捞起Apache的HttpClient开始做,或者用其他的一些知名的开源库如OkHttp, 当然原生的HttpURLConnection也是没问题的 本篇博文则主要关注点放在Sprig的生态下,利用RestTemplate来发起Http请求的使用姿势 I. RestTempalate 基本使用 0. 目标 在介绍如何使用RestTemplate之前,我们先抛出一些

Spring学习笔记3之消息队列(rabbitmq)发送邮件功能

rabbitmq简介: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们.消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术.排队指的是应用程序通过 队列来通信.队列的使用除去了接收和发送应用程序同时执行的要求.其中较为成熟的MQ产品有IBM WEBSPHERE MQ. 本节的内容是用户注册时,将邮

Spring学习笔记1之IOC详解尽量使用注解以及java代码

在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IOC,mybatis,SpringMVC的基础知识,表单数据验证,文件上传等) 2.服务器异步发送邮件给注册用户.(学习消息队列) 3.用户登录.(学习缓存.Spring Security) 4.其他. 边学习边总结,不定时更新.项目环境为Intellij + Spring4. 一.准备工作. 1.m

Spring学习笔记2之表单数据验证、文件上传实例代码

在上篇文章给大家介绍了Spring学习笔记1之IOC详解尽量使用注解以及java代码,接下来本文重点给大家介绍Spring学习笔记2之表单数据验证.文件上传实例代码,具体内容,请参考本文吧! 一.表单数据验证 用户注册时,需要填写账号.密码.邮箱以及手机号,均为必填项,并且需要符合一定的格式.比如账号需要32位以内,邮箱必须符合邮箱格式,手机号必须为11位号码等.可以采用在注册时验证信息,或者专门写一个工具类用来验证:来看下在SpringMVC中如何通过简单的注释实现表单数据验证. 在javax

Spring学习笔记之bean生命周期

前言 上一篇文章主要学习了下bean的配置.注入.自定义属性编辑器,今天来熟悉bean的生命周期. 任何一个事物都有自己的生命周期,生命的开始.生命中.生命结束.大家最熟悉的应该是servlet 的生命周期吧.和 servlet 一样 spring bean 也有自己的生命周期. 在开发中生命周期是一个很常见的名词,基本每种编程语言都能找到与它关联的.关于bean的生命周期我在网上也找了好多,基本都差不多.这里我主要是想通过代码来验证,毕竟学的知识都是一样的,都是学的Java,最重要的是动手练习

Spring学习笔记之RedisTemplate的配置与使用教程

前言 Spring针对Redis的使用,封装了一个比较强大的Template以方便使用:之前在Spring的生态圈中也使用过redis,但直接使用Jedis进行相应的交互操作,现在正好来看一下RedisTemplate是怎么实现的,以及使用起来是否更加便利 I. 基本配置 1. 依赖 依然是采用Jedis进行连接池管理,因此除了引入 spring-data-redis之外,再加上jedis依赖,pom文件中添加 <dependency> <groupId>org.springfra

Spring学习笔记之bean的基础知识

Bean: 在Spring技术中是基于组件的 最基本了是最常用的单元 其实实例保存在Spring的容器当中 Bean通常被定义在配置文件当中,Bean实例化由Spring的Ioc容器进行管理,Bean的实例可以通过Beanfactory进行访问,实际上大部分J2EE应用,Bean是通过ApplicationContext来访问的,ApplicationContext是BeanFactory的子接口,功能要比BeanFactory强大许多 在前面得博客依赖注入与控制反转中演示了应用spring实现

spring boot 学习笔记(入门篇)

简介: Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置.用我的话来理解,就是spring boot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架(不知道这样比喻是否合适). 优点: 其实就是简单.快速.方便!平时如果我们需要搭建一个spring web项目的时候需要怎么

Spring Security学习笔记(一)

介绍 这里学习SpringSecurity,对SpringSecurity进行学习. 基本用法 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 添加接口 package com.example.demo.web; import

JS学习笔记之数组去重实现方法小结

本文实例讲述了JS学习笔记之数组去重实现方法.分享给大家供大家参考,具体如下: 操作的数组 let arr=[0,1,23,'1',4,2,8,5,5,6,9,'asdasd','5'] 1. 利用ES6 的set 来进行数组去重 console.time("set") let type1=new Set(arr) console.log(type1) type1=[...type1] console.log(type1) console.timeEnd("set"