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 传递复杂参数的方式(多个对象),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Spring学习笔记之RestTemplate使用小结

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

  • springMVC中RestTemplate传值接值方法

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

  • Spring使用RestTemplate模拟form提交示例

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

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

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

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

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

    使用微服务的时候往往服务之间调用比较麻烦,spring cloud提供了Feign接口调用,RestTemplate调用的方式 这里我探讨下RestTemplate调用的方式: 服务A:接收三个对象参数  这三个参数的是通过数据库查询出来的 服务B:要调用服务A 服务B提供了查询三个参数的方法,后面要使用三个参数 对于服务A,处理的方式有两中 1. 服务B提供一个Feign接口将查询三个参数的方法公开,服务A直接引用Feign来查询参数,服务B只需要将三个查询关键字传递过去即可 服务A acti

  • spring cloud gateway中如何读取请求参数

    spring cloud gateway读取请求参数 1. 我的版本: spring-cloud:Hoxton.RELEASE spring-boot:2.2.2.RELEASE spring-cloud-starter-gateway 2. 请求日志 import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springfram

  • Spring Cloud Feign 使用对象参数的操作

    目录 概述 @RequestBody @SpringQueryMap QueryMapEncoder 解决方案 概述 Spring Cloud Feign 用于微服务的封装,通过接口代理的实现方式让微服务调用变得简单,让微服务的使用上如同本地服务.但是它在传参方面不是很完美.在使用 Feign 代理 GET 请求时,对于简单参数(基本类型.包装器.字符串)的使用上没有困难,但是在使用对象传参时却无法自动的将对象包含的字段解析出来. 如果你没耐心看完,直接跳到最后一个标题跟着操作就行了. @Req

  • spring cloud config分布式配置中心的高可用问题

    在前面的文章中,我们实现了配置文件统一管理的功能,但是我们可以发现,我们仅仅只用了一个server,如果当这个server挂掉的话,整个配置中心就会不可用,下面,我们就来解决配置中心的高可用问题. 下面我们通过整合Eureka来实现配置中心的高可用,因为作为架构内的配置管理,本身其实也是可以看作架构中的一个微服务,我们可以把config server也注册为服务,这样所有客户端就能以服务的方式进行访问.通过这种方法,只需要启动多个指向同一Gitlab仓库位置的config server端就能实现

  • Spring Cloud升级最新Finchley版本的所有坑

    Spring Boot 2.x 已经发布了很久,现在 Spring Cloud 也发布了 基于 Spring Boot 2.x 的 Finchley 版本,现在一起为项目做一次整体框架升级. 升级前 => 升级后 Spring Boot 1.5.x => Spring Boot 2.0.2 Spring Cloud Edgware SR4 => Spring Cloud Finchley.RELEASE Eureka Server Eureka Server 依赖更新 升级前: <

  • Spring Cloud GateWay 路由转发规则介绍详解

    Spring在因Netflix开源流产事件后,在不断的更换Netflix相关的组件,比如:Eureka.Zuul.Feign.Ribbon等,Zuul的替代产品就是SpringCloud Gateway,这是Spring团队研发的网关组件,可以实现限流.安全认证.支持长连接等新特性. Spring Cloud Gateway Spring Cloud Gateway是SpringCloud的全新子项目,该项目基于Spring5.x.SpringBoot2.x技术版本进行编写,意在提供简单方便.可

  • 详解Spring Cloud Finchley版中Consul多实例注册的问题处理

    consul 简介 consul 具有以下性质: 服务发现:consul通过http 方式注册服务,并且服务与服务之间相互感应. 服务健康监测 key/value 存储 多数据中心 consul可运行在mac windows linux 等机器上. 由于Spring Cloud对Etcd的支持一直没能从孵化器中出来,所以目前来说大多用户还在使用Eureka和Consul,之前又因为Eureka 2.0不在开源的消息,外加一些博眼球的标题党媒体使得Eureka的用户有所减少,所以,相信在选择Spr

  • 浅谈升级Spring Cloud到Finchley后的一点坑

    最近为了使用Kotlin以及Webflux进行后台应用开发,把Spring Cloud版本升级到了Finchley. 这种大版本的提升,坑自然是少不了的,我最近会把遇到问题都总结在这里避免大家花太多时间在排坑上: Failed to bind properties under 'eureka.instance.instance-id' to java.lang.String: Description: Failed to bind properties under 'eureka.instanc

  • Spring Cloud Alibaba使用Sentinel实现接口限流

    最近管点闲事浪费了不少时间,感谢网友 libinwalan 的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一段落,后续与其他结合的内容等讲到的时候再一起拿出来说,不然内容会有点跳跃.接下来我们就来一起学习一下Spring Cloud Alibaba下的另外一个重要组件:Sentinel. Sentinel是什么 Sentinel的官方标题是:分布式系统的流量防卫兵.从名字上来看,很容易就能猜到它是用来

  • Spring MVC传递接收参数方式小结

    目录 一.通过实体Bean接收请求参数 二.通过处理方法的形参接收请求参数 三.通过HttpServletRequest接收请求参数 四.通过@PathVariable接收URL中的请求参数 五.通过@RequestParam接收请求参数 六.通过@ModelAttribute接收请求参数 大家在开发中经常会用到Spring MVC Controller来接收请求参数,主要常用的接收方式就是通过实体对象以及形参等方式.有些用于GET请求,有些用于POST请求,有些用于两者. 下面的几种常见的后台

随机推荐