
org.ssssssss.magicapi.controller.RequestHandler Maven / Gradle / Ivy
package org.ssssssss.magicapi.controller;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.ssssssss.magicapi.config.MagicConfiguration;
import org.ssssssss.magicapi.config.MappingHandlerMapping;
import org.ssssssss.magicapi.config.Valid;
import org.ssssssss.magicapi.config.WebSocketSessionManager;
import org.ssssssss.magicapi.context.CookieContext;
import org.ssssssss.magicapi.context.RequestContext;
import org.ssssssss.magicapi.context.SessionContext;
import org.ssssssss.magicapi.exception.ValidateException;
import org.ssssssss.magicapi.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.logging.MagicLoggerContext;
import org.ssssssss.magicapi.model.*;
import org.ssssssss.magicapi.modules.ResponseModule;
import org.ssssssss.magicapi.provider.ResultProvider;
import org.ssssssss.magicapi.script.ScriptManager;
import org.ssssssss.magicapi.utils.PatternUtils;
import org.ssssssss.script.MagicScriptContext;
import org.ssssssss.script.MagicScriptDebugContext;
import org.ssssssss.script.exception.MagicScriptAssertException;
import org.ssssssss.script.exception.MagicScriptException;
import org.ssssssss.script.functions.ObjectConvertExtension;
import org.ssssssss.script.parsing.Span;
import org.ssssssss.script.parsing.ast.literal.BooleanLiteral;
import org.ssssssss.script.reflection.JavaInvoker;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import static org.springframework.http.HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS;
import static org.ssssssss.magicapi.config.MessageType.BREAKPOINT;
import static org.ssssssss.magicapi.model.Constants.*;
public class RequestHandler extends MagicController {
private static final Logger logger = LoggerFactory.getLogger(RequestHandler.class);
private final ResultProvider resultProvider;
private static final Map EMPTY_MAP = new HashMap<>();
public RequestHandler(MagicConfiguration configuration) {
super(configuration);
this.resultProvider = configuration.getResultProvider();
}
/**
* 测试入口、实际请求入口
*/
@ResponseBody
@Valid(requireLogin = false) // 无需验证是否要登录
public Object invoke(HttpServletRequest request, HttpServletResponse response,
@PathVariable(required = false) Map pathVariables,
@RequestParam(required = false) Map parameters) throws Throwable {
String sessionId = null;
boolean requestedFromTest = configuration.isEnableWeb() && (sessionId = request.getHeader(HEADER_REQUEST_SESSION)) != null;
RequestEntity requestEntity = new RequestEntity(request, response, requestedFromTest, parameters, pathVariables);
if (requestEntity.getApiInfo() == null) {
logger.error("{}找不到对应接口", request.getRequestURI());
return buildResult(requestEntity, API_NOT_FOUND, "接口不存在");
}
Map headers = new HashMap() {
@Override
public Object get(Object key) {
return request.getHeader(key.toString());
}
};
requestEntity.setHeaders(headers);
List paths = new ArrayList<>(requestEntity.getApiInfo().getPaths());
MappingHandlerMapping.findGroups(requestEntity.getApiInfo().getGroupId())
.stream()
.flatMap(it -> it.getPaths().stream())
.filter(it -> !paths.contains(it))
.forEach(paths::add);
Object bodyValue = readRequestBody(requestEntity.getRequest());
try {
// 验证参数
doValidate("参数", requestEntity.getApiInfo().getParameters(), parameters, PARAMETER_INVALID);
// 验证 header
doValidate("header", requestEntity.getApiInfo().getHeaders(), headers, HEADER_INVALID);
// 验证 path
doValidate("path", paths, requestEntity.getPathVariables(), PATH_VARIABLE_INVALID);
BaseDefinition requestBody = requestEntity.getApiInfo().getRequestBodyDefinition();
if (requestBody != null && requestBody.getChildren().size() > 0) {
requestBody.setName(StringUtils.defaultIfBlank(requestBody.getName(), "root"));
doValidate(VAR_NAME_REQUEST_BODY, Collections.singletonList(requestBody), new HashMap() {{
put(requestBody.getName(), bodyValue);
}}, BODY_INVALID);
}
} catch (ValidateException e) {
return resultProvider.buildResult(requestEntity, RESPONSE_CODE_INVALID, e.getMessage());
} catch (Throwable root) {
return processException(requestEntity, root);
}
MagicScriptContext context = createMagicScriptContext(requestEntity, bodyValue);
requestEntity.setMagicScriptContext(context);
RequestContext.setRequestEntity(requestEntity);
Object value;
// 执行前置拦截器
if ((value = doPreHandle(requestEntity)) != null) {
return value;
}
if (requestedFromTest) {
try {
MagicLoggerContext.SESSION.set(sessionId);
return invokeRequest(requestEntity);
} finally {
MagicLoggerContext.SESSION.remove();
WebSocketSessionManager.remove(sessionId);
}
} else {
return invokeRequest(requestEntity);
}
}
private Object buildResult(RequestEntity requestEntity, JsonCode code, Object data) {
return resultProvider.buildResult(requestEntity, code.getCode(), code.getMessage(), data);
}
private boolean doValidateBody(String comment, BaseDefinition parameter, Map parameters, JsonCode jsonCode, Class> target) {
if (!parameter.isRequired() && parameters.isEmpty()) {
return true;
}
if (parameter.isRequired() && !BooleanLiteral.isTrue(parameters.get(parameter.getName()))) {
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]为必填项", comment, parameter.getName())));
}
Object value = parameters.get(parameter.getName());
if (value != null && !target.isAssignableFrom(value.getClass())) {
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]数据类型错误", comment, parameter.getName())));
}
return false;
}
private void doValidate(String comment, List validateParameters, Map parameters, JsonCode jsonCode) {
parameters = parameters != null ? parameters : EMPTY_MAP;
for (BaseDefinition parameter : validateParameters) {
// 针对requestBody多层级的情况
if (VAR_NAME_REQUEST_BODY_VALUE_TYPE_OBJECT.equalsIgnoreCase(parameter.getDataType().getJavascriptType())) {
if (doValidateBody(comment, parameter, parameters, jsonCode, Map.class)) {
continue;
}
doValidate(VAR_NAME_REQUEST_BODY, parameter.getChildren(), (Map) parameters.get(parameter.getName()), jsonCode);
} else if (VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY.equalsIgnoreCase(parameter.getDataType().getJavascriptType())) {
if (doValidateBody(comment, parameter, parameters, jsonCode, List.class)) {
continue;
}
List list = (List) parameters.get(parameter.getName());
if (list != null) {
for (Object value : list) {
List definitions = parameter.getChildren();
doValidate(VAR_NAME_REQUEST_BODY, definitions, new HashMap() {{
put("", value);
}}, jsonCode);
}
}
} else if (StringUtils.isNotBlank(parameter.getName())) {
String requestValue = StringUtils.defaultIfBlank(Objects.toString(parameters.get(parameter.getName()), EMPTY), Objects.toString(parameter.getDefaultValue(), EMPTY));
if (StringUtils.isBlank(requestValue)) {
if (!parameter.isRequired()) {
continue;
}
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]为必填项", comment, parameter.getName())));
}
try {
Object value = convertValue(parameter.getDataType(), parameter.getName(), requestValue);
if (VALIDATE_TYPE_PATTERN.equals(parameter.getValidateType())) { // 正则验证
String expression = parameter.getExpression();
if (StringUtils.isNotBlank(expression) && !PatternUtils.match(Objects.toString(value, EMPTY), expression)) {
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]不满足正则表达式", comment, parameter.getName())));
}
}
parameters.put(parameter.getName(), value);
} catch (Exception e) {
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]不合法", comment, parameter.getName())));
}
}
}
// 取出表达式验证的参数
List validates = validateParameters.stream().filter(it -> VALIDATE_TYPE_EXPRESSION.equals(it.getValidateType()) && StringUtils.isNotBlank(it.getExpression())).collect(Collectors.toList());
for (BaseDefinition parameter : validates) {
MagicScriptContext context = new MagicScriptContext();
// 将其他参数也放置脚本中,以实现“依赖”的情况
context.putMapIntoContext(parameters);
Object value = parameters.get(parameter.getName());
if (value != null) {
// 设置自身变量
context.set(EXPRESSION_DEFAULT_VAR_NAME, value);
if (!BooleanLiteral.isTrue(ScriptManager.executeExpression(parameter.getExpression(), context))) {
throw new ValidateException(jsonCode, StringUtils.defaultIfBlank(parameter.getError(), String.format("%s[%s]不满足表达式", comment, parameter.getName())));
}
}
}
}
/**
* 转换参数类型
*/
private Object convertValue(DataType dataType, String name, String value) {
if (dataType == null) {
return value;
}
try {
if (dataType.isNumber()) {
BigDecimal decimal = ObjectConvertExtension.asDecimal(value, null);
if (decimal == null) {
throw new IllegalArgumentException();
}
return dataType.getInvoker().invoke0(decimal, null);
} else {
JavaInvoker invoker = dataType.getInvoker();
if (invoker != null) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy