RestTemplate.exchange()构造Http请求

〇、配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/*
restTemplate 配置类  ——  基础配置写法
 */

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    /**
     * 配置一个简单的 HTTP 请求工厂, 设置 HTTP 请求的超时时间
     * @return
     */
    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(150000); // ms
        factory.setConnectTimeout(150000); // ms
        return factory;
    }
}

一、GET请求

1.1 GET返回String

RestTemplate接口

// 1.1 get请求返回基本类型
@GetMapping("/name")
public String getName(@RequestParam("id") Integer id) {
    String url = "http://localhost:8080/name/Rest?id=" + id;
    return restTemplate.exchange(url, HttpMethod.GET, null, String.class).getBody();
    
    //getBody() 得到数据
}

被调用接口

@GetMapping("/name/Rest")
public String mockName(@RequestParam("id") Integer id) {
    return "接口提供数据 " + id;
}

1.2 GET返回Pojo

请求接口

// 1.2 get请求返回对象类型
@GetMapping("/user")
public UserDto getUser(@RequestParam("id") Integer id) {
    String url = "http://localhost:8080/user/Rest?id=" + id;
    return restTemplate.exchange(url, HttpMethod.GET, null, User.class).getBody();
}

被调用接口

@GetMapping("/user/Rest")
public UserDto mockUser(@RequestParam("id") Integer id) {
    return UserDto.builder().id(id)
            .name("name" + id)
            .age(id + 18)
            .birthday(new Date()).build();
}

1.3 GET返回List<>

调用接口

// 1.3 get请求返回List<T>类型
@GetMapping("/user/list")
public List<UserDto> getUserList(@RequestParam("name") String name) {
    String url = "http://localhost:8080/user/list/Rest?name=" + name;
    ParameterizedTypeReference<List<UserDto>> responseBodyType = new ParameterizedTypeReference<List<UserDto>>() {};
    return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
    
    //restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<List<UserDto>>() {}).getBody();
}

被调用接口

@GetMapping("/user/list/Rest")
public List<UserDto> mockUserList(@RequestParam("name") String name) {
    ...
        
    return list;
}

1.4 GET返回Map<key, value>

调用接口

// 1.4 get请求返回Map类型
@GetMapping("/user/map")
public Map<String, Object> getUserMap(@RequestParam(value = "type", required = true) Integer type, @RequestParam("key") String key) {
    String url = "http://localhost:8080/user/Rest?type=" + type + "&key=" + key;
    ParameterizedTypeReference<Map<String, Object>> responseBodyType = new ParameterizedTypeReference<Map<String, Object>>() {};
    return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
}

被调用接口

@GetMapping("/user/map/mock")
public Map<String, Object> mockUserMap(@RequestParam(value = "type", required = true) Integer type, @RequestParam("key") String key) {
    Map<String, Object> map = new HashMap<>();
    if (type.equals(1)) {
        map.put("id", 1);
        map.put("name" + type, "hello" + key);
    } else {
        map.put("id", 2);
        map.put("name" + type, "hello" + key);
    }
    return map;
}

1.5 GET返回Result<>

调用接口

// 1.5 get请求返回自定义泛型类型
@GetMapping("/user/result")
public Result<UserDto> getUserResult(@RequestParam("id") Integer id) {
    String url = "http://localhost:8080/user/result/Rest?id=" + id;
    ParameterizedTypeReference<Result<UserDto>> responseBodyType = new ParameterizedTypeReference<Result<UserDto>>() {};
    return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
}

被调用接口

@GetMapping("/user/result/mock")
public Result<UserDto> mockUserResult(@RequestParam("id") Integer id) {
    ...
        
    return Result.success("200", "成功", user);
}

二、POST请求

2.1 header+body返回Pojo

调用函数

@GetMapping("/user/body")
public UserDto postUser(@RequestParam("id") Integer id) {
    String url = "http://localhost:8080/user/body/Rest";
    UserDto body = UserDto.builder().id(id)
            .name("body" + id)
            .age(id + 18)
            .birthday(new Date()).build();
    
    // header根据实际情况设置,没有就空着
    HttpHeaders headers = new HttpHeaders();
    headers.add("AccessKey", "自定义的API访问key");
    headers.add("Content-Type", "application/json");
    HttpEntity<?> requestEntity = new HttpEntity<>(body, headers);
    
    return restTemplate.exchange(url, HttpMethod.POST, requestEntity, UserDto.class).getBody();
    
    //被调用函数是用@RequestBody 实体类来接受的参数
}

被调用函数

@PostMapping("/user/body/Rest")
public UserDto mockPostUser(@RequestBody UserDto userParam) {
    return userParam;
}

2.2 header+body返回Result<>

只需要和GET请求一样,更改类型即可

ParameterizedTypeReference<Result<UserDto>> responseBodyType = new ParameterizedTypeReference<Result<UserDto>>(){};
    return restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseBodyType).getBody();

三、JSON格式处理

依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.12.6</version>
</dependency>
// 提取 JSON 字符串
String jsonString = responseEntity.getBody();

try {
    // 创建 ObjectMapper 对象
    ObjectMapper objectMapper = new ObjectMapper();

    // 将 JSON 字符串转换为实体类对象
    RestRegionDTO restRegionDTO = objectMapper.readValue(jsonString, RestRegionDTO.class);

    // 打印转换后的实体类对象
    System.out.println(restRegionDTO);
} catch (Exception e) {
    //e.printStackTrace();
    log.error("JSON格式处理发生异常");
}

完整代码

/**
 * 请求太平洋 获得ip归属地信息
 * @param ipAddress
 * @return
 */
public RestRegionDTO getIpAddr(String ipAddress) {
    String url = "http://whois.pconline.com.cn/ipJson.jsp?ip="+ipAddress+"&json=true";

    // 发送 HTTP GET 请求并获取响应
    ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
    // 提取 JSON 字符串
    String jsonString = exchange.getBody();

    RestRegionDTO restRegionDTO = new RestRegionDTO();
    try {
        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();
        // 将 JSON 字符串转换为实体类对象
        restRegionDTO = objectMapper.readValue(jsonString, RestRegionDTO.class);
        // 打印转换后的实体类对象
        log.info(String.valueOf(restRegionDTO));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return restRegionDTO;
}

四、异常处理

try {
    ResponseEntity<List<AppModel>> responseEntity = restTemplate.exchange(getApps, HttpMethod.GET, null, new ParameterizedTypeReference<List<AppModel>>() {});
    //返回的状态码 == 200
    if (responseEntity.getStatusCode() == HttpStatus.OK) {
        List<AppModel> result = responseEntity.getBody();
        if (result != null && !result.isEmpty()) {
            return result;
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}
	return null;

五、参考

使用RestTemplate发请求时自动拼接header信息(一学就会系列)_resttemplate 拦截器加header-CSDN博客

RestTemplate.exchange各种用法(包括泛型等 --全)-腾讯云开发者社区-腾讯云 (tencent.com)

RestTemplate总结_resttemple-CSDN博客

restTemplate配置及使用 - 简书 (jianshu.com)

六、结合AOP实现登录日志存储

自定义注解loginLog

/**
 * 自定义注解,实现 登录日志 ip 记录
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface loginLog {
}

切面

/**
 * 实现登陆用户 日志的记录
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LoginLogAspect {
    private final LoginLogService loginLogService;
    private final RestTemplateController restTemplateController;

    //扫描加注释的方法
    @Pointcut("@annotation(com.example.demoip.Annotation.loginLog)")
    public void loginLog() {
    }


    @AfterReturning(pointcut = "loginLog()")
    public void afterReturning(JoinPoint joinPoint) {
        LocalDateTime now = LocalDateTime.now();

        //获得签名
        Signature signature = joinPoint.getSignature();
        //获得切入的包名
        String declaringTypeName = signature.getDeclaringTypeName();
        //拿到方法名
        String name = signature.getName();

        // 也可以用来记录一些信息,比如获取请求的 URL 和 IP
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 请求里面获得ip
        String ip = IpUtils.getIpAddr(request);


        // 获取请求 URL
        String url = request.getRequestURL().toString();
        log.info("执行切点的包名:"+declaringTypeName+" 方法名:"+name+" url:"+url);

        // 获得所有参数
        Object[] args = joinPoint.getArgs();
        User user = (User) args[0];

        // ip归属地
        String cityInfo = null;

        //发送http请求
        cityInfo = restTemplateController.getIpAddr(ip).getCity();
        System.out.println(cityInfo);

        loginLogService.saveLoginLog(
                LoginLog.builder()
                        .ip(ip)
                        .ipAttribution(cityInfo)
                        .name(user.getUserName())
                        .createTime(now)
                        .build());
        log.info("日志存入数据库");
    }
}

构造RestTemplate Http请求

/**
 * 请求太平洋 获得ip归属地信息 返回的是JSON数据
 * @param ipAddress
 * @return
 */
public RestRegionDTO getIpAddr(String ipAddress) {
    String url = "http://whois.pconline.com.cn/ipJson.jsp?ip="+ipAddress+"&json=true";

    // 发送 HTTP GET 请求并获取响应
    ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
    // 提取 JSON 字符串
    String jsonString = exchange.getBody();

    RestRegionDTO restRegionDTO = new RestRegionDTO();
    try {
        // 创建 ObjectMapper 对象
        ObjectMapper objectMapper = new ObjectMapper();
        // 将 JSON 字符串转换为实体类对象
        restRegionDTO = objectMapper.readValue(jsonString, RestRegionDTO.class);
        // 打印转换后的实体类对象
        log.info(String.valueOf(restRegionDTO));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return restRegionDTO;
}