优雅的请求接口(java)
前言
最近转发了一些 PDD 的 SDK,发现他代码中同一个请求方法使用不同的入参可以返回不同的出参,如果不是写死的话,就很有借鉴意义
思路:
定义两个模板类,一个为返回(response),一个为请求(request)
请求模板类
里面有个模板方法为设置出参类型
在
入参类
中继承请求模板类
添加出参
的class在
请求方法
中利用入参类
获取出参
的class,生成出参类
代码
统一返回类:Results
/*** 用于返回** @param <T>*/
@ApiModel("统一返回类")
public class Results<T> {public static final String ERROR = "500";public static final String SUCCESS = "200";/*** 返回码*/@ApiModelProperty("返回码,正确码为:200")private String resCode;/*** 返回消息*/@ApiModelProperty("返回消息")private String msg;/*** 返回实体*/@ApiModelProperty("返回实体")private T obj;public static <T> Results<T> success() {return success(SUCCESS, "成功", null);}public static <T> Results<T> success(String msg) {return success(SUCCESS, msg, null);}public static <T> Results<T> success(T obj) {return success(SUCCESS, "成功", obj);}public static <T> Results<T> success(String msg, T obj) {return success(SUCCESS, msg, obj);}public static <T> Results<T> success(String resCode, String msg, T obj) {Results<T> result = new Results<T>();result.setResCode(resCode);result.setMsg(msg);result.setObj(obj);return result;}public static <T> Results<T> failed() {return failed(ERROR, "失败", null);}public static <T> Results<T> failed(String msg) {return failed(ERROR, msg, null);}public static <T> Results<T> failed(String msg, T obj) {return failed(ERROR, msg, obj);}public static <T> Results<T> failed(String resCode, String msg) {return failed(resCode, msg, null);}public static <T> Results<T> failed(Integer resCode, String msg) {return failed(String.valueOf(resCode), msg);}public static <T> Results<T> failed(String resCode, String msg, T obj) {Results<T> result = new Results<T>();result.setResCode(resCode);result.setMsg(msg);result.setObj(obj);return result;}public String getResCode() {return resCode;}public void setResCode(String resCode) {this.resCode = resCode;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getObj() {return obj;}public void setObj(T obj) {this.obj = obj;}@Overridepublic String toString() {return "Results{" +"resCode='" + resCode + '\'' +", msg='" + msg + '\'' +", obj=" + obj +'}';}
}
两个模板类(HttpCommonRequest、HttpCommonResponse)
请求模板类:HttpCommonRequest
/*** 入参模板类*/
@Data
@ToString
@Slf4j
public abstract class HttpCommonRequest<T> {/*** 请求时间*/private Long timestamp;/*** 自定义头标签*/private Map<String, String> headers;/*** 获取出参模板方法* 例如:* public Class<UploadFilesVo> getResponseClass() {* return UploadFilesVo.class;* }*/public abstract Class<T> getResponseClass();public Long getTimestamp() {if (this.timestamp == null) {this.timestamp = System.currentTimeMillis() / 1000L;}return this.timestamp;}/*** 获取子类的属性与值** @return Map<String, String>*/public final Map<String, String> getParamsMap() {Map<String, Object> paramsFrom = getParamsFrom();return paramsFrom.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,entry -> {String v = "null";Object value = entry.getValue();if (value != null) {if (this.isPrimaryType(value)) {v = String.valueOf(value);} else {v = JSON.toJSONString(value);}}return v;}));}/*** 获取子类的属性与值,主要用于 form 表单提交** @return Map<String, Object>*/public final Map<String, Object> getParamsFrom() {try {Map<String, Object> paramsMap = new TreeMap<>();paramsMap.put("timestamp", this.getTimestamp().toString());this.setUserParams(paramsMap);return paramsMap;} catch (IllegalAccessException e) {log.error("HttpCommonRequest getParamsFrom 获取表单数据失败", e);throw new RuntimeException(e.getMessage());}}/*** 设置子类属性模板类* 例如:* protected void setUserParams(Map<String, Object> params) throws IllegalAccessException {* setUserParam(params, this);* }*/protected abstract void setUserParams(Map<String, Object> params) throws IllegalAccessException;/*** 子类可以调用该方法设置属性值** @param paramMap 总参数* @param r 子类(this)*/protected final <R> void setUserParam(Map<String, Object> paramMap, R r) throws IllegalAccessException {Class<?> tClass = r.getClass();Field[] declaredFields = tClass.getDeclaredFields();for (Field declaredField : declaredFields) {declaredField.setAccessible(true);Object o = declaredField.get(r);if (o != null) {String fieldName = declaredField.getName();paramMap.put(fieldName, o);}}}/*** 判断是否为基础类型*/private boolean isPrimaryType(Object param) {if (param instanceof Boolean) {return true;} else if (param instanceof Byte) {return true;} else if (param instanceof Character) {return true;} else if (param instanceof Short) {return true;} else if (param instanceof Integer) {return true;} else if (param instanceof Long) {return true;} else if (param instanceof Float) {return true;} else if (param instanceof Double) {return true;} else {return param instanceof String;}}
}
返回模板类:HttpCommonResponse
/*** 出参模板类*/
@ToString
@Data
public class HttpCommonResponse {/*** 返回时间*/private Long timestamp;public Long getTimestamp() {if (this.timestamp == null) {this.timestamp = System.currentTimeMillis() / 1000L;}return this.timestamp;}
}
请求方法:HttpUtils(用到了Hutool、FastJson、Lombok)
package com.example.test.utils;import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.example.test.exception.HttpCommonException;
import com.example.test.pojo.common.HttpCommonRequest;
import com.example.test.pojo.common.HttpCommonResponse;
import com.example.test.pojo.dto.GetUserDto;
import com.example.test.pojo.dto.UploadFilesDto;
import com.example.test.pojo.vo.GetUserVO;
import com.example.test.pojo.vo.UploadFilesVo;
import lombok.extern.slf4j.Slf4j;import java.io.File;
import java.util.Map;@Slf4j
public class HttpUtils {/*** 默认超时时间*/private static final int DEFAULT_TIMEOUT = 5000;/*** 最小超时时间*/private static final int MIN_TIMEOUT = 2000;/*** 空参*/private static final String EMPTY_BODY_LOG = "{}";/*** 参数返回*/private static final TypeReference<Results<JSONObject>> RESULT_TYPE_REF = new TypeReference<Results<JSONObject>>() {};// ==================================== region POST方法 ====================================public static <T extends HttpCommonResponse> T post(String url, HttpCommonRequest<T> request) {return post(url, request, DEFAULT_TIMEOUT);}/*** 普通请求** @param url 链接* @param request 入参* @param timeout 超时时间*/public static <T extends HttpCommonResponse> T post(String url, HttpCommonRequest<T> request, int timeout) {return executeJsonRequest(url, request, HttpMethod.POST, timeout);}public static <T extends HttpCommonResponse> T post(String url, Class<T> responseType) {return post(url, responseType, DEFAULT_TIMEOUT);}/*** 无入参有出参** @param url 链接* @param responseType 出参 class 类* @param timeout 超时时间*/public static <T extends HttpCommonResponse> T post(String url, Class<T> responseType, int timeout) {return executeEmptyRequest(url, responseType, HttpMethod.POST, timeout);}public static <T extends HttpCommonResponse> T postForm(String url, HttpCommonRequest<T> request) {return postForm(url, request, DEFAULT_TIMEOUT);}/*** form 表单提交** @param url 链接* @param request 请求体* @param timeout 超时时间*/public static <T extends HttpCommonResponse> T postForm(String url, HttpCommonRequest<T> request, int timeout) {return executeFormRequest(url, request, HttpMethod.POST, timeout);}// ==================================== endregion ====================================// ==================================== region GET方法 ====================================public static <T extends HttpCommonResponse> T get(String url, HttpCommonRequest<T> request) {return get(url, request, DEFAULT_TIMEOUT);}public static <T extends HttpCommonResponse> T get(String url, HttpCommonRequest<T> request, int timeout) {return executeJsonRequest(url, request, HttpMethod.GET, timeout);}public static <T extends HttpCommonResponse> T get(String url, Class<T> responseType) {return get(url, responseType, DEFAULT_TIMEOUT);}public static <T extends HttpCommonResponse> T get(String url, Class<T> responseType, int timeout) {return executeEmptyRequest(url, responseType, HttpMethod.GET, timeout);}public static <T extends HttpCommonResponse> T getForm(String url, HttpCommonRequest<T> request) {return getForm(url, request, DEFAULT_TIMEOUT);}public static <T extends HttpCommonResponse> T getForm(String url, HttpCommonRequest<T> request, int timeout) {return executeFormRequest(url, request, HttpMethod.GET, timeout);}// ==================================== endregion ====================================// ==================================== region 无返回值方法 ====================================public static void post(String url) {post(url, DEFAULT_TIMEOUT);}/*** 无参无返回** @param url 链接* @param timeout 超时时间*/public static void post(String url, int timeout) {executeVoidRequest(url, HttpMethod.POST, timeout);}public static void get(String url) {get(url, DEFAULT_TIMEOUT);}public static void get(String url, int timeout) {executeVoidRequest(url, HttpMethod.GET, timeout);}// ==================================== endregion ====================================// ==================================== region 核心执行方法 ====================================/*** 执行json请求** @param url 链接* @param request 入参* @param method 方法* @param timeout 超时时间* @return 自定义出参*/private static <T extends HttpCommonResponse> T executeJsonRequest(String url, HttpCommonRequest<T> request,HttpMethod method, int timeout) {validateRequest(url, request);validateTimeout(timeout);String jsonBody = JSON.toJSONString(request);logRequestStart(url, jsonBody, method);HttpRequest httpRequest = createRequest(url, method).addHeaders(request.getHeaders()).body(jsonBody);return executeAndProcess(httpRequest, jsonBody, request.getResponseClass(), timeout);}/*** 执行空请求(有返回)** @param url 链接* @param responseType 出参类型* @param method 方法* @param timeout 超时时间* @return 根据出参类型 返回出参*/private static <T extends HttpCommonResponse> T executeEmptyRequest(String url, Class<T> responseType,HttpMethod method, int timeout) {validateUrl(url);validateTimeout(timeout);logRequestStart(url, EMPTY_BODY_LOG, method);HttpRequest httpRequest = createRequest(url, method);return executeAndProcess(httpRequest, EMPTY_BODY_LOG, responseType, timeout);}/*** 执行表单提交** @param url 链接* @param request 入参* @param method 方法* @param timeout 超时时间* @return 自定义出参*/private static <T extends HttpCommonResponse> T executeFormRequest(String url, HttpCommonRequest<T> request,HttpMethod method, int timeout) {validateRequest(url, request);validateTimeout(timeout);Map<String, Object> formParams = request.getParamsFrom();logRequestStart(url, formParams, method);HttpRequest httpRequest = createRequest(url, method).addHeaders(request.getHeaders()).form(formParams);return executeAndProcess(httpRequest, formParams, request.getResponseClass(), timeout);}/*** 执行空请求(无返回)** @param url 链接* @param method 方法* @param timeout 超时时间*/private static void executeVoidRequest(String url, HttpMethod method, int timeout) {validateUrl(url);validateTimeout(timeout);logRequestStart(url, EMPTY_BODY_LOG, method);HttpRequest httpRequest = createRequest(url, method);processVoidResponse(executeRequest(httpRequest, timeout), url);}// ==================================== endregion ====================================// ==================================== region 工具方法 ====================================/*** 创建请求体** @param url 链接* @param method 方法* @return 请求体*/private static HttpRequest createRequest(String url, HttpMethod method) {validateUrl(url);return HttpMethod.GET == method ? HttpUtil.createGet(url) : HttpUtil.createPost(url);}/*** 执行请求** @param request 请求体* @param timeout 超时时间* @return 请求返回值*/private static String executeRequest(HttpRequest request, int timeout) {return request.timeout(adjustTimeout(timeout)).execute().body();}/*** 执行请求和处理返回** @param request 请求体* @param params 入参* @param responseType 出参类型* @param timeout 超时时间* @return 自定义出参*/private static <T> T executeAndProcess(HttpRequest request, Object params, Class<T> responseType, int timeout) {String response = executeRequest(request, timeout);logRequestEnd(request.getUrl(), params, response);return processResponse(response, request.getUrl(), responseType);}/*** 入参日志记录** @param url 链接* @param params 入参* @param method 方法*/private static void logRequestStart(String url, Object params, HttpMethod method) {if (log.isInfoEnabled()) {String paramStr = params instanceof Map ? JSON.toJSONString(params) : params.toString();log.info("[HTTP请求开始] 方法: [{}] URL: [{}] 参数: [{}]", method, url, paramStr);}}/*** 响应日志记录** @param url 链接* @param params 入参* @param response 响应体*/private static void logRequestEnd(String url, Object params, String response) {if (log.isInfoEnabled()) {String paramStr = params instanceof Map ? JSON.toJSONString(params) : params.toString();log.info("[HTTP请求完成] URL: [{}] 参数: [{}] 响应: [{}]", url, paramStr, response);}}/*** 解析结果** @param response 响应体* @return 统一解析体*/private static Results<JSONObject> parseResult(String response) {return JSON.parseObject(response, RESULT_TYPE_REF);}/*** 处理响应体** @param response 响应体* @param url 链接* @param responseType 出参类型* @return 出参实体类*/private static <T> T processResponse(String response, String url, Class<T> responseType) {Results<JSONObject> result = parseResult(response);validateResult(result, url);return parseResponse(result.getObj(), responseType);}/*** 处理空响应** @param response 响应体* @param url 链接*/private static void processVoidResponse(String response, String url) {Results<JSONObject> result = parseResult(response);validateResult(result, url);}/*** 解析响应** @param data 数据* @param type 出参类型* @return 空 或者 出参实体类*/private static <T> T parseResponse(JSONObject data, Class<T> type) {return data != null && type != null ? data.toJavaObject(type) : null;}/*** 调整超时时间** @param timeout 超时时间* @return 自定义超时时间 或者 最小超时时间*/private static int adjustTimeout(int timeout) {return Math.max(timeout, MIN_TIMEOUT);}// ==================================== endregion ====================================// ==================================== region 验证方法 ====================================/*** 验证请求参数** @param url 链接* @param request 入参*/private static void validateRequest(String url, Object request) {validateUrl(url);if (request == null) {throw new IllegalArgumentException("请求参数不能为空");}}/*** 验证链接** @param url 链接*/private static void validateUrl(String url) {if (url == null || url.trim().isEmpty()) {throw new IllegalArgumentException("URL不能为空");}}/*** 验证自定义超时时间 打日志** @param timeout 超时时间*/private static void validateTimeout(int timeout) {if (timeout < MIN_TIMEOUT) {log.warn("超时时间 {}ms 过小,已自动调整为最小值 {}ms", timeout, MIN_TIMEOUT);}}/*** 验证返回结果 如果有问题抛出自定义异常** @param result 返回值* @param url 链接*/private static void validateResult(Results<JSONObject> result, String url) {if (!Results.SUCCESS.equals(result.getResCode())) {log.error("接口异常 URL: {} 错误信息: {}", url, result.getMsg());throw new HttpCommonException(result.getMsg());}}// ==================================== endregion ====================================/*** 只有 GET 和 POST 方法*/public enum HttpMethod {POST,GET}// 示例用法public static void main(String[] args) {log.info("第一个请求 post 返回正常参数 ==============");GetUserDto getUserDto = new GetUserDto().setUserId("007");Map<String, String> paramsMap = getUserDto.getParamsMap();log.info("paramsMap = {}", paramsMap);GetUserVO getUserVO = HttpUtils.post("http://localhost:8080/api/getUser", getUserDto);log.info("getUserVO = {}", getUserVO);log.info("");try {log.info("第二个请求 错误请求 404 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/getUser22", getUserDto);log.info("getUserVO = {}", getUserVO);} catch (Exception e) {log.error("第二个请求 错误", e);}log.info("");try {log.info("第三个请求 错误请求 逻辑错误 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/error", getUserDto);log.info("getUserVO = {}", getUserVO);} catch (HttpCommonException e) {log.error("第三个请求 错误", e);}log.info("");log.info("第四个请求 get 返回 null ==============");getUserDto = new GetUserDto().setUserId("001");paramsMap = getUserDto.getParamsMap();log.info("paramsMap = {}", paramsMap);getUserVO = HttpUtils.post("http://localhost:8080/api/getUser", getUserDto);log.info("getUserVO = {}", getUserVO);log.info("");log.info("第五个请求 post 无入参 有出参 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/getUser2", GetUserVO.class);log.info("getUserVO = {}", getUserVO);log.info("");log.info("第六个请求 post 无入参 无出参 ==============");HttpUtils.post("http://localhost:8080/api/getUser2");log.info("");log.info("第七个请求 post 文件上传 文件上传参数不能为空 ==============");File file = new File("D:\\project\\test\\src\\main\\resources\\static\\test.png");UploadFilesDto UploadFilesDto = new UploadFilesDto().setUserId("626").setFile(file);Map<String, Object> paramsFrom = UploadFilesDto.getParamsFrom();log.info("paramsMap = {}", paramsFrom);UploadFilesVo updateVo = HttpUtils.postForm("http://localhost:8080/api/getFile", UploadFilesDto);log.info("updateVo = {}", updateVo);}
}
自定义报错:HttpCommonException
package com.example.test.exception;public class HttpCommonException extends RuntimeException{public HttpCommonException() {super();}public HttpCommonException(String s) {super(s);}public HttpCommonException(String message, Throwable cause) {super(message, cause);}public HttpCommonException(Throwable cause) {super(cause);}
}
测试
四个实体类:
两个入参:GetUserDto、UploadFilesDto
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Accessors(chain = true)
public class GetUserDto extends HttpCommonRequest<GetUserVO> {/*** 其他数据:用户ID*/@NotBlank(message = "用户ID 不能为空")private String userId;@Overridepublic Class<GetUserVO> getResponseClass() {return GetUserVO.class;}@Overrideprotected void setUserParams(Map<String, Object> params) throws IllegalAccessException {setUserParam(params, this);}
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Accessors(chain = true)
public class UploadFilesDto extends HttpCommonRequest<UploadFilesVo> {/*** 文件*/private File file;/*** 其他数据:用户ID*/private String userId;@Overridepublic Class<UploadFilesVo> getResponseClass() {return UploadFilesVo.class;}@Overrideprotected void setUserParams(Map<String, Object> params) throws IllegalAccessException {setUserParam(params, this);}
}
两个出参:GetUserVO、UploadFilesVo
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Accessors(chain = true)
public class GetUserVO extends HttpCommonResponse {/*** 用户名*/private String userName;/*** 年龄*/private String age;
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Accessors(chain = true)
public class UploadFilesVo extends HttpCommonResponse {/*** 文件名称*/private String fileName;/*** 原始文件名*/private String originalFilename;/*** 其他数据:用户名*/private String userName;
}
Controller
@RestController
@Slf4j
@RequestMapping("/api")
public class ApiController {@RequestMapping("/getUser")public Results<GetUserVO> getUser(@RequestBody @Validated GetUserDto dto) {GetUserVO getUserVO = null;if ("007".equals(dto.getUserId())) {getUserVO = new GetUserVO().setUserName("詹姆斯·邦德").setAge("10086");}return Results.success(getUserVO);}@RequestMapping("/getUser2")public Results<GetUserVO> getUser2() {GetUserVO getUserVO = new GetUserVO().setUserName("666").setAge("777");return Results.success(getUserVO);}@RequestMapping("/error")public Results error() {return Results.failed("这里没有逻辑,反正就是失败了");}@RequestMapping("/getFile")public Results<UploadFilesVo> getUser(MultipartFile file, String userId) {UploadFilesVo uploadFilesVo = new UploadFilesVo();if ("626".equals(userId)) {String name = file.getName();String originalFilename = file.getOriginalFilename();uploadFilesVo.setUserName("史迪仔").setFileName(name).setOriginalFilename(originalFilename);}return Results.success(uploadFilesVo);}
}
测试数据:
public static void main(String[] args) {log.info("第一个请求 post 返回正常参数 ==============");GetUserDto getUserDto = new GetUserDto().setUserId("007");Map<String, String> paramsMap = getUserDto.getParamsMap();log.info("paramsMap = {}", paramsMap);GetUserVO getUserVO = HttpUtils.post("http://localhost:8080/api/getUser", getUserDto);log.info("getUserVO = {}", getUserVO);log.info("");try {log.info("第二个请求 错误请求 404 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/getUser22", getUserDto);log.info("getUserVO = {}", getUserVO);} catch (Exception e) {log.error("第二个请求 错误", e);}log.info("");try {log.info("第三个请求 错误请求 逻辑错误 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/error", getUserDto);log.info("getUserVO = {}", getUserVO);} catch (HttpCommonException e) {log.error("第三个请求 错误", e);}log.info("");log.info("第四个请求 get 返回 null ==============");getUserDto = new GetUserDto().setUserId("001");paramsMap = getUserDto.getParamsMap();log.info("paramsMap = {}", paramsMap);getUserVO = HttpUtils.post("http://localhost:8080/api/getUser", getUserDto);log.info("getUserVO = {}", getUserVO);log.info("");log.info("第五个请求 post 无入参 有出参 ==============");getUserVO = HttpUtils.post("http://localhost:8080/api/getUser2", GetUserVO.class);log.info("getUserVO = {}", getUserVO);log.info("");log.info("第六个请求 post 无入参 无出参 ==============");HttpUtils.post("http://localhost:8080/api/getUser2");log.info("");log.info("第七个请求 post 文件上传 文件上传参数不能为空 ==============");File file = new File("D:\\project\\test\\src\\main\\resources\\static\\test.png");UploadFilesDto UploadFilesDto = new UploadFilesDto().setUserId("626").setFile(file);Map<String, Object> paramsFrom = UploadFilesDto.getParamsFrom();log.info("paramsMap = {}", paramsFrom);UploadFilesVo updateVo = HttpUtils.postForm("http://localhost:8080/api/getFile", UploadFilesDto);log.info("updateVo = {}", updateVo);}
测试结果:
11:31:20.928 [main] INFO com.example.test.utils.HttpUtils - 第一个请求 post 返回正常参数 ==============
11:31:20.992 [main] INFO com.example.test.utils.HttpUtils - paramsMap = {userId=007, timestamp=1747193480}
11:31:21.126 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getUser] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}]
11:31:21.545 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/getUser] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}] 响应: [{"resCode":"200","msg":"成功","obj":{"timestamp":1747193481,"userName":"詹姆斯·邦德","age":"10086"}}]
11:31:21.592 [main] INFO com.example.test.utils.HttpUtils - getUserVO = GetUserVO(super=HttpCommonResponse(timestamp=1747193481), userName=詹姆斯·邦德, age=10086)
11:31:21.592 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.592 [main] INFO com.example.test.utils.HttpUtils - 第二个请求 错误请求 404 ==============
11:31:21.593 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getUser22] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}]
11:31:21.631 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/getUser22] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}] 响应: [<html><body><h1>Whitelabel Error Page</h1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p><div id='created'>Wed May 14 11:31:21 CST 2025</div><div>There was an unexpected error (type=Not Found, status=404).</div></body></html>]
11:31:21.634 [main] ERROR com.example.test.utils.HttpUtils - 第二个请求 错误
com.alibaba.fastjson.JSONException: syntax error,except start with { or [,but actually start with errorat com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:684)at com.alibaba.fastjson.JSON.parseObject(JSON.java:396)at com.alibaba.fastjson.JSON.parseObject(JSON.java:364)at com.alibaba.fastjson.JSON.parseObject(JSON.java:278)at com.example.test.utils.HttpUtils.parseResult(HttpUtils.java:303)at com.example.test.utils.HttpUtils.processResponse(HttpUtils.java:315)at com.example.test.utils.HttpUtils.executeAndProcess(HttpUtils.java:264)at com.example.test.utils.HttpUtils.executeJsonRequest(HttpUtils.java:162)at com.example.test.utils.HttpUtils.post(HttpUtils.java:54)at com.example.test.utils.HttpUtils.post(HttpUtils.java:43)at com.example.test.utils.HttpUtils.main(HttpUtils.java:425)
11:31:21.635 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.635 [main] INFO com.example.test.utils.HttpUtils - 第三个请求 错误请求 逻辑错误 ==============
11:31:21.635 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/error] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}]
11:31:21.642 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/error] 参数: [{"paramsFrom":{"timestamp":"1747193480","userId":"007"},"paramsMap":{"userId":"007","timestamp":"1747193480"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193480,"userId":"007"}] 响应: [{"resCode":"500","msg":"这里没有逻辑,反正就是失败了","obj":null}]
11:31:21.642 [main] ERROR com.example.test.utils.HttpUtils - 接口异常 URL: http://localhost:8080/api/error 错误信息: 这里没有逻辑,反正就是失败了
11:31:21.642 [main] ERROR com.example.test.utils.HttpUtils - 第三个请求 错误
com.example.test.exception.HttpCommonException: 这里没有逻辑,反正就是失败了at com.example.test.utils.HttpUtils.validateResult(HttpUtils.java:399)at com.example.test.utils.HttpUtils.processResponse(HttpUtils.java:316)at com.example.test.utils.HttpUtils.executeAndProcess(HttpUtils.java:264)at com.example.test.utils.HttpUtils.executeJsonRequest(HttpUtils.java:162)at com.example.test.utils.HttpUtils.post(HttpUtils.java:54)at com.example.test.utils.HttpUtils.post(HttpUtils.java:43)at com.example.test.utils.HttpUtils.main(HttpUtils.java:434)
11:31:21.643 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.643 [main] INFO com.example.test.utils.HttpUtils - 第四个请求 get 返回 null ==============
11:31:21.643 [main] INFO com.example.test.utils.HttpUtils - paramsMap = {userId=001, timestamp=1747193481}
11:31:21.643 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getUser] 参数: [{"paramsFrom":{"timestamp":"1747193481","userId":"001"},"paramsMap":{"userId":"001","timestamp":"1747193481"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193481,"userId":"001"}]
11:31:21.654 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/getUser] 参数: [{"paramsFrom":{"timestamp":"1747193481","userId":"001"},"paramsMap":{"userId":"001","timestamp":"1747193481"},"responseClass":"com.example.test.pojo.vo.GetUserVO","timestamp":1747193481,"userId":"001"}] 响应: [{"resCode":"200","msg":"成功","obj":null}]
11:31:21.654 [main] INFO com.example.test.utils.HttpUtils - getUserVO = null
11:31:21.654 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.654 [main] INFO com.example.test.utils.HttpUtils - 第五个请求 post 无入参 有出参 ==============
11:31:21.655 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getUser2] 参数: [{}]
11:31:21.669 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/getUser2] 参数: [{}] 响应: [{"resCode":"200","msg":"成功","obj":{"timestamp":1747193481,"userName":"666","age":"777"}}]
11:31:21.669 [main] INFO com.example.test.utils.HttpUtils - getUserVO = GetUserVO(super=HttpCommonResponse(timestamp=1747193481), userName=666, age=777)
11:31:21.669 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.669 [main] INFO com.example.test.utils.HttpUtils - 第六个请求 post 无入参 无出参 ==============
11:31:21.669 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getUser2] 参数: [{}]
11:31:21.676 [main] INFO com.example.test.utils.HttpUtils -
11:31:21.676 [main] INFO com.example.test.utils.HttpUtils - 第七个请求 post 文件上传 文件上传参数不能为空 ==============
11:31:21.676 [main] INFO com.example.test.utils.HttpUtils - paramsMap = {file=D:\project\test\src\main\resources\static\test.png, timestamp=1747193481, userId=626}
11:31:21.676 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求开始] 方法: [POST] URL: [http://localhost:8080/api/getFile] 参数: [{"file":"D:\\project\\test\\src\\main\\resources\\static\\test.png","timestamp":"1747193481","userId":"626"}]
11:31:21.802 [main] INFO com.example.test.utils.HttpUtils - [HTTP请求完成] URL: [http://localhost:8080/api/getFile] 参数: [{"file":"D:\\project\\test\\src\\main\\resources\\static\\test.png","timestamp":"1747193481","userId":"626"}] 响应: [{"resCode":"200","msg":"成功","obj":{"timestamp":1747193481,"fileName":"file","originalFilename":"test.png","userName":"史迪仔"}}]
11:31:21.805 [main] INFO com.example.test.utils.HttpUtils - updateVo = UploadFilesVo(super=HttpCommonResponse(timestamp=1747193481), fileName=file, originalFilename=test.png, userName=史迪仔)进程已结束,退出代码0