如何使用自定义过滤器记录表单的访问次数

栏目:云苍穹知识作者:金蝶来源:金蝶云社区发布:2024-09-23浏览:1

如何使用自定义过滤器记录表单的访问次数

关键词:自定义过滤器、rabbitmq、访问次数

一、需求

        用户期望可以看到某些应用的运营情况,实时统计出某些应用下的某些表单有多少人次访问了。通过这些数据列表或者图,估算出应用产生的业务价值。

二、思路与方案

  1. 首先要找到在哪里可以拦截每次请求,可以在各种action请求之前,即actionDispatcher过滤器之前增加过滤器。又因为自定义过滤器中要用orm去存数据,所以必须在loginFilter过滤器对上下文信息初始化完成之后去增加过滤器。

  2. 另外,记录各个表单的访问量,不应该影响实际前端请求的响应速度,这时需要通过rabbitmq异步累加访问量。同时mq队列的先进先出原理保证了并发访问同一个表单时累加数据的准确性。当前端请求量过大时,队列中等待的消息会很大,这时要想更及时的显示各个业务表单的访问量时,可以按访问的应用增加队列。(增加队列根据实际需求增加

三、实现过程

1、开发自定义过滤器

(1)在resources包下增加myFilter.xml的文件

<web-app>
   <filter>
       <filter-name>ShowVisitCountFilter</filter-name>
       <filter-class>kd.bos.filter.ShowVisitCountFilter</filter-class>
       <filter-order>50001</filter-order>
       <filter-mapping>
           <url-pattern>*</url-pattern>
       </filter-mapping>
   </filter>
</web-app>

(2)开发自定义过滤器类

public class ShowVisitCountFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);//filter.ShowVisitCountFilter
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        Map<String, String[]> parameterMap = httpRequest.getParameterMap();
        String[] appids = parameterMap.get("appId");//应用标识
        String[] fs = parameterMap.get("f");//表单标识
        if (appids != null && appids.length > 0) {
            if (appids[0].equals("bos")) {//过滤掉平台的请求
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
            if (fs != null && fs.length > 0) {
                MessagePublisher mp = null;
                //简单模拟发出多次请求
                for (int i = 0; i < 100; i++) {
//                    if (i > 4) {
//                        fs[0] = String.valueOf(i);
//                        parameterMap.put("f", fs);
//                    }
                    try {//mq生产消息
                        mp = MQFactory.get().createSimplePublisher("kdec_showcloud", "erkai_queue");
                        mp.publish(parameterMap);
                    } finally {
                        mp.close();
                    }
                }

            }
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

2、通过rabbitmq异步累加访问量

(1)由于轻量级环境的MQ是使用内存模拟出来的,因此需要重新安装rabbitmq后,在启动参数中添加如下信息

特别注意,如果配置填写错误,会报错rabbitmq config error: null。

cosmic.set("lightweightdeploy","fasle");//非轻量级模式启动
String mqHost = "127.0.0.1";
        String mqPort = "18001";  // 默认5672
        String webPort = "5672";  // 默认5672
        String mqUser = "admin";//账号
        String mqPwd = "admin";//密码
        String mqVhost = "ierp";//
        StringBuilder builder = new StringBuilder();
        builder.append("type=rabbitmq").append("\n")
                .append("host=").append(mqHost).append("\n")
                .append("port=").append(mqPort).append("\n")
//                .append("webport=").append(webPort).append("\n")
                .append("user=").append(mqUser).append("\n")
                .append("password=").append(mqPwd).append("\n")
                .append("vhost=").append(mqVhost);
        cosmic.set("mq.server", builder.toString());

(2)安装及配置好rabbit信息之后,在resources包下配置消息队列信息

<root>
    <region name="kdec_showcloud">
        <queue name="erkai_queue" appid="kdec_showapp">
<!--            <consumer class="kd.bos.mymq.DemoConsumer" concurrency='5'></consumer>并行量为5-->
            <consumer class="kd.bos.mymq.DemoConsumer" ></consumer>
        </queue>
    </region>
</root>

注意分应用部署模式下,当前服务节点的appids中如果包含队列信息中配置的appid才可以消费该队列的消息

(3)开发消费者类

public class DemoConsumer implements MessageConsumer {
    Log log = LogFactory.getLog(getClass());

    @Override
    public void onMessage(Object message, String messageId, boolean b, MessageAcker acker) {
        log.info("自定义DemoConsumer开始消费");
        Map<String, String[]> parameterMap = (Map<String, String[]>) message;
        String[] appids = parameterMap.get("appId");
        String[] fs = parameterMap.get("f");
        String appid = appids[0];
        String formid = fs[0];
        try {
            //入参dataObjId以应用id和表单id拼接而成,因为同时新增一条数据时,都还没有pkid
//            boolean require = MutexHelper.require("kdec_visitcount", appid + formid, "donothing", false, null);
//            if (require) {
 //               log.info("互斥锁申请成功:"+appid+formid);
                QFilter filter = new QFilter("kdec_appid", QCP.equals, appid);
                filter = filter.and(new QFilter("kdec_formid", QCP.equals, formid));
                DynamicObject visitcount = BusinessDataServiceHelper.loadSingle("kdec_visitcount", "kdec_appid,kdec_formid,kdec_count", new QFilter[]{filter});
                if (visitcount == null) {
                    visitcount = BusinessDataServiceHelper.newDynamicObject("kdec_visitcount");
                    visitcount.set("kdec_count", 1);
                    visitcount.set("kdec_appid", appid);
                    visitcount.set("kdec_formid", formid);
                } else {
                    int oldcount = visitcount.getInt("kdec_count");
                    visitcount.set("kdec_count", oldcount + 1);
                }
                Thread.sleep(1000);//测试用,可删除本行:未保存之前,其他用户发出对某个【应用+表单】的访问时,会申请互斥锁失败
                //直接存库,无业务校验
                OperationResult result = SaveServiceHelper.saveOperate("kdec_visitcount", new DynamicObject[]{visitcount}, OperateOption.create());
                if (result.isSuccess()) {
                    acker.ack(messageId);
                }
//            }else {
//                log.info("互斥锁申请失败,重发mq:"+appid+formid);
//                Thread.sleep(200);
//                acker.deny(messageId);//告诉mq重发这条消息,重新申请互斥锁,直到申请成功。
//            }
        } catch (Throwable e) {
//                acker.discard(messageId);//废弃
            // 记录废弃原因,并写业务日志
            acker.deny(messageId);//出现异常,告诉mq重发这条消息,重新申请互斥锁,直到申请成功。
            // 记录异常原因,并写业务日志
        }finally {
//            boolean isRelease = MutexHelper.release("kdec_visitcount", "donothing", appid + formid);
//            log.info("互斥锁释放状态"+String.valueOf(isRelease));
        }
    }
}

四、效果图

用户点击表单某个按钮时,访问量信息会异步记录到了如下表中。

五、开发环境版本

V6.0.6

六、参考资料

若无满意“过滤器”,轻轻松松自定义

MQ进阶:如何用MQ解决并发问题

轻量级环境加redis和rabbitmq服务的配置

如何使用自定义过滤器记录表单的访问次数

关键词:自定义过滤器、rabbitmq、访问次数一、需求 用户期望可以看到某些应用的运营情况,实时统计出某些应用下的某些表单有多少人...
点击下载文档
确认删除?
回到顶部
客服QQ
  • 客服QQ点击这里给我发消息