DispatcherController 功能完善与接口文档编写
前言
没什么动力说废话了。
今天来完善 DispatcherController
的功能,然后写写接口文档。
日程
- 早上:本来只有早八,但是早上摸鱼了,罪过罪过。
- 下午:把
DispatcherController
完善得比较充足了(我认为的哈)。 - 晚上 10 点:现在的时间,
deepseek
卡爆了,先来写写 blog。 - 晚上 10 点半:摆烂了,开摆!
学习内容
省流
DispatcherController
完善
1. DispatcherController
完善(有点水了)
主要是兼容各种询问参数,注解如下:
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatPathVariable {
String value() default "";
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatRequestBody {
boolean required() default true;
}
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatRequestParam {
String value() default ""; // 参数名
boolean required() default true; // 是否必须
String defaultValue() default ""; // 默认值
}
1)路径参数 KatPathVariable
private Object resolvePathVariable(KatPathVariable annotation,
java.lang.reflect.Parameter parameter,
Class<?> paramType,
HttpServletRequest req) {
Map<String, String> pathVariables = (Map<String, String>) req.getAttribute("pathVariables");
// 获取参数名,优先使用注解值,其次使用参数名
String paramName = annotation.value().isEmpty()
? parameter.getName()
: annotation.value();
String value = pathVariables.get(paramName);
if (value == null) {
throw new IllegalArgumentException("Path variable '" + paramName + "' not found");
}
try {
// 使用 TypeConverter 进行类型转换
return TypeConverter.convertValue(value, paramType);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
String.format("Failed to convert path variable '%s' value '%s' to type %s",
paramName, value, paramType.getName()),
e
);
}
}
TypeConverter
是从原来 SimpleMapper
类中拆出来的方法:
public static Object convertValue(Object value, Class<?> targetType) {
if (value == null) {
if (targetType == Number.class) { // Number类型检查
return 0;
}
return null;
}
if (targetType.isInstance(value)) {
return value;
}
// 数值类型转换
if (value instanceof Number number) {
if (targetType == Double.class || targetType == double.class) {
return number.doubleValue();
}
if (targetType == Float.class || targetType == float.class) {
return number.floatValue();
}
if (targetType == Integer.class || targetType == int.class) {
return number.intValue();
}
// 其他数值类型省略...
}
// 字符串到其他类型的转换
if (value instanceof String strValue) {
try {
if (targetType == Integer.class || targetType == int.class) {
return Integer.parseInt(strValue);
}
if (targetType == Long.class || targetType == long.class) {
return Long.parseLong(strValue);
}
// 其他类型省略...
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Failed to convert string '" + strValue +
"' to type " + targetType.getName(), e);
}
}
// 日期类型转换
if (value instanceof java.sql.Date sqlDate) {
if (targetType == LocalDate.class) {
return sqlDate.toLocalDate();
}
if (targetType == LocalDateTime.class) {
return sqlDate.toLocalDate().atStartOfDay();
}
}
// 布尔类型转换、时间戳转换等省略...
log.warn("Cannot convert value '{}' of type {} to target type {}",
value, value.getClass().getName(), targetType.getName());
throw new IllegalArgumentException("Cannot convert value '" + value +
"' of type " + value.getClass().getName() +
" to target type " + targetType.getName());
}
2)询问参数 KatRequestParam
也是差不多的逻辑:
private Object resolveRequestParam(KatRequestParam annotation,
java.lang.reflect.Parameter parameter,
Class<?> paramType,
HttpServletRequest req) {
// 获取参数名,优先使用注解值,其次使用参数名
String paramName = annotation.value().isEmpty()
? parameter.getName()
: annotation.value();
String paramValue = req.getParameter(paramName);
// 处理参数缺失情况
if (paramValue == null || paramValue.isEmpty()) {
if (annotation.required()) {
throw new IllegalArgumentException("Required request parameter '" + paramName + "' is not present");
}
if (!annotation.defaultValue().isEmpty()) {
paramValue = annotation.defaultValue();
} else {
return null; // 非必需且无默认值,返回null
}
}
try {
// 使用 TypeConverter 进行类型转换
return TypeConverter.convertValue(paramValue, paramType);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
String.format("Failed to convert request parameter '%s' value '%s' to type %s",
paramName, paramValue, paramType.getName()),
e
);
}
}
3)请求体参数 KatRequestBody
private Object resolveRequestBody(Class<?> paramType,
HttpServletRequest req,
KatRequestBody annotation) throws IOException {
// 检查请求体是否为空
if (req.getContentLength() == 0) {
if (annotation.required()) {
throw new IllegalArgumentException("Required request body is missing");
}
return null;
}
try {
String requestBody = ServletUtils.getRequestBody(req);
// 如果是String类型,直接返回
if (paramType.equals(String.class)) {
return requestBody;
}
// 构建对象
return JsonUtils.parseJson(requestBody, paramType); //这里借助了Jakson工具
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse request body", e);
}
}
4)对应代理方法的装配也有比较大的改动
private Object invokeHandlerMethod(HandlerMethod handler,
HttpServletRequest req,
HttpServletResponse resp) throws Exception {
Method method = handler.method();
Object[] args = new Object[method.getParameterCount()];
Class<?>[] paramTypes = method.getParameterTypes();
Annotation[][] paramAnnotations = method.getParameterAnnotations(); //一个
for (int i = 0; i < paramTypes.length; i++) {
// 处理 @KatPathVariable 注解参数
KatPathVariable pathVar = findAnnotation(paramAnnotations[i],KatPathVariable.class);
if (pathVar != null) {
args[i] = resolvePathVariable(pathVar, method.getParameters()[i],
paramTypes[i], req);
continue;
}
// 处理 @KatRequestParam 注解参数
KatRequestParam requestParam = findAnnotation(paramAnnotations[i], KatRequestParam.class);
if (requestParam != null) {
args[i] = resolveRequestParam(requestParam,method.getParameters()[i], paramTypes[i], req);
continue;
}
// 处理 @KatRequestBody 注解参数
KatRequestBody requestBody = findAnnotation(paramAnnotations[i], KatRequestBody.class);
if (requestBody != null) {
args[i] = resolveRequestBody(paramTypes[i], req, requestBody);
continue;
}
// 处理 HttpServletRequest/HttpServletResponse 参数
if (paramTypes[i].equals(HttpServletRequest.class)) {
args[i] = req;
} else if (paramTypes[i].equals(HttpServletResponse.class)) {
args[i] = resp;
}
}
return method.invoke(handler.controllerInstance(), args);
}
结语
不知不觉,不知不觉,已经 5 月 9 号了。
项目只剩下 12 天了,我真的把握好时间了吗?