magic-boot/magic-api 使用随记

朱治龙
2023-10-31 / 0 评论 / 115 阅读 / 正在检测是否收录...

magic-api 是一款非常优秀的快速开发框架,在做大屏的过程中找到的宝贝应用,可以用类JS 语法快速开发接口,能非常方便的操作数据库及处理一些复杂的业务逻辑,而 magic-boot 是基于 magic-api 开发的一款快速开发平台,提供了基本的用户鉴权、后台管理等功能。

在实际项目过程中我基于 magic-boot 做了如下事项:

1、通过Matomo的API定时同步数据至数仓做大数据分析
2、采集coolshell.cn整站数据
3、每周五定时推送企业微信消息,提醒同事写周报
更多功能待进一步挖掘……

下面是我在项目中有用到的技术点的一个记录,会在项目过程中不断更新,便于后续有其他项目用到的话,能快速查找运用。

获取 系统设置/配置中心 模块设置的配置项

import '@/configure/getBykey' as configure;
var baseURL = configure('matomo.base-url');
var authToken = configure('matomo.auth-token');

http请求数据示例

import cn.hutool.json.JSONUtil
import org.springframework.util.StringUtils
import http;
import log;
import '@/configure/getBykey' as configure;
// 从配置中心获取接口所需数据
var baseURL = configure('matomo.base-url');
var authToken = configure('matomo.auth-token');
// 组转请求URL
var reqURL = `${baseURL}?module=API&method=${method}&format=JSON&token_auth=${authToken}`;
if (!StringUtils.isEmpty(params)) {
    reqURL += `&${params}`;
}
log.info(`reqURL:${reqURL}`);
// 请求数据
var resData = http.connect(reqURL).contentType('application/json').get().getBody();
return resData;

在原基础上增加http请求出错重试机制

import cn.hutool.json.JSONUtil
import org.springframework.util.StringUtils
import cn.hutool.core.date.DateUtil
import cn.hutool.core.thread.ThreadUtil
import http
import log
import '@/configure/getBykey' as configure;
// 从配置中心获取接口所需数据
var baseURL = configure('matomo.base-url');
var authToken = configure('matomo.auth-token');
// 组转请求URL
var reqURL = `${baseURL}?module=API&method=${method}&format=JSON&token_auth=${authToken}`;
if (!StringUtils.isEmpty(params)) {
    reqURL += `&${params}`;
}
// log.info(`reqURL:${reqURL}`);
var requestStartTime = DateUtil.now();
var successFlag = ''
var exceptionContent = ''
// 请求数据
var resData = ''
// 最大重试次数
var MAX_RETRY_COUNT = 5
// 当前重试次数
var retryCount = 0;
while(retryCount < MAX_RETRY_COUNT && successFlag !== 'Y') {
    try {
        resData = http.connect(reqURL).contentType('application/json').get().getBody();
        successFlag = 'Y'
    } catch(e) {
        successFlag = 'N'
        ThreadUtil.sleep(1000);
        retryCount++
        exceptionContent = e.getMessage();
    }
}

var requestEndTime = DateUtil.now();
db.table('matomo_sync_log').insert({ 'apiMethod' : method, 'requestParams' : params, 'responseContent': resData.asString(), 'exceptionContent': exceptionContent, 'requestTime':requestStartTime, 'responseTime': requestEndTime, 'retryCount':retryCount, 'successFlag': successFlag});


return resData;

分页获取数据

在获取一些详情数据的时候,存在数据量超大的情况,一次性获取所有数据极有可能会导致数据库及应用挂掉,即便不挂掉的情况下,也会超长事件才会响应结果,所以采用分页获取还是很有必要的。

下面的代码是在实际项目中分页调用Matomo的接口获取输入然后将接口返回的数据,结构化处理后,保存到本地数据库。


import cn.hutool.json.JSONUtil
import log;
import '@/dmcfns/sendMatomoRequest' as getMatomoData;

