【仅供内部供应商使用,不提供对外解答和培训】

一、特殊名词介绍

二、背景、场景介绍

定时任务中报表计算最终会在服务器存档相关的附件,通常默认是有cpr或者frr文件的。而通过定时任务的设置是可以把定时任务的结果挂载到决策平台作为快照报表访问的。如果用户做了一些特殊定制生成的附件不包含cpr或者frr,或者因为一些特殊要求不希望展现cpr或frr,而是希望转换自己扩展的相关附件。则可通过ReportScheduleResultProvider接口实现,通过附件后缀指定新的快照展现。

三、接口介绍

ReportScheduleResultProvider.java
package com.fr.schedule.extension.report.provider;

import com.fr.schedule.extension.report.result.ScheduleResultProvider;
import com.fr.stable.fun.mark.Mutable;

/**
 *提供ScheduleResultProvider注册的接口.
 *
 * @author NIKO
 * created on 2020-11-13
 */
public interface ReportScheduleResultProvider extends Mutable {

    String MARK_STRING = "ReportScheduleResultProvider";

    int CURRENT_LEVEL = 1;

    /**
     * 提供自定义的报表结果类型,待实现.
     *
     * @return 自定义报表结果类型对象
     */
    ScheduleResultProvider customResult();
}
ScheduleResultProvider.java
package com.fr.schedule.extension.report.result;

import com.fr.schedule.extension.report.ScheduleShowType;
import com.fr.stable.web.Weblet;

import javax.servlet.http.HttpServletRequest;

/**
 * 声明自定义结果类型访问方法的接口.
 *
 * <p>
 * 通过实现该接口自定义结果的访问逻辑,注册进ScheduleResultBox从而自定义结果的访问逻辑
 * </p>
 *
 * Created by Zed on 2018/4/16.
 */
public interface ScheduleResultProvider {

    String getResultSuffix();

    Weblet accessResult(HttpServletRequest req, String path, String fileName, ScheduleShowType showType) throws Exception;
}


四、支持版本

产品线

版本

支持情况

备注

FR10.0支持

五、插件注册

plugin.xml
<extra-decision>
        <ReportScheduleResultProvider class="your class name"/>
</extra-decision>


六、原理说明

ScheduleResultBox.java
package com.fr.schedule.extension.report.result;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 注册报表结果访问类型.
 *
 * <p>
 * 注册进ScheduleResultProvider实例,根据文件后缀获取到该实例,进而通过自定义的逻辑来访问特定的结果文件
 * </p>
 *
 * Created by Zed on 2018/4/16.
 */
public class ScheduleResultBox {

    private static Map<String, ScheduleResultProvider> map = new ConcurrentHashMap<String, ScheduleResultProvider>();

    public static void register(ScheduleResultProvider provider) {
        if (!map.containsKey(provider.getResultSuffix())) {
            map.put(provider.getResultSuffix(), provider);
        }
    }

    public static ScheduleResultProvider formSuffix(String suffix) {
        if (map.containsKey(suffix)) {
            return map.get(suffix);
        }
        return null;
    }

    /**
     * 移除目标provider.
     *
     * @param provider 需要从box中移除的provider
     */
    public static void remove(ScheduleResultProvider provider){
        if(map.containsKey(provider.getResultSuffix())) {
            map.remove(provider.getResultSuffix());
        }
    }

    /**
     * 清空map中已经注册的ScheduleResultProvider.
     *
     * <p>
     * 线程不安全,仅单线程环境调用
     * </p>
     */
    public static void reset() {
        map.clear();
    }
}

ReportletResult.java
package com.fr.schedule.extension.report.result;

...

/**
 * Created by Zed on 2018/03/26.
 * 定时任务报表结果访问
 */
public class ReportletResult extends TaskResult {

    ...

    @Override
    public void accessResult(HttpServletRequest req,
                             HttpServletResponse res,
                             Map<String, Object> param) throws Exception {

        String username = (String) param.get(ScheduleConstants.USERNAME);
        String taskName = (String) param.get(ScheduleConstants.TASK_NAME);
        String resultPath = (String) param.get(ScheduleConstants.TASK_RESULT_PATH);
        String showType = (String) param.get(ScheduleConstants.SHOW_TYPE);
        // 包含有cpr、frr的目录
        String path;
        ...

        String[] files = ResourceIOUtils.list(path);
        req.setAttribute(ScheduleConstants.USERNAME, username);
        req.setAttribute(ScheduleConstants.TASK_NAME, taskName);
        req.setAttribute(ScheduleConstants.SHOW_TYPE, showType);
        req.setAttribute(ScheduleConstants.TASK_RESULT_PATH, path);
        addTaskPara(req, path);

        WebletDealWith.dealWithWeblet(req, res, this.getResultFile(req, files, path, showType));
    }

    private Weblet getResultFile(HttpServletRequest req, String[] files, String path, String showType) throws Exception {
        for (String file : files) {
            ScheduleResultProvider provider = ScheduleResultBox.formSuffix(this.getFileSuffix(file));
            if (provider != null) {
                return provider.accessResult(req, StableUtils.pathJoin(path, file), file, this.getShowType(showType));
            }
        }
        // 没有cpr、frr
        throw new ResultFileNotExistException("Fine-Schedule_Result_File_Not_Exist");
    }

    ...
}


七、特殊限制说明

由ReportletResult第26行所示 String[] files = ResourceIOUtils.list(path); 可知,最终开发者实现的接口是否会生效,取决于这里的files列表。在getResultFile方法中,会按照files的顺序逐一匹配,直到有一个ScheduleResultProvider被匹配到。而匹配规则本身又是根据文件的后缀来匹配的。这也就导致这个接口变得十分的不稳定了,如果开发者的目标是把files里面再cpr或frr之后的文件转换成自己定义的展现快照,那么就必须先保证附件里面没有这两个文件,否则就无法实现了。

所以这个接口使用时需要考虑到这个不稳定的因素!谨慎使用。

八、常用链接

入门demo地址:demo-report-schedule-result-provider

九、开源案例

免责声明:所有文档中的开源示例,均为开发者自行开发并提供。仅用于参考和学习使用,开发者和官方均无义务对开源案例所涉及的所有成果进行教学和指导。若作为商用一切后果责任由使用者自行承担。

暂无


  • No labels