
package com.dyl.dto;
import java.io.Serializable;
public class TreeModel implements Serializable {
private String id; // 節點 id
private String pId; // 父節點 id (zTree 必須大寫 P)
private String name; // 節點名稱
private boolean open = false; // 預設不展開
private String url; // 連結目標 URL
private String icon; // 自訂圖標路徑
private String title; // 提示訊息
// Getter/Setter 省略...
}
關鍵點:pId 大寫 P 為 zTree 固定慣例;title 欄位作為節點顯示文字(含 id+name)。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context/springContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>SpringServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context/dispatcher_servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:ORCL jdbc.username=dyl jdbc.password=dyl
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="1"/>
<property name="maxActive" value="5"/>
<property name="maxIdle" value="2"/>
<property name="minIdle" value="1"/>
<property name="maxWait" value="-1"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlmap/mybatis-config.xml"/>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<typeAliases> <typeAlias alias="tree" type="com.dyl.dto.TreeModel"/> </typeAliases> <mappers> <mapper resource="com/dyl/dao/OrgDaoMapper.xml"/> </mappers>
public interface IOrgDao {
List getTreeList(String org);
}
<select id="getTreeList" parameterType="java.lang.String" resultType="tree">
select distinct comcode id, comcname name, uppercomcode pId,
(comcode || '-' || comcname) title, comlevel
from org
start with comcode like concat(#{org}, '%')
connect by nocycle uppercomcode = prior comcode
order by comlevel
</select>
使用 Oracle START WITH ... CONNECT BY 遞歸查詢,nocycle 防循環。
@Service("orgServiceImpl")
@Transactional
public class OrgServiceImpl implements IOrgService {
@Resource(name="sqlSessionTemplate")
private SqlSessionTemplate session;
public List getTreeList(String org) throws Exception {
IOrgDao dao = session.getMapper(IOrgDao.class);
return dao.getTreeList(org);
}
}
@Controller
@RequestMapping("org.do")
public class OrgController {
@Resource(name="orgServiceImpl")
private IOrgService orgService;
@RequestMapping(params="method=queryOrg")
public void queryOrg(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html;charset=GBK");
PrintWriter out = response.getWriter();
String data = "0"; // 預設失敗
try {
List list = orgService.getTreeList(request.getParameter("org"));
if (list.isEmpty()) data = "2"; // 無資料
else data = JSONArray.fromObject(list).toString();
} catch (Exception e) {
logger.error("查詢機構樹異常", e);
} finally {
out.write(data);
out.close();
}
}
}
function selectOrg() {
var diag = new Dialog();
diag.Width = 400; diag.Height = 400;
diag.Title = "請選擇機構";
diag.URL = '/WebRoot/jsp/invoicemanage/invoiceOrgTree.jsp?org=' + fm.org.value;
diag.OKEvent = function() {
var val = diag.innerFrame.contentWindow.document.getElementById('orgOfTree').value;
if (val) { fm.org.value = val; diag.close(); }
else Dialog.alert('請選擇機構');
};
diag.show();
}
<script src="/WebRoot/js/jquery-1.9.1.min.js"></script>
<script src="/WebRoot/js/zTree/jquery.ztree.all.min.js"></script>
<link rel="stylesheet" href="/WebRoot/js/zTree/zTreeStyle.css"/>
<ul id="orgTree" class="ztree"></ul>
<script>
function init() {
$.ajax({
type: "POST", url: '/WebRoot/org.do',
data: { method: 'queryOrg', org: fm.orgOfTree.value },
dataType: "json",
beforeSend: function() { $(document).mask('載入中...'); },
success: function(data) {
if (data == '0') { Dialog.alert('系統異常'); return; }
if (data == '2') { Dialog.alert('無資料'); return; }
var setting = {
check: { chkStyle: 'radio', radioType: 'all' },
data: { key: { name: 'title' }, simpleData: { enable: true } },
callback: { onClick: zTreeOnClick, onCheck: zTreeOnCheck }
};
var treeNodes = data; // 後端直接回傳 zTree 相容的簡單 JSON
$.fn.zTree.init($("#orgTree"), setting, treeNodes);
var treeObj = $.fn.zTree.getZTreeObj("orgTree");
var nodes = treeObj.getNodes();
if (nodes.length > 0) {
treeObj.selectNode(nodes[0]);
fm.orgOfTree.value = nodes[0].id;
}
},
complete: function() { $(document).unmask(); }
});
}
function zTreeOnClick(event, treeId, treeNode) {
fm.orgOfTree.value = treeNode.id;
}
function zTreeOnCheck(event, treeId, treeNode) {
fm.orgOfTree.value = treeNode.id;
}
</script>

本實作展示了從資料庫層次查詢、DTO 設計、MyBatis 映射、Spring 分層、Controller JSON 回傳、zTree 前端渲染的完整鏈路。關鍵在於後端直接輸出 zTree 相容的簡單 JSON 格式,前端零轉換即可渲染,極大簡化開發。