如何在Spring Boot Services应用程序中使用REST服务调用之间的请求参数



我们正在做一个建筑重构,以将整体式J2EE EJB应用程序转换为Spring Services。为此,我正在通过针对其域的关节打破应用程序来创建服务。目前,我有三个,每个人都通过休息来调用另一个服务。

在此项目中,我们的最终目的是将应用程序转换为微服务,但是由于云基础架构尚不清楚,而且可能不可能,我们决定这样做,并认为由于使用REST的服务,

很容易使转换变换

我们的方法有意义吗?我的问题源于此。


我将请求发送给使用标题参数的UserService,postman的用户名。

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

用户服务调用另一个调用另一个服务的服务。服务之间的休息呼叫订单是:

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

由于我现在正在进行这样的携带常见请求参数的工作,因此我需要在每种方法中设置常见的标题参数,以通过将其从传入请求带到传出请求来进行休息请求:

@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);
     ...
 }

用户服务:

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...");
        }
    }
}

customerservice:

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();
    }
}

我尝试了这些配置和拦截器文件,但是我可以将它们仅用于登录,并且无法通过使用它们来传输标头参数。可能是因为每个服务都有它们。而且,此拦截器仅在使用RESTTEMPLATE发送请求的用户服务中起作用。来自Postman发出的称为服务和第一个请求,因为他们没有像UserVice这样的任何日志消息。

COMPORMODULE:

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=============");
    }
}

如何通过在单个位置使用某种拦截器或其他机制来管理通用标题信息(例如用户名)?

在您的HeaderRequestcteptor的拦截方法中,您可以通过以下方式访问当前的HTTP请求及其标题(用户ID):

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

最新更新