Solon v3.5.1

执行处理器 ActionExecuteHandler

</> markdown

前置参考:

偏内部使用,一般不定制

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);
    }
}