var PAGE_SIZE=10 // 每页获取记录数,获取后批量入库
var currentPage = 0// 当前页
var needLoad = true // 继续加载数据标识,当当前页加载的内容小于PAGE_SIZE时则不再加载
while(needLoad) {
  var resData = getMatomoData('Live.getLastVisitsDetails', `period=day&date=${date}&idSite=${siteId}&doNotFetchActions=1&filter_offset=${PAGE_SIZE * currentPage}&filter_limit=${PAGE_SIZE}`)
  
  if (resData.asString().startsWith("[")) {
    var siteDatas = JSONUtil.parseArray(resData);
    var siteData = [];
    for (index, site in siteDatas) {
        var siteObj = siteDatas.getJSONObject(index);
        var visitId = siteObj.getStr("idVisit");
        var visitorId = siteObj.getStr("visitorId");
        var visitIp = siteObj.getStr("visitIp");
        var longitude = siteObj.getStr("longitude");
        var latitude = siteObj.getStr("latitude");
        var userId = siteObj.getStr("userId");
        var country = siteObj.getStr("country");
        var referrerName = siteObj.getStr("referrerName");
        var visitProps = JSONUtil.toJsonStr(siteObj);
        
        db.table('matomo_daily_visit').insert({
            date,
            siteId,
            visitId,
            visitorId,
            visitIp,
            longitude,
            latitude,
            userId,
            country,
            referrerName,
            visitProps
        })
    }
    if (siteDatas.size() === PAGE_SIZE) {
        currentPage++
    } else {
        needLoad = false
    }
  }
}

使用多数据源操作数据库

db['ZR'].table('crawler_list').insert({
    pageURL: linkURL,
    articleTitle:linkTitle
})

根据主键更新部分字段内容

var updateMap = {
    id: visitItem.id,
    ipCountry: country,
    ipProvince: province,
    ipCity: city
}
db.table('matomo_daily_visit').primary('id').update(updateMap)

修改某个字段的值

db.table("sys_user").column("isLogin", isLogin).where().eq("id",id).update()

推送消息至企业微信机器人

import http
import log
// 测试机器人
// var ROBOT_URL = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx'
// 超算云研发部2023 微信群的eHour 机器人
var ROBOT_URL = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxx'
var msg = {
    "msgtype": "text",
    "text": {
        "content": """为便于公司开展项目成本核算相关工作,请各位同事及时登录eHour系统录入本周工作工时,如有系统使用相关问题可联系 XXX,感谢配合[抱拳][抱拳]\neHour系统链接如下:http://172.18.3.xxx/""",
         "mentioned_list":["@all"]
    }
}

http.connect(ROBOT_URL).body(msg).post();
log.info('eHour消息推送成功')
// 以下cron表达式为每周五16:30分执行
00 30 16 * * 05

读取Excel文件并转换为json

import cn.hutool.poi.excel.ExcelUtil
import request
import log
var datas = ExcelUtil.getReader(new ByteArrayInputStream(request.getFile('file').getBytes())).readAll()
var sourceDatas = datas::stringify::json

导出Excel

import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.json.JSONUtil;
import log;
import response
import java.io.*;

var list = db['MDC'].select("select * from crawler_resource limit 10")

//通过hutool工具创建的excel的writer,默认为xls格式
ExcelWriter writer= ExcelUtil.getWriter();
var bos = new ByteArrayOutputStream();
log.info("List:\n" + JSONUtil.toJsonPrettyStr(list))
try {
    //一次性写出内容,使用默认样式,强制输出标题
    writer.write(list,true);
    writer.flush(bos,true);
} finally {
    bos.flush();
    writer.close();
}

return response.download(bos.toByteArray(), "crawler_resource_list.xlsx");

数据库事务处理

db.transaction(() => {
    if (archived_at == null) {
        //项目取消归档
        //推送取消归档的通知
        db.table("project_tasks").primary("project_id").primary("archived_follow").update({
            project_id: project_id,
            archived_follow: 1,
            archived_at: null,
            archived_follow: 0,

        })
    } else {
        //项目归档
        db.table("project_tasks").primary("project_id").primary("archived_at").update({
            project_id: project_id,
            archived_at: null,
            archived_at: archived_at,
            archived_follow: 1,
        })
    }

    db.table("projects").primary("id").update({
        id: project_id,
        archived_at: archived_at,
        archived_userid: userid
    })

})
0

评论 (0)

取消