自定义springboot组件--统一封装http客户端实现

http是第三方接口调用的常用工具,该组件通过对常见的http客户端工具进行统一的整合,参考了feign的上下文和springmvc的拦截器等相关设计思路,设计了相应的Context用于对请求上下文的相关配置进行统一的配置,避免客户端配置混乱配置,保证了项目的统一配置,并内置了相应拦截器,用于客户端自定义相关的业务逻辑,比如:通过模仿feign的拦截器,解决了feig三方接口调用时无token的尴尬.

一 基本原理

在这里插入图片描述

  • 客户端发起http调用时,通过请求执行器,执行底层请求逻辑
  • 从请求的上下文中获得相应编码器,对body进行统一的序列化处理
  • 获得相应的前置处理器,执行自定义的业务前置处理(如token等公用参数的绑定)
  • 调用httprequestclient执行http请求(更具项目的自身需求,配置相应的客户端,默认为:JDK HttpURLConnection)
  • 请求发生异常,执行requestExceptionHandler中handler逻辑
  • 解析当前响应状态码,状态码不为200执行responseErrorHandler逻辑
  • 根据当前请求是否配置相应的响应前置处理器,做响应前置处理,没有直接通过解码器反序列化后相应当前请求的数据

二 客户端调用

2.1 根据项目的实际需求配置核心参数

详见源码具体配置
在这里插入图片描述

2.2 根据项目的实际需求选择相应的http客户端

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
默认http客户端
在这里插入图片描述

2.3 引入相应的组件

 <dependency>
            <groupId>com.cncloud</groupId>
            <artifactId>shell-platform-common-http-client</artifactId>
 </dependency>

2.4 bean方式调用

@RestController
@RequestMapping("/client")
@Slf4j
public class HttpClientController {

    @Autowired
    private HttpRequestExecutor httpRequestExecutor;

    public static final String LOGIN_URL = "https://develop.shequtalk.com/auth/oauth/token";

    public static final String GET_URL = "https://develop.shequtalk.com/admin/user/getUserListByDept";



    @PostMapping("/testPost")
    @Inner(value = false)
    public void testPost(){
        HttpRequest request = getLoginRequest();
        final R result = httpRequestExecutor.execute(request);
        log.info("login result : {}",result);
    }

    @GetMapping("/testGet")
    @Inner(value = false)
    public void testGet(){
        HttpRequest request = new BasicRequestBuilder(GET_URL)
                .header("tenant-id", "6054656364413952")
                .header("authorization", "Bearer 8350ebce-1f98-41e3-a30f-69f4f6702119")
                .method(RequestMethod.GET)
                .query("sysDeptId", "6054656376194048")
                .query("current", 1)
                .query("size", 10)
                .resultType(R.class)
                .build();
        R result = httpRequestExecutor.execute(request);
        log.info("query result: {}",result);
    }
    private HttpRequest getLoginRequest() {
        HashMap<String, Object> bodyMap = new HashMap<>();
        bodyMap.put("username","szs");
        bodyMap.put("password","rKu1/348LvKp0rsVC06eCA==");
        bodyMap.put("grant_type","password");

        HttpRequest request = new BodyRequestBuilder<>(LOGIN_URL)
                .header("tenant-id", "6054656364413952")
                .header("authorization","Basic c2hlbGxwYzpzaGVsbHBj")
                .method(RequestMethod.POST)
                .form(bodyMap)
                .resultType(R.class)
                .build();
        return request;
    }
}

采用相应的构造者构建相应的请求
在这里插入图片描述

2.5 非bean方式调用

@RestController
@RequestMapping("/client")
@Slf4j
public class HttpClientController {

    @Autowired
    private HttpRequestExecutor httpRequestExecutor;

    public static final String LOGIN_URL = "https://develop.shequtalk.com/auth/oauth/token";

    public static final String GET_URL = "https://develop.shequtalk.com/admin/user/getUserListByDept";
    
    @PostMapping("/testNoBeanWithHutool")
    @Inner(value = false)
    public void testNoBeanWithHutool(){
        HttpRequestClient httpRequestClient = new HutoolRequestClient();
        final HttpRequestExecutor httpRequestExecutor = initHttpRequestExecutor(httpRequestClient);
        HttpRequest request = getLoginRequest();
        final R result = httpRequestExecutor.execute(request);
        log.info("login result : {}",result);
    }

    private HttpRequestExecutor initHttpRequestExecutor(HttpRequestClient httpRequestClient) {

        return new DefaultHttpRequestExecutor(getContext(), httpRequestClient);
    }

    private Context getContext() {
        TimeoutSetting timeoutSetting = new TimeoutSetting();
        Encoder encoder = new DefaultEncoder();
        Decoder decoder = new DefaultDecoder();
        return new DefaultContext(timeoutSetting, decoder, encoder);
    }



    private HttpRequest getLoginRequest() {
        HashMap<String, Object> bodyMap = new HashMap<>();
        bodyMap.put("username","szs");
        bodyMap.put("password","rKu1/348LvKp0rsVC06eCA==");
        bodyMap.put("grant_type","password");

        HttpRequest request = new BodyRequestBuilder<>(LOGIN_URL)
                .header("tenant-id", "6054656364413952")
                .header("authorization","Basic c2hlbGxwYzpzaGVsbHBj")
                .method(RequestMethod.POST)
                .form(bodyMap)
                .resultType(R.class)
                .build();
        return request;
    }
}

三 核心API

/**
 * http请求执行器
 * @author likun
 * @date 2022/7/25 10:14
 */
public interface HttpRequestExecutor {
    /**
     *  执行http请求(异常处理器及前置拦截器均可传入)
     * @param request 核心请求
     * @param requestExceptionHandler 请求发送异常处理器
     * @param responseErrorHandler 相应异常处理器
     * @param requestInterceptor 请求拦截器
     * @param responseInterceptor 相应拦截器
     * @param <T>
     * @return
     */
    <T> T execute(HttpRequest request, RequestExceptionHandler requestExceptionHandler, ResponseErrorHandler responseErrorHandler,
                  RequestInterceptor requestInterceptor, ResponseInterceptor responseInterceptor);

    /**
     * 执行http请求(使用默认的拦截器和异常处理器)
     * @param request
     * @param <T>
     * @return
     */
    default <T> T execute(HttpRequest request){
        return execute(request,null,null,null,null);
    }

    /**
     * 执行http请求 (可以传入请求异常及响应状态码非200的请求处理器)
     * @param request
     * @param requestExceptionHandler
     * @param responseErrorHandler
     * @param <T>
     * @return
     */
    default <T> T execute(HttpRequest request, RequestExceptionHandler requestExceptionHandler, ResponseErrorHandler responseErrorHandler){
        return execute(request, requestExceptionHandler, responseErrorHandler, null, null);
    }

    /**
     * 执行http请求(可以传入请求前置拦截器及响应解码的前置拦截器)
     * @param request
     * @param requestInterceptor
     * @param responseInterceptor
     * @param <T>
     * @return
     */
    default <T> T execute(HttpRequest request, RequestInterceptor requestInterceptor, ResponseInterceptor responseInterceptor) {
        return execute(request, null, null, requestInterceptor, responseInterceptor);
    }


}

四 项目源码

由于改组件的源码较长,这里不在文章中展示,需要的可以私信笔者.

### 如何使用 Spring Boot 创建 HTTP RESTful API #### 项目创建与依赖管理 要开始构建基于 Spring Boot 的 RESTful API 应用程序,首先需要设置一个新的 Maven 或 Gradle 项目,并引入必要的依赖项。对于大多数 Web 应用来说,`spring-boot-starter-web` 是必需的,因为它包含了构建 Web 应用所需的核心库。 ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> ``` #### 启动类定义 接着,在应用程序入口处编写启动类,该类通常带有 `@SpringBootApplication` 注解,用于启用自动配置和其他特性。此注解集成了组件扫描、配置属性加载等功能[^3]。 ```java package cn.juwatech.springbootrest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringBootRestApplication { public static void main(String[] args) { SpringApplication.run(SpringBootRestApplication.class, args); } } ``` #### 控制器层设计 为了暴露 REST 接口给客户端调用,需创建一个控制器类。此类中的每一个公共方法都映射到具体的 URL 路径上,并通过相应的 HTTP 方法访问。例如: - 使用 `@RestController` 来标记这是一个返回 JSON 数据而非视图页面的控制器; - 利用 `@RequestMapping`, `@GetMapping`, `@PostMapping` 等注解指定路由规则以及所支持的方法类型; 下面是一个简单的例子展示如何获取单个用户的详情信息[^5]。 ```java @RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; @Autowired public UserController(UserService userService){ this.userService = userService; } /** * 获取指定ID的用户对象. */ @GetMapping("/{id}") public ResponseEntity<User> getUserById(@PathVariable Long id) { User user = userService.findById(id).orElseThrow(() -> new ResourceNotFoundException("User not found")); return ResponseEntity.ok(user); } // 更多接口... } ``` 这里展示了基本 CRUD 操作之一——读取资源的操作模式。当接收到 GET 请求 `/api/users/{id}` 时,会触发上述方法执行查询逻辑并将结果封装成 `ResponseEntity` 返回给前端。 #### 错误处理机制 良好的错误处理也是高质量 API 设计的一部分。可以自定义全局异常处理器来统一管理和标准化不同类型的异常情况下的响应格式。这有助于提高用户体验的一致性和可靠性。 ```java @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler(ResourceNotFoundException.class) protected ResponseEntity<Object> handleResourceNotFound(RuntimeException ex, WebRequest request) { String bodyOfResponse = "This should be application specific"; return handleExceptionInternal(ex, bodyOfResponse, new HttpHeaders(), HttpStatus.NOT_FOUND, request); } // 处理更多异常... } ``` 以上就是利用 Spring Boot 构建简单却功能完备的 RESTful API 所涉及的关键要素概述[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值