簡體   English   中英

如何在Spring Boot服務應用程序中的REST服務調用之間傳遞請求參數?

[英]How to pass request parameters as-is between REST service calls in a Spring Boot services application?

我們正在進行體系結構重構,以將單個J2EE EJB應用程序轉換為Spring服務。 為了做到這一點,我通過打破應用程序對其域的關節創建服務。 目前,我有三個,每個通過Rest調用另一個服務。

在這個項目中,我們的最終目的是將應用程序轉換為微服務,但由於雲基礎架構不明確且可能無法實現,我們決定以這種方式實現,並認為由於使用Rest的服務,因此很容易制作未來的轉變。

我們的方法有意義嗎? 我的問題源於此。


我使用來自Postman的頭參數userName向UserService發送請求。

GET http://localhost:8087/users/userId?userName=12345

UserService調用另一個調用另一個服務的服務。 服務之間的休息呼叫順序如下:

UserService ---REST--> CustomerService ---REST--> AlarmService

由於我現在正在進行這樣的公共請求參數的工作,所以我需要在每個通過從傳入請求到傳出請求獲取Rest請求的方法中設置公共頭參數:

@RequestMapping(value="/users/userId", method = RequestMethod.GET)
public ResponseEntity<Long> getUserId(@RequestHeader("userName") String userName) {
    ...
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Collections.singletonList
(MediaType.APPLICATION_JSON));

        headers.set("userName", userName);

        HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
        HttpEntity<Long> response =
                restTemplate.exchange(CUSTOMER_REST_SERVICE_URI,
                HttpMethod.GET, entity, Long.class);
     ...
 }

UserService:

package com.xxx.userservice.impl;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.Collections;
import java.util.Map;

@RestController
public class UserController  extends AbstractService{

    Logger logger = Logger.getLogger(UserController.class.getName());

    @Autowired
    private RestTemplate restTemplate;

    private final String CUSTOMER_REST_SERVICE_HOST = "http://localhost:8085";
    private final String CUSTOMER_REST_SERVICE_URI = CUSTOMER_REST_SERVICE_HOST + "/customers/userId";

    @RequestMapping(value="/users/userId", method = RequestMethod.GET)
    public ResponseEntity<Long> getUserId(@RequestHeader("userName") String userName) {
        logger.info(""user service is calling customer service..."");
        try {

            //do the internal customer service logic

            //call other service.
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Collections.singletonList
(MediaType.APPLICATION_JSON));
            headers.set("userName", userName);
            HttpEntity<String> entity = new HttpEntity<>("parameters", headers);

            HttpEntity<Long> response =
                    restTemplate.exchange(CUSTOMER_REST_SERVICE_URI,
                    HttpMethod.GET, entity, Long.class);

            return ResponseEntity.ok(response.getBody());
        } catch (Exception e) {
            logger.error("user service could not call customer service: ", e);
            throw new RuntimeException(e);
        }
        finally {
            logger.info("customer service called...");
        }
    }

}

客戶服務:

package com.xxxx.customerservice.impl;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.xxx.interf.CustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class CustomerController  extends AbstractService{

    private final String ALARM_REST_SERVICE_HOST = "http://localhost:8086";
    private final String ALARM_REST_SERVICE_URI = ALARM_REST_SERVICE_HOST + "/alarms/maxAlarmCount";

    @Autowired
    private CustomerService customerService;

    @Autowired
    private RestTemplate restTemplate;

    ...

    @GetMapping(path="/customers/userId", produces = "application/json")
    public long getUserId(@RequestHeader(value="Accept") String acceptType) throws RemoteException {

        //customer service internal logic.
        customerService.getUserId();

        //customer service calling alarm service.
        return restTemplate.getForObject(ALARM_REST_SERVICE_URI, Long.class);

    }

}

AlarmService:

package com.xxx.alarmservice.impl;

import com.xxx.interf.AlarmService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PriceAlarmController extends AbstractService{

    @Autowired
    private AlarmService priceAlarmService;

    @RequestMapping("/alarms/maxAlarmCount")
    public long getMaxAlarmsPerUser() {

        // alarm service internal logic.
        return priceAlarmService.getMaxAlarmsPerUser();
    }

}

我已經嘗試過這些配置和攔截器文件,但我可以只使用它們進行日志記錄,並且不能通過使用它們來傳輸標頭參數。 可能是因為每項服務都有它們。 此外,此攔截器僅適用於UserService,它首先使用RestTemplate發送請求。 來自Postman的被叫服務和第一個請求不能用於它,因為它們不會打印像UserService那樣的任何日志消息。

CommonModule:

package com.xxx.common.config;

import com.xxx.common.util.HeaderRequestInterceptor;
import org.apache.cxf.common.util.CollectionUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        List<ClientHttpRequestInterceptor> interceptors
                = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }
        interceptors.add(new HeaderRequestInterceptor());
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }
}

ClientHttpRequestInterceptor:


package com.xxx.common.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

import java.io.IOException;
import java.nio.charset.Charset;

public class HeaderRequestInterceptor implements ClientHttpRequestInterceptor {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    public ClientHttpResponse intercept(
            HttpRequest request,
            byte[] body,
            ClientHttpRequestExecution execution) throws IOException
    {
        log.info("HeaderRequestInterceptor....");
        logRequest(request, body);
        request.getHeaders().set("Accept", MediaType.APPLICATION_JSON_VALUE);

        ClientHttpResponse response = execution.execute(request, body);
        logResponse(response);

        return response;
    }

    private void logRequest(HttpRequest request, byte[] body) throws IOException
    {
        log.info("==========request begin=======================");
    }

    private void logResponse(ClientHttpResponse response) throws IOException
    {
        log.info("==========response begin=============");
    }

}

如何通過在一個地方使用某種攔截器或其他機制來管理像userName這樣的公共頭信息的傳遞?

在HeaderRequestInterceptor的攔截方法中,您可以通過以下方式訪問當前的http請求及其標頭(在您的情況下為userId):

@Override
public ClientHttpResponse intercept(HttpRequest request..
...
   HttpServletRequest httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
   String userId = httpServletRequest.getHeader("userId");
   request.getHeaders().set("userId", userId);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM