码学堂商户接入指南
1. 概述与接入流程
2. 题目加载接口指南
3. 提交判题接口指南
4. 测评结果查询接口指南
5. 知识点加载接口指南
6. 知识点管理接口指南
7. 题目管理接口指南
选项格式说明
编程语言对应说明
8. 编程题、函数题、程序填空题批量上传测试数据集
9. 商户授权说明
-
+
home page
2. 题目加载接口指南
## 2.1 概述 通过码学堂提供的题库接口,用户可以直接引用码堂平台中,指定教师所出的或公开的题目。 ## 2.2 请求参数说明 | 序号 | 参数 | 名称 | 是否必须提供 |描述 | | :----: | :----: | :----: | :----: |:---- | | 01 | merchant_id | 商户号 | 是 | | | 02 | ptype | 题目类型 | 是| {1,2,3,...,8},1:判断题、2:单项选择题、3:多项选择题、4:填空题、5:程序函数题、6:程序填空题、7:编程题、8:主观题| | 03 | sign | 签名 | 是 | SHA256签名 | | 04 | pid | 题目ID | 是 | 整型,指定时仅返回当前题目 | | 05 | uid | 教师ID | 否 | 指定时仅返回当前教师发布的题目| | 06 | kp_level | 知识点级别|否|1为一级,2为二级,3为三级| | 07 | kp_id | 知识点ID|否|整型,指定时仅返回当前知识点下的题目| | 08 | start | 分页 | 否 |不指定时默认为0,表示第1页,每页10条数据| | 09 |timestamp|时间戳|否|长整型数| ## 2.3 请求地址及方式 请求地址:`https://mp.api.maxuetang.cn/problem` 请求方式:`POST` ## 2.4 返回JSON参数说明 | 序号 | 参数 | 名称 | 描述 | | :---- | :----: | :----: |:---- | |01|success|成功标识|true 或 false| |02|msg|消息|返回执行消息| |03|data|数据|返回数据对象| |04|memory|内存大小|编程题目时返回内存大小要求| |05|time|时间要求|编程题目时返回内存大小要求,单位为秒| |06|in|输入|编程题目时返回输入要求说明| |07|out|输出|编程题目时返回输出要求说明| |08|src|题目来源| | |09|ans|题目解析| JSON对象,文本描述为desc,编程题目程序模板为列表,元素对象为{"language":"language","source":"code"}| |10|pid|题目ID| | |11|diff|题目难度|{1,2,3,4,5}| |12|ptype|题目类型|{1,2,3,...,8}| |13|source|题目资源信息|标准答案json格式字符串,选择题返回:{"0":{"key":"A","value":"optionA","ans":0},"1":{"key":"B","value":"optionA","ans":1},"length":2};程序填空题时返回填空程序段 | |14|title|题目名称|| |15|sample_in|样例输入|编程题目时返回| |16|sample_out|样例输出|编程题目时返回| |17|other_in_out|其他样例输入输出列表|编程题目时返回| |18|tip|提示| | |19|desc|题目题面描述|填空题时返回字符串中包含“填空”的标识信息@@{答案}(分数),可以作正则表达式解析后生成“填空”| |20|uid|所属教师ID|非公开题目时返回| |21|status|题目公开标识|2表示公开| |22|score|分数|| |23|teacher|教师| | |24|score_json|分数分布|程序题目时返回各测试数据分数JSON,主观题时返回得分点JSON| |25|start|分页|数据为列表时返回| |26|limit|分页大小|数据为列表时返回| |27|rows|数据总条数|数据为列表时返回| ## 2.5 接入示例 POST请求: ```java problem?pid=1008&ptype=7&merchant_id=88&sign=8dd82f52c26...dd60731012f0 ``` 示例返回如下: ```json { "success": true, "msg": "OK", "data": { "memory": "64", "in": "输入的每行有两个输入数据。第一个是十进制数;第二个是负进制数的基数", "src": "第六届全国青少年信息学(计算机)奥林匹克分区联赛[2000年12月2日]", "ans": { "list": [ { "language": "cc", "source": "#include<iostream>\nusing namespace std;\nconst int N=1e5;\nint n,r,num=-1;\nint a[N];\nchar alp[10]={'A','B','C','D','E','F','G','H','I'};\nvoid print(int x){\n if(x<10) cout<<x;\n else cout<<alp[x-10];\n}\nint main(){\n cin>>n>>r;\n cout<<n<<\"=\";\n while(n!=0){\n a[++num]=n%r;\n n/=r;\n if(a[num]<0) a[num]-=r,n++;\n //cout<<a[num]<<\"\\n\";\n }\n for(int j=num;j>=0;j--) if(a[j]!=0||j!=num) print(a[j]);\n cout<<\"(base\"<<r<<\")\";\n}\n\n" } ], "desc": "答案解析" }, "pid": "1008", "diff": "3", "ptype": "7", "source": "", "title": "[2000年NOIP提高组] 进制转换", "sample_in": "30000 -2\n-20000 -7\n28800 -16\n-25000 -16", "out": "<p>结果显示在屏幕上,相对于输入,应输出此负进制数及其基数", "uid": "", "score": "15", "teacher": "向老师", "sample_out": "30000=1101101010111000(base-2)\n-20000=1111011000100000(base-2)\n28800=19180(base-16)\n-25000=7FB8(base-16)", "score_json": {"0":{"score":3,"desc":"fjz1"},"1":{"score":3,"desc":"fjz3"},"2":{"score":3,"desc":"fjz4"},"3":{"score":3,"desc":"fjz5"},"test":{"score":3,"desc":"test"}}, "other_in_out": [], "tip": "每个测试数据不超过1000", "time": "1", "desc": "我们可以用这样的方式来表示一个十进制数:将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数...底数的幂之和的形式。", "status": "2" } } ``` ### 2.5.1 Java接入示例 (1) SHA256加密算法 ```java package com.mxt.sign; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class SHA256Util { public static String createSHA256Str(String s) { if(s==null)return null; try { MessageDigest d = MessageDigest.getInstance("SHA-256"); d.update(s.getBytes("UTF-8")); return hexSHA256(d.digest()); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private static String hexSHA256(byte[] b) { StringBuffer sub = new StringBuffer(); for(int i = 0; i < b.length; ++i) { String t = Integer.toHexString(b[i] & 0xFF); sub.append(t.length() == 1? "0"+t:t); } return sub.toString(); } } ``` (2) 签名算法 ```java package com.mxt.sign; import java.util.Iterator; import java.util.Map; /** * 签名 * @author maxuetang.cn * @date 2022-04-06 */ public class SignHelper { /** * 生成签名 * @param map:TreeMap * @param key:商户密钥 * @return 签名字符串 */ public static String sign(Map map, String key){ map.remove("sign"); Iterator <String>iter = map.keySet().iterator(); StringBuffer sb = new StringBuffer(); while(iter.hasNext()){ sb.append(map.get(iter.next())); } return SHA256Util.createSHA256Str(sb.toString() + key); } /** * 签名验证 * @param map:TreeMap * @param key:商户密钥 * @param sign:签名字符串 * @return */ public static boolean checkSign(Map map, String key, String sign){ if(map==null)return false; map.remove("sign"); Iterator <String>iter = map.keySet().iterator(); StringBuffer sb = new StringBuffer(); while(iter.hasNext()){ sb.append(map.get(iter.next())); } if(sb.length()<1)return false; return sign.equalsIgnoreCase(SHA256Util.createSHA256Str(sb.toString() + key)); } } ``` (3) 请求算法 ```java package com.mxt.problem.load; import java.util.Map; import java.util.TreeMap; import com.mxt.sign.SignHelper; import cn.hutool.http.HttpUtil; import cn.hutool.json.JSONObject; public class ProblemRemote { public static final String MERCHANT_ID="商户号"; public static final String MERCHANT_KEY="商户密钥"; public static final String SERVER_HOST = "https://mp.api.maxuetang.cn/problem"; //按列表读取题目 public static JSONObject getProblems(int ptype, int start) { Map params = new TreeMap(); params.put("merchant_id", MERCHANT_ID); params.put("ptype" , ptype); params.put("start" , start); params.put("timestamp" , System.currentTimeMillis()); params.put("sign" , SignHelper.sign(params, MERCHANT_KEY)); return new JSONObject(HttpUtil.post(SERVER_HOST, params)); } //按题目号读取题目 public static JSONObject getProblem(int ptype, int pid) { Map params = new TreeMap(); params.put("merchant_id", MxtApiConfig.MERCHANT_ID); params.put("ptype" , ptype); params.put("pid" , pid); params.put("timestamp" , System.currentTimeMillis()); params.put("sign" , SignHelper.sign(params, MxtApiConfig.MERCHANT_KEY)); return new JSONObject(HttpUtil.post(MxtApiConfig.PROBLEM_LOAD_API, params)); } public static void main(String []args) { System.out.println(getProblems(1,0)); } } ``` ## 2.6 注意事项 (1) 码学堂具有题目的管理功能,所以在显示题目时,需要在页面中加上样式: ```html <link rel="stylesheet" href="https://www.maxuetang.cn/lxojres/mxt-editor/css/mxt-editor.min.css?v=20220406"/> ``` (2) 填空题解析 ```java /** * 功能:将题目描述中的@@{答案}(分数)通过正则表达式轮换为带“空”的html * 参数:h为题目题目描述 * 返回:html代码,包含填空对应的input标签 */ var convertFillOutHtml=(h)=>{ var patt1 = /@@\{(.+?)\}\(([0-9]+\.{0,1}[0-9]{0,2})\)+/g; var patt2 = /@@\{(.+?)\}\(([0-9]+\.{0,1}[0-9]{0,2})\)/; var mm = h.match(patt1); for(var i=0;i<mm.length;i++){ var jj = mm[i].match(patt2); h = h.replace("@@{"+jj[1]+"}("+jj[2]+")","<input class='fill-out-ipt' type='text' value=''/><span>("+jj[2]+"分)</span>"); } return h; } ``` (3) 程序填空题解析 ```java /** * 功能:将题目裁判样例中的@@{答案}(分数)通过正则表达式轮换为带“空”的html * 参数:h为题目裁判样例,pid为题目ID * 返回:html代码,包含填空对应的input标签 */ var convertFillOutHtml=(h,pid)=>{ h = h.replace(new RegExp("<","g"),"<").replace(new RegExp(">","g"),">");; var patt1 = /@@\{(.+?)\}\(([0-9]+\.{0,1}[0-9]{0,2})\)+/g; var patt2 = /@@\{(.+?)\}\(([0-9]+\.{0,1}[0-9]{0,2})\)/; var mm = h.match(patt1); var obj = []; for(var i=0;i<mm.length;i++){ var jj = mm[i].match(patt2); h = h.replace("@@{"+jj[1]+"}("+jj[2]+")","<input data-id='"+pid+"' class='problem-input' type='text' value=''/><span>("+jj[2]+"分)</span>"); obj.push("("+(i+1)+") "+jj[1]+" "); } return {h:h, a:obj.join("")}; } ```
码学堂管理员
Aug. 2, 2023, 10:09 p.m.
Share documents
Collection documents
Last
Next
Scan wechat
Copy link
Scan your mobile phone to share
Copy link
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
share
link
type
password
Update password