除了 Web UI,hledger-web 还提供一个 JSON API,可用于获取数据或添加新事务。如果您只需要 JSON API,则可以使用该--serve-api标志。
Json Api启动
hledger-web.exe -f D:\Program\hledger\test.hledger.journal --serve-api

路由
我们可以从以下路由获取Json数据
/favicon.ico FaviconR GET
/robots.txt RobotsR GET
/static StaticR Static getStatic
/ RootR GET
/journal JournalR GET
/register RegisterR GET
/add AddR GET POST PUT
/manage ManageR GET
/edit/#FilePath EditR GET POST
/upload/#FilePath UploadR GET POST
/download/#FilePath DownloadR GET
/version VersionR GET
/accountnames AccountnamesR GET 帐户名称
/transactions TransactionsR GET 交易
/prices PricesR GET 价格
/commodities CommoditiesR GET
/accounts AccountsR GET
/accounttransactions/#AccountName AccounttransactionsR GET
这时候再通过浏览器访问会直接报错,因为没有开启web ui

只能通过Json进行访问,linux系统可以通过curl命令访问,然后通过python命令进行格式化
curl -s http://127.0.0.1:5000/accountnames | python -m json.tool
这里我是windows系统,同时为了和我们项目保持一致,我们将使用Java模拟访问一下。
官方的json数据:
{
"tcomment": "",
"tpostings": [
{
"pbalanceassertion": null,
"pstatus": "Unmarked",
"pamount": [
{
"aprice": null,
"acommodity": "$",
"aquantity": {
"floatingPoint": 1,
"decimalPlaces": 10,
"decimalMantissa": 10000000000
},
"aismultiplier": false,
"astyle": {
"ascommodityside": "L",
"asdigitgroups": null,
"ascommodityspaced": false,
"asprecision": 2,
"asdecimalpoint": "."
}
}
],
"ptransaction_": "1",
"paccount": "assets:bank:checking",
"pdate": null,
"ptype": "RegularPosting",
"pcomment": "",
"pdate2": null,
"ptags": [],
"poriginal": null
},
{
"pbalanceassertion": null,
"pstatus": "Unmarked",
"pamount": [
{
"aprice": null,
"acommodity": "$",
"aquantity": {
"floatingPoint": -1,
"decimalPlaces": 10,
"decimalMantissa": -10000000000
},
"aismultiplier": false,
"astyle": {
"ascommodityside": "L",
"asdigitgroups": null,
"ascommodityspaced": false,
"asprecision": 2,
"asdecimalpoint": "."
}
}
],
"ptransaction_": "1",
"paccount": "income:salary",
"pdate": null,
"ptype": "RegularPosting",
"pcomment": "",
"pdate2": null,
"ptags": [],
"poriginal": null
}
],
"ttags": [],
"tsourcepos": {
"tag": "JournalSourcePos",
"contents": [
"",
[
1,
1
]
]
},
"tdate": "2008-01-01",
"tcode": "",
"tindex": 1,
"tprecedingcomment": "",
"tdate2": null,
"tdescription": "income",
"tstatus": "Unmarked"
}
debug模式启动Hledger web
官方描述:General flags: -h –help show general help or (after command) command help –debug=N show debug output if N is 1-9 (default: 0) –version show version information
调试方式启动web ui
hledger-web.exe --debug=9 -f D:\Program\hledger\test.hledger.journal
经过测试发现是可以获取到debug信息但是并没有得到想要的debug信息。请求错误依旧是简单的返回400错误,没有显示具体信息。

