执行处理器 ActionExecuteHandler
前置参考:
偏内部使用,一般不定制
1、接口声明
package org.noear.solon.core.handle;
import org.noear.solon.core.wrap.MethodWrap;
public interface ActionExecuteHandler {
/**
* 是否匹配
*
* @param ctx 请求上下文
* @param mime 内容类型
*/
boolean matched(Context ctx, String mime);
/**
* 参数分析
*
* @param ctx 请求上下文
* @param target 控制器
* @param mWrap 函数包装器
*/
Object[] resolveArguments(Context ctx, Object target, MethodWrap mWrap) throws Throwable;
/**
* 执行
*
* @param ctx 请求上下文
* @param target 控制器
* @param mWrap 函数包装器
* @deprecated 3.4
*/
@Deprecated
Object executeHandle(Context ctx, Object target, MethodWrap mWrap) throws Throwable;
}
2、定制参考1
public class Fastjson2ActionExecutor extends ActionExecuteHandlerDefault {
private final Fastjson2StringSerializer serializer = new Fastjson2StringSerializer();
public Fastjson2ActionExecutor() {
serializer.getDeserializeConfig().config();
serializer.getDeserializeConfig().config(JSONReader.Feature.ErrorOnEnumNotMatch);
}
/**
* 获取序列化接口
*/
public Fastjson2StringSerializer getSerializer() {
return serializer;
}
/**
* 反序列化配置
*/
public JSONReader.Context config() {
return getSerializer().getDeserializeConfig();
}
/**
* 是否匹配
*
* @param ctx 请求上下文
* @param mime 内容类型
*/
@Override
public boolean matched(Context ctx, String mime) {
return serializer.matched(ctx, mime);
}
/**
* 转换 body
*
* @param ctx 请求上下文
* @param mWrap 函数包装器
*/
@Override
protected Object changeBody(Context ctx, MethodWrap mWrap) throws Exception {
return serializer.deserializeFromBody(ctx);
}
/**
* 转换 value
*
* @param ctx 请求上下文
* @param p 参数包装器
* @param pi 参数序位
* @param pt 参数类型
* @param bodyRef 主体对象
*/
@Override
protected Object changeValue(Context ctx, ParamWrap p, int pi, Class<?> pt, LazyReference bodyRef) throws Throwable {
if (p.spec().isRequiredPath() || p.spec().isRequiredCookie() || p.spec().isRequiredHeader()) {
//如果是 path、cookie, header 变量
return super.changeValue(ctx, p, pi, pt, bodyRef);
}
if (p.spec().isRequiredBody() == false && ctx.paramMap().containsKey(p.spec().getName())) {
//可能是 path、queryString 变量
return super.changeValue(ctx, p, pi, pt, bodyRef);
}
Object bodyObj = bodyRef.get();
if (bodyObj == null) {
return super.changeValue(ctx, p, pi, pt, bodyRef);
}
if (bodyObj instanceof JSONObject) {
JSONObject tmp = (JSONObject) bodyObj;
if (p.spec().isRequiredBody() == false) {
//
//如果没有 body 要求;尝试找按属性找
//
if (tmp.containsKey(p.spec().getName())) {
//支持泛型的转换
if (p.spec().isGenericType()) {
return tmp.getObject(p.spec().getName(), p.getGenericType());
} else {
return tmp.getObject(p.spec().getName(), pt);
}
}
}
//尝试 body 转换
if (pt.isPrimitive() || pt.getTypeName().startsWith("java.lang.")) {
return super.changeValue(ctx, p, pi, pt, bodyRef);
} else {
if (List.class.isAssignableFrom(pt)) {
return null;
}
if (pt.isArray()) {
return null;
}
//支持泛型的转换 如:Map<T>
if (p.spec().isGenericType()) {
return tmp.to(p.getGenericType());
} else {
return tmp.to(pt);
}
}
}
if (bodyObj instanceof JSONArray) {
JSONArray tmp = (JSONArray) bodyObj;
//如果参数是非集合类型
if (!Collection.class.isAssignableFrom(pt)) {
return null;
}
//集合类型转换
if (p.spec().isGenericType()) {
//转换带泛型的集合
return tmp.to(p.getGenericType());
} else {
//不仅可以转换为List 还可以转换成Set
return tmp.to(pt);
}
}
return bodyObj;
}
}
3、定制参考2
public class ActionExecuteHandlerDefault implements ActionExecuteHandler {
/**
* 是否匹配
*
* @param ctx 请求上下文
* @param mime 内容类型
*/
@Override
public boolean matched(Context ctx, String mime) {
return true;
}
/**
* 执行
*
* @param ctx 请求上下文
* @param target 控制器
* @param mWrap 函数包装器
*/
@Override
public Object executeHandle(Context ctx, Object target, MethodWrap mWrap) throws Throwable {
Object[] args = resolveArguments(ctx, target, mWrap);
return mWrap.invokeByAspect(target, args);
}
/**
* 执行
*
* @param ctx 请求上下文
* @param target 控制器
* @param mWrap 函数包装器
*/
@Override
public Object[] resolveArguments(Context ctx, Object target, MethodWrap mWrap) throws Throwable {
ParamWrap[] pSet = mWrap.getParamWraps();
Object[] args = new Object[pSet.length];
//懒引用
LazyReference bodyRef = new LazyReference(() -> changeBody(ctx, mWrap));
//p 参数
//pt 参数原类型
for (int i = 0, len = pSet.length; i < len; i++) {
ParamWrap p = pSet[i];
args[i] = resolveArgumentDo(ctx, target, mWrap, p, i, bodyRef);
}
return args;
}
/**
* 参数分析
*
* @param ctx 请求上下文
* @param target 控制器
* @param mWrap 函数包装器
* @param pWrap 参数包装器
* @param pIndex 参数序位
* @param bodyRef 主体引用
*/
protected Object resolveArgumentDo(Context ctx, Object target, MethodWrap mWrap, ParamWrap pWrap, int pIndex, LazyReference bodyRef) throws Throwable {
Class<?> pt = pWrap.getType();
if (Context.class.isAssignableFrom(pt)) {
//如果是 Context 类型,直接加入参数
//
return ctx;
} else if (ModelAndView.class.isAssignableFrom(pt)) {
//如果是 ModelAndView 类型,直接加入参数
//
return new ModelAndView();
} else if (Locale.class.isAssignableFrom(pt)) {
//如果是 Locale 类型,直接加入参数
//
return ctx.getLocale();
} else if (UploadedFile.class == pt) {
//如果是 UploadedFile
//
return ctx.file(pWrap.spec().getName());
} else if (UploadedFile[].class == pt) {
//如果是 UploadedFile
//
return ctx.fileValues(pWrap.spec().getName());
}
/// /////////////
Object tv = null;
if (Object.class != pt) { //object 是所在基类,不能用它拉取
tv = ctx.pull(pt);
}
if (tv == null) {
if (pWrap.spec().isRequiredBody()) {
//需要 body 数据
if (String.class.equals(pt)) {
tv = ctx.bodyNew();
} else if (InputStream.class.equals(pt)) {
tv = ctx.bodyAsStream();
} else if (Map.class.equals(pt) && bodyRef.get() instanceof MultiMap) {
tv = ((MultiMap) bodyRef.get()).toValueMap();
}
}
}
if (tv == null) {
if (Solon.app() != null) {
ActionArgumentResolver argumentResolver = Solon.app().chainManager().getArgumentResolver(ctx, pWrap);
if (argumentResolver != null) {
tv = argumentResolver.resolveArgument(ctx, target, mWrap, pWrap, pIndex, bodyRef);
}
}
}
if (tv == null) {
//尝试数据转换
try {
tv = changeValue(ctx, pWrap, pIndex, pt, bodyRef);
} catch (ConstructionException e) {
throw e;
} catch (Exception e) {
String methodFullName = mWrap.getDeclaringClz().getName() + "::" + mWrap.getName() + "@" + pWrap.spec().getName();
throw new StatusException("Action parameter change failed: " + methodFullName, e, 400);
}
}
if (tv == null) {
//
// 如果是基类类型(int,long...),则抛出异常
//
if (pt.isPrimitive()) {
//如果是基本类型,则为给个默认值
//
if (pt == short.class) {
tv = (short) 0;
} else if (pt == int.class) {
tv = 0;
} else if (pt == long.class) {
tv = 0L;
} else if (pt == double.class) {
tv = 0d;
} else if (pt == float.class) {
tv = 0f;
} else if (pt == boolean.class) {
tv = false;
} else {
//
//其它类型不支持
//
throw new IllegalArgumentException("Please enter a valid parameter @" + pWrap.spec().getName());
}
}
}
if (tv == null) {
if (pWrap.spec().isRequiredInput()) {
throw new StatusException(pWrap.spec().getRequiredHint(), 400);
}
}
return tv;
}
/**
* 尝试将body转换为特定对象
*
* @param ctx 请求上下文
* @param mWrap 函数包装器
*/
protected Object changeBody(Context ctx, MethodWrap mWrap) throws Exception {
return ctx.paramMap();
}
/**
* 尝试将值按类型转换
*
* @param ctx 请求上下文
* @param p 参数包装
* @param pi 参数序位
* @param pt 参数类型
* @param bodyRef 主体对象
*/
protected Object changeValue(Context ctx, ParamWrap p, int pi, Class<?> pt, LazyReference bodyRef) throws Throwable {
String pn = p.spec().getName(); //参数名
String pv = p.spec().getValue(ctx); //参数值
Object tv = null; //目标值
if (pv == null) {
pv = p.spec().getDefaultValue();
}
if (pv == null) {
//
// 没有从 ctx.param 直接找到值
//
if (UploadedFile.class == pt) {
//1.如果是 UploadedFile 类型
tv = ctx.file(pn);
} else if (UploadedFile[].class == pt) {
//2.如果是 UploadedFile[] 类型
tv = ctx.fileValues(pn);
} else {
//$name 的变量,从attr里找
if (pn.startsWith("$")) {
tv = ctx.attr(pn);
} else {
if (pt.getName().startsWith("java.") || pt.isArray() || pt.isPrimitive() || pt.isEnum()) {
//如果是java基础类型,则为null(后面统一地 isPrimitive 做处理)
//
tv = null;
} else {
//尝试转为实体
tv = changeEntityDo(ctx, p, pn, pt);
}
}
}
} else {
//如果拿到了具体的参数值,则开始转换
tv = changeValueDo(ctx, p, pn, pt, pv);
}
return tv;
}
/**
* 尝试将值转换为目标值
*
* @param ctx 请求上下文
* @param p 参数包装
* @param name 数据名字
* @param type 数据类型
*/
protected Object changeValueDo(Context ctx, ParamWrap p, String name, Class<?> type, String value) {
return ConvertUtil.to(p.spec(), value, ctx);
}
/**
* 尝试将值转换为目标实体
*
* @param ctx 请求上下文
* @param p 参数包装
* @param name 数据名字
* @param type 数据类型
*/
protected Object changeEntityDo(Context ctx, ParamWrap p, String name, Class<?> type) throws Exception {
ClassWrap clzW = ClassWrap.get(type);
MultiMap<String> map = ctx.paramMap();
return clzW.newBy(map::get, ctx);
}
}