前提準備:JSON文字列
[{
"id": 1,
"code": "FLOW_NODE_1",
"name": "環節A",
"children": [{
"id": 2,
"code": "RULE_NODE_1",
"name": "規則A"
}, {
"id": 3,
"code": "RULE_NODE_2",
"name": "規則B"
}, {
"id": 4,
"code": "PARALLEL_NODE_2",
"name": "並行ノード",
"children": [{
"id": 5,
"code": "RULE_NODE_3",
"name": "規則C1"
}, {
"id": 6,
"code": "RULE_COLLECTION_1",
"name": "規則集1",
"children": [{
"id": 7,
"code": "RULE_NODE_4",
"name": "規則C21"
}, {
"id": 8,
"code": "RULE_NODE_5",
"name": "規則C22"
}]
}]
}, {
"id": 9,
"code": "MUTUAL_NODE_1",
"name": "互斥ノード",
"children": [{
"id": 10,
"code": "RULE_NODE_6",
"name": "規則D1"
}, {
"id": 11,
"code": "RULE_NODE_7",
"name": "規則D2"
}]
}]
}, {
"id": 12,
"code": "FLOW_NODE_2",
"name": "環節B"
}]
本記事ではSpring Boot環境下でのFastJson APIの使用例を紹介します。
ステップ1:依存関係の追加
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
- 指定したtreeIdのJSONツリーを検索し、前端に返す方法
Controller:
/**
* @param treeId
* @return
*/
@ApiOperation(value = "ツリー情報を検索", notes = "ツリー情報を検索")
@RequestMapping(value = "/api/v1/orders/findTree", method = RequestMethod.POST)
public Map findTree(@ApiParam(required = true, value = "ツリーID") @RequestParam Integer treeId) {
return ActionHelper.responseOk(categoryTreeService.getJsonTree(treeId));
}
Service:
// IDを用いてJSONツリーを検索
public JSONArray getJsonTree(Integer treeId) {
JSONArray jsonTree = JSONArray.parseArray(categoryTreeRepository.selectJsonTree(treeId));
return jsonTree;
}
- 指定したtreeIdのJSONツリー内にある特定のkey-valueペアを持つノードを検索する方法
Controller:
/**
* @param treeId ツリーID
* @param key 検索するノードのキー
* @param value 検索するノードの値
* @return
*/
@ApiOperation(value = "ノード情報を検索", notes = "ノード情報を検索")
@RequestMapping(value = "/api/v1/orders/findNode", method = RequestMethod.POST)
public Map findNode(@ApiParam(required = true, value = "ツリーID") @RequestParam Integer treeId,
@ApiParam(required = true, value = "ノードキー") @RequestParam String key,
@ApiParam(required = true, value = "ノード値") @RequestParam String value) {
return ActionHelper.responseOk(categoryTreeService.searchNode(treeId, key, value));
}
Service:
// 特定のkey-valueペアを持つノードを検索
public JSONObject searchNode(Integer treeId, String key, String value) {
JSONArray jsonTree = JSONArray.parseArray(categoryTreeRepository.selectJsonTree(treeId));
JSONObject node = search(jsonTree, key, value, new JSONObject());
return node;
}
/**
* 特定条件に一致するノードを検索
* @param body 検索対象のJSON配列
* @param key 検索条件のキー
* @param value 検索条件の値
* @param result 検索結果を格納するJSONObject
* @return
*/
public static JSONObject search(JSONArray body, String key, Object value, JSONObject result) {
for (int i = 0; i < body.size(); i++) {
JSONObject jsonObject = body.getJSONObject(i);
if (jsonObject.get(key).toString().equals(value.toString())) {
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
result.put(entry.getKey(), entry.getValue());
}
} else if (jsonObject.getJSONArray("children") != null) {
search(jsonObject.getJSONArray("children"), key, value, result);
}
}
return result;
}
- 指定したtreeIdのノードを削除する方法
Controller:
@ApiOperation(value = "ノード情報を削除", notes = "ノード情報を削除")
@RequestMapping(value = "/api/v1/orders/delNode", method = RequestMethod.POST)
public Map delNode(@ApiParam(required = true, value = "ツリーID") @RequestParam Integer treeId,
@ApiParam(required = true, value = "ノードキー") @RequestParam String key,
@ApiParam(required = true, value = "ノード値") @RequestParam String value) {
return ActionHelper.responseOk(categoryTreeService.deleteNode(treeId, key, value));
}
Service:
// JSONツリーから指定ノードを削除し、子ノードも削除
public JSONObject deleteNode(Integer treeId, String key, String value) {
JSONArray jsonTree = JSONArray.parseArray(categoryTreeRepository.selectJsonTree(treeId));
JSONObject node = search(jsonTree, key, value, new JSONObject());
delete(jsonTree, key, value);
String updatedTree = jsonTree.toString();
categoryTreeRepository.updateTree(updatedTree, treeId);
return node;
}
/**
* 特定条件に一致するノードを削除
* @param body 削除対象のJSON配列
* @param key 削除条件のキー
* @param value 削除条件の値
*/
public void delete(JSONArray body, String key, Object value) {
for (int i = 0; i < body.size(); i++) {
JSONObject jsonObject = body.getJSONObject(i);
if (jsonObject.get(key).toString().equals(value.toString())) {
body.remove(i);
break;
} else if (jsonObject.getJSONArray("children") != null) {
delete(jsonObject.getJSONArray("children"), key, value);
}
}
}
Mapper:
public interface CategoryTreeRepository extends JpaRepository<CategoryTree, String>, JpaSpecificationExecutor<CategoryTree> {
// 指定IDのJSONツリー文字列を取得
@Query(value = "SELECT jsonTree FROM catagory_tree WHERE id = ?1", nativeQuery = true)
String selectJsonTree(Integer id);
@Modifying
@Transactional
@Query(value = "UPDATE catagory_tree SET jsonTree = ?1 WHERE id = ?2", nativeQuery = true)
void updateTree(String jsonTreeStr, Integer id);
}
- 指定したkey-valueペアノードの下に新規ノードを追加する方法
Controller:
@ApiOperation(value = "新規ノードを作成", notes = "新規ノードを作成")
@RequestMapping(value = "/tree_data/node/{treeId}", method = RequestMethod.POST)
public Map addNode(@ApiParam(required = true, value = "カテゴリツリーID") @PathVariable Integer treeId,
@ApiParam(required = true, value = "ノードキー") @RequestParam String key,
@ApiParam(required = true, value = "ノード値") @RequestParam String value,
@ApiParam(required = true, value = "挿入位置") @RequestParam Integer index,
@ApiParam(required = true, value = "ノード情報") @RequestBody Map map) {
return ActionHelper.responseOk(categoryTreeService.addNode(treeId, key, value, index, map));
}
Service:
// JSONツリーにノードを追加
public JSONArray addNode(Integer treeId, String key, Object value, Integer sequ, Map newNodeMap) {
JSONArray jsonTree = JSONArray.parseArray(categoryTreeRepository.selectJsonTree(treeId));
Integer nodeId = (Integer) newNodeMap.get("id");
JSONObject node = search(jsonTree, "id", nodeId, new JSONObject());
if (!node.isEmpty()) {
throw new BadRequestException("指定されたIDのノードが既に存在します");
}
JSONObject newNode = new JSONObject(newNodeMap);
insertNode(jsonTree, key, value, sequ, newNode);
return jsonTree;
}
/**
* 指定条件に一致するノードの子要素として新規ノードを挿入
* @param jsonArray 更新対象のJSON配列
* @param key 挿入条件のキー
* @param value 挿入条件の値
* @param sequ 挿入位置
* @param node 挿入する新規ノード
*/
public void insertNode(JSONArray jsonArray, String key, Object value, Integer sequ, JSONObject node) {
for (Object obj : jsonArray) {
JSONObject jsonObject = (JSONObject) obj;
JSONArray children = jsonObject.getJSONArray("children");
if (children != null) {
if (value.toString().equals(jsonObject.get(key).toString())) {
if (sequ > children.size()) {
children.add(children.size(), node);
} else {
children.add(sequ - 1, node);
}
return;
}
insertNode(children, key, value, sequ, node);
} else {
if (value.toString().equals(jsonObject.get(key).toString())) {
JSONArray array = new JSONArray();
array.add(node);
jsonObject.put("children", array);
return;
}
}
}
}
- 指定したノードIDのノード属性を更新する方法
Controller:
@ApiOperation(value = "ノード情報を更新", notes = "ノード情報を更新")
@RequestMapping(value = "/tree_data/node/{treeId}/{id}", method = RequestMethod.PATCH)
public Map updateNode(@ApiParam(required = true, value = "カテゴリツリーID") @PathVariable Integer treeId,
@ApiParam(required = true, value = "ノードID") @PathVariable Integer id,
@ApiParam(required = true, value = "ノード情報") @RequestBody Map map) {
return ActionHelper.responseOk(categoryTreeService.updateNode(treeId, id, map));
}
Service:
/**
* 単一ノードを更新
* @param treeId
* @param nodeId
* @param map
* @return
*/
@Transactional
public JSON updateNode(Integer treeId, Integer nodeId, Map map) {
JSONArray jsonTree = JSONArray.parseArray(categoryTreeRepository.selectJsonTree(treeId));
if (!search(jsonTree, "id", nodeId, new JSONObject()).isEmpty()) {
update(jsonTree, "id", nodeId, map);
categoryTreeRepository.updateTree(jsonTree.toString(), treeId);
} else {
throw new BadRequestException("指定されたIDのノードが存在しません");
}
return jsonTree;
}
/**
* 指定条件に一致するノードの属性を更新
* @param jsonArray 更新対象のJSON配列
* @param key 更新条件のキー
* @param value 更新条件の値
* @param map 更新する属性情報
*/
public void update(JSONArray jsonArray, String key, Object value, Map<String, Object> map) {
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
if (value.toString().equals(json.get(key).toString())) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
json.put(entry.getKey(), entry.getValue());
}
break;
} else if (json.getJSONArray("children") != null) {
update(json.getJSONArray("children"), key, value, map);
}
}
}