본문 바로가기

JAVA

부모-자식관계 트리구조 만들기

부서를 구현하고 싶을때, 3단계 까지 들어가는 부서가 있다고 치면 

예를 들어 ○○실-□부-△△팀 의 형식이라 해당하는 부서를 컬럼으로 따로 구분했었습니다. 

기존에 이미 서비스중인 시스템의 데이터베이스였어서, 각각 실,부,팀의 컬럼 코드 조합해 키값을 만들어내는 식으로 구현했었는데 이후 더 효율적인 방법이 있을것으로 생각해 구현해보았습니다. 

 

데이터베이스에 부모의 값을 가지는 컬럼만 추가해주고 자바코드에서 이를 구현하는것인데요. 

 

데이터베이스는 이렇게만 구성해주면 자식이 무한대로 늘어날수 있는 부서구조가 되겠네요. 

문제는 자바코드에서 뿌려줄때, 

위와 같은 구조를 가지도록 구현하는것입니다. 

 

먼저, 트리에 해당하는 VO를 만들어 주도록 하겠습니다. 

public class TreeNode {

	// 트리 기본 - easyui property
	private int id;
	private String state;
	private String checked;
	private String text;
	private int pid;

	// 부서용
	private int team_cd;
	private String team_name;
	private String r_cdate;
	private String r_deleted;
	private int team_parent_cd;
	private String depth_fullname;
	private List<TreeNode> children = new ArrayList<TreeNode>();
	
	

	public int getPid() {
		return pid;
	}

	public void setPid(int pid) {
		this.pid = pid;
	}

	public String getDepth_fullname() {
		return depth_fullname;
	}

	public void setDepth_fullname(String depth_fullname) {
		this.depth_fullname = depth_fullname;
	}
	
	public int getTeam_parent_cd() {
		return team_parent_cd;
	}

	public void setTeam_parent_cd(int team_parent_cd) {
		this.team_parent_cd = team_parent_cd;
	}

	public List<TreeNode> getChildren() {
		return children;
	}

	public void setChildren(List<TreeNode> children) {
		this.children = children;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public String getChecked() {
		return checked;
	}

	public void setChecked(String checked) {
		this.checked = checked;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public int getTeam_cd() {
		return team_cd;
	}

	public void setTeam_cd(int team_cd) {
		this.team_cd = team_cd;
	}

	public String getTeam_name() {
		return team_name;
	}

	public void setTeam_name(String team_name) {
		this.team_name = team_name;
	}

	public String getR_cdate() {
		return r_cdate;
	}

	public void setR_cdate(String r_cdate) {
		this.r_cdate = r_cdate;
	}

	public String getR_deleted() {
		return r_deleted;
	}

	public void setR_deleted(String r_deleted) {
		this.r_deleted = r_deleted;
	}

	@Override
	public String toString() {
		return "TreeNode [id=" + id + ", state=" + state + ", checked=" + checked + ", text=" + text + ", team_cd="
				+ team_cd + ", team_name=" + team_name + ", r_cdate=" + r_cdate + ", r_deleted=" + r_deleted
				+ ", team_parent_cd=" + team_parent_cd + ", depth_fullname=" + depth_fullname + ", children=" + children
				+ "]";
	}

}

 

주석을 달아놓은 트리 기본은 제가 주로 사용하는 easyui에서 사용하는 키값과 상태값입니다.

이외는 데이터베이스의 컬럼명과 동일하게 만들어주고, 자식이 들어갈 children List 를 만들어 놓고, getter, setter도 만들어주겠습니다. 

 

다음으로 만들 클래스는 트리를 만들어줄 TreeMake입니다. 이 클래스가 핵심이라고 보면되겠습니다. 

public class TreeMake {
	public List<TreeNode> formatTree(List<TreeNode> list) {
		
		TreeNode root = new TreeNode();
		TreeNode node = new TreeNode();
		List<TreeNode> treelist = new ArrayList<TreeNode>();
		List<TreeNode> parentnodes = new ArrayList<TreeNode>();
		if (list != null && list.size() > 0){
			root = list.get(0);
			for (int i = 1; i < list.size(); i++) {
				node = list.get(i);
				if (node.getPid() == root.getId()) {
					parentnodes.add(node);
					root.getChildren().add(node);
				}
				else {
					getChildrenNodes(parentnodes, node);
					parentnodes.add(node);
				}
			}     
		} 
		treelist.add(root);
		
		return treelist;
		
	}

	private static void getChildrenNodes(List<TreeNode> parentnodes, TreeNode node) {		
		for (int i = parentnodes.size() - 1; i >= 0; i--) {
			TreeNode pnode = parentnodes.get(i);
			if (pnode.getId() == node.getPid()) {
				//pnode.setState("closed");
				pnode.getChildren().add(node);
				return;
			}
			else {
				//parentnodes.remove(i);
			}
		}
	} 
}

코드를 자세히 보면, 최초로 데이터베이스에서 받아온 모든 리스트를 담은 리스트가 formatTree에 매개변수로서 들어오고, for문을 순회하며 root 노드와 id값이 일치하는지 여부를 확인후에, 자식노드로 넣습니다. 

id값이 일치하지 않는다면, getChildrenNodes 메소드에서 현재까지 들어온 노드중에서 부모노드를 찾아 해당하는 부모노드의 자식으로 넣어줍니다.  

 

이렇게 구현하면 사용할때는

@Service
public class SampleService {

	@Autowired
	private SampleDAO dao;
	
	public String getTeamCodeList(TreeNode vo) {
		String jsonString = "";
		try {
			List<TreeNode> result = new ArrayList<TreeNode>();
			
			List<TreeNode> list = dao.getTeamList(vo);
			
			for(int i=0;i<list.size();i++) {
				TreeNode node = list.get(i);
				node.setId(node.getTeam_cd());
				node.setText(node.getTeam_name());
				node.setPid(node.getTeam_parent_cd());
				result.add(node);
			}
			
			TreeMake tm = new TreeMake();
			List<TreeNode> out = tm.formatTree(result);
			
			ObjectMapper objectMapper = new ObjectMapper();
			jsonString = objectMapper.writeValueAsString(out);
		}catch(Exception e) {
			e.printStackTrace();
		}
		return jsonString;
	}
}

 위 코드에서와 같이 사용하면 되겠습니다. 

저는 json으로 뷰에 넘겨주어 사용했습니다. 

 

머리속에 있는것도 좋지만 기억이 안날때는 메모를 찾아보는게 가장 빠른 정답이 될수도 있겠어요.

 

'JAVA' 카테고리의 다른 글

웹서비스 - CXF vs AXIS  (1) 2021.03.12