java模拟访问Json
通过json api获取hledger数据
@Test
public void test5(){
String urlPath = "http://127.0.0.1:5000/transactions";
try {
URL url = new URL(urlPath);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream inputStream = connection.getInputStream();
//对应的字符编码转换
Reader reader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader bufferedReader = new BufferedReader(reader);
String str = null;
StringBuffer sb = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
sb.append(str);
}
reader.close();
connection.disconnect();
System.out.println(sb);
} catch (IOException e) {
e.printStackTrace();
}
}
账户里只有一条交易的json数据,可以认为是基本组成单位。
未格式化:
[{"tcomment":"","tstatus":"Unmarked","ttags":[],"tprecedingcomment":"","tpostings":[{"pdate":null,"poriginal":null,"ptags":[],"paccount":"资产:银行卡","pdate2":null,"ptype":"RegularPosting","pbalanceassertion":null,"pstatus":"Unmarked","pamount":[{"aprice":null,"acommodity":"","astyle":{"asprecision":0,"asdecimalpoint":".","ascommodityspaced":false,"asdigitgroups":null,"ascommodityside":"L"},"aquantity":{"floatingPoint":1200,"decimalPlaces":0,"decimalMantissa":1200}}],"ptransaction_":"1","pcomment":""},{"pdate":null,"poriginal":null,"ptags":[],"paccount":"资产:现金","pdate2":null,"ptype":"RegularPosting","pbalanceassertion":null,"pstatus":"Unmarked","pamount":[{"aprice":null,"acommodity":"","astyle":{"asprecision":0,"asdecimalpoint":".","ascommodityspaced":false,"asdigitgroups":null,"ascommodityside":"L"},"aquantity":{"floatingPoint":-1200,"decimalPlaces":0,"decimalMantissa":-1200}}],"ptransaction_":"1","pcomment":""}],"tcode":"","tdate":"2021-10-08","tsourcepos":[{"sourceLine":1,"sourceName":"D:\\Program\\hledger\\test.hledger.journal","sourceColumn":1},{"sourceLine":3,"sourceName":"D:\\Program\\hledger\\test.hledger.journal","sourceColumn":28}],"tindex":1,"tdescription":"测试银行卡现金","tdate2":null}]
格式化:
{
"tcomment": "",
"tstatus": "Unmarked",
"ttags": [],
"tprecedingcomment": "",
"tpostings": [{
"pdate": null,
"poriginal": null,
"ptags": [],
"paccount": "资产:电脑库存",
"pdate2": null,
"ptype": "RegularPosting",
"pbalanceassertion": null,
"pstatus": "Unmarked",
"pamount": [{
"aprice": null,
"acommodity": "",
"astyle": {
"asprecision": 2,
"asdecimalpoint": ".",
"ascommodityspaced": false,
"asdigitgroups": null,
"ascommodityside": "L"
},
"aquantity": {
"floatingPoint": 13293.12,
"decimalPlaces": 2,
"decimalMantissa": 1329312
}
}],
"ptransaction_": "1",
"pcomment": ""
}, {
"pdate": null,
"poriginal": null,
"ptags": [],
"paccount": "资产:银行存款",
"pdate2": null,
"ptype": "RegularPosting",
"pbalanceassertion": null,
"pstatus": "Unmarked",
"pamount": [{
"aprice": null,
"acommodity": "",
"astyle": {
"asprecision": 2,
"asdecimalpoint": ".",
"ascommodityspaced": false,
"asdigitgroups": null,
"ascommodityside": "L"
},
"aquantity": {
"floatingPoint": -13293.12,
"decimalPlaces": 2,
"decimalMantissa": -1329312
}
}],
"ptransaction_": "1",
"pcomment": ""
}],
"tcode": "",
"tdate": "2021-10-08",
"tsourcepos": [{
"sourceLine": 2,
"sourceName": "D:\\Program\\hledger\\test.hledger.journal",
"sourceColumn": 1
}, {
"sourceLine": 5,
"sourceName": "D:\\Program\\hledger\\test.hledger.journal",
"sourceColumn": 1
}],
"tindex": 1,
"tdescription": "采购-电脑",
"tdate2": null
}
多条记录重复上述json组。
经测试发现报文类型要求的非常严格如下:模版里的null就是null,不是"",javaBean to json也要是null
"tdate2": null
"aprice": null,
"asdigitgroups": null,
如果java生成的报文为"",则发送不成功。
通过json api向hledger发送数据
用Http PUT添加一条交易信息,目前测试同样的报文Http Post报错,Http Put可以正确添加。
@Test
public void test6(){
try {
CloseableHttpClient httpclient = HttpClients.createDefault();
//HttpPost httpPost = new HttpPost("http://127.0.0.1:5000/add");
HttpPut httpPost = new HttpPut("http://127.0.0.1:5000/add");
httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
String tempJson = "{\"tcomment\":\"\",\"tstatus\":\"Unmarked\",\"ttags\":[],\"tprecedingcomment\":\"\",\"tpostings\":[{\"pdate\":null,\"poriginal\":null,\"ptags\":[],\"paccount\":\"资产:银行卡\",\"pdate2\":null,\"ptype\":\"RegularPosting\",\"pbalanceassertion\":null,\"pstatus\":\"Unmarked\",\"pamount\":[{\"aprice\":null,\"acommodity\":\"\",\"astyle\":{\"asprecision\":0,\"asdecimalpoint\":\".\",\"ascommodityspaced\":false,\"asdigitgroups\":null,\"ascommodityside\":\"L\"},\"aquantity\":{\"floatingPoint\":3200,\"decimalPlaces\":0,\"decimalMantissa\":3200}}],\"ptransaction_\":\"1\",\"pcomment\":\"\"},{\"pdate\":null,\"poriginal\":null,\"ptags\":[],\"paccount\":\"资产:现金\",\"pdate2\":null,\"ptype\":\"RegularPosting\",\"pbalanceassertion\":null,\"pstatus\":\"Unmarked\",\"pamount\":[{\"aprice\":null,\"acommodity\":\"\",\"astyle\":{\"asprecision\":0,\"asdecimalpoint\":\".\",\"ascommodityspaced\":false,\"asdigitgroups\":null,\"ascommodityside\":\"L\"},\"aquantity\":{\"floatingPoint\":-3200,\"decimalPlaces\":0,\"decimalMantissa\":-3200}}],\"ptransaction_\":\"1\",\"pcomment\":\"\"}],\"tcode\":\"\",\"tdate\":\"2021-10-08\",\"tsourcepos\":[{\"sourceLine\":1,\"sourceName\":\"D:\\\\Program\\\\hledger\\\\test.hledger.journal\",\"sourceColumn\":1},{\"sourceLine\":3,\"sourceName\":\"D:\\\\Program\\\\hledger\\\\test.hledger.journal\",\"sourceColumn\":28}],\"tindex\":1,\"tdescription\":\"测试银行卡现金3\",\"tdate2\":null}";
// 解决中文乱码问题
// StringEntity stringEntity = new StringEntity(obj.toString(), "UTF-8");
StringEntity stringEntity = new StringEntity(tempJson, "UTF-8");
stringEntity.setContentEncoding("UTF-8");
httpPost.setEntity(stringEntity);
// CloseableHttpResponse response =
// httpclient.execute(httpPost);
System.out.println("Executing request " + httpPost.getRequestLine());
// Create a custom response handler
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {//
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
throw new ClientProtocolException(
"Unexpected response status: " + status);
}
}
};
String responseBody = httpclient.execute(httpPost, responseHandler);
System.out.println("----------------------------------------");
System.out.println(responseBody);
} catch (Exception e) {
System.out.println(e);
}
}
apache http client的maven坐标:
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>