ajax jsp 级联菜单(原始方式)

本文介绍了一个使用Ajax技术从客户端向服务器发起请求,并通过Servlet处理请求返回数据的示例。示例中展示了如何利用Ajax实现异步加载省份和城市数据的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

public class ProvLoad extends HttpServlet {
    Ajax001 a1=new Ajax001();
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
        List<String> prolist=a1.loadPro();
        StringBuffer sb=new StringBuffer("[");
        for(int i=0;i<prolist.size();i++){
        	sb.append(prolist.get(i));
        	if(i<prolist.size()-1){
        	sb.append(",");	
        	}
        }
        sb.append("]");
        response.setContentType("text/json; charset=utf-8");
		response.getWriter().println(sb.toString());
	}

}

 ajax js文件

function   createXmlHttpRequest(){
var xmlhttp = null;
try{
		//Firefox, Opera 8.0+, Safari
           xmlhttp=new XMLHttpRequest();
		}catch(e){//IEIE7.0以下的浏览器以ActiveX组件的方式来创建XMLHttpRequest对象
var MSXML = 
['MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0',
'MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0',
'MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
  for(var n = 0; n < MSXML.length; n ++){
    try{
      xmlhttp = new ActiveXObject(MSXML[n]);
      break;
    }catch(e){}}
  }
return xmlhttp;
}
function loadcity(name){
	var xhr=createXmlHttpRequest();
	xhr.onreadystatechange=function(){
		if(xhr.readyState==4 ||(xhr.status==200 || xhr.status==304)){
			alert(xhr.responseText);
			var ret=eval("("+xhr.responseText+")");
			alert("ret lenght:"+ret.length);
			var v="";
			for(var i=0;i<ret.length;i++){
			//	alert("retX="+ret[i]);
				v+="<option>"+ret[i]+"</option>";
			}
			//alert("v:"+v);
			document.getElementById("city").innerHTML=v;
		}
	}
	xhr.open("post","servlet/CityLoad",true);
	xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	alert(name);
	xhr.send("name="+name);
}
function loadpro(){
	var xhr=createXmlHttpRequest();
	xhr.onreadystatechange=function(){
		if(xhr.readyState==4 ||(xhr.status==200 || xhr.status==304)){
			var ret=eval("("+xhr.responseText+")");
			var s="<option>--</option>";
			for(var i=0;i<ret.length;i++){
				s+="<option>"+ret[i]+"</option>";
			}
			document.getElementById("pro").innerHTML=s;
		}
	}
	xhr.open("get","servlet/ProvLoad",true);
	xhr.send(null);
}
window.onload=loadpro;

 

页面内容

  选择省份<select id="pro" onchange="loadcity(this.value)"></select>选择城市<select id="city"></select>

 

<think>我们正在解决前端 combotree 组件的数据渲染问题,并需要调整后端 Service 层代码以支持正确的数据展示和选中状态。根据引用内容,我们可以推断出以下关键点: 1. 引用[1]提到了一种通过 ref 和 refUrl 实现级联菜单的方法,其中省级菜单的变化会触发市级菜单的数据加载。这启发我们:combotree 可能需要类似的数据结构(树形结构)和选中逻辑。 2. 引用[2]展示了后端返回菜单树数据的Controller方法,返回的是`List<Menu>`,这通常是一个树形结构的列表。 3. 引用[4]展示了前端验证逻辑,其中包含对下拉框选中值的检查,这提醒我们需要确保combotree的选中状态能够正确设置。 4. 引用[5]展示了通过HTML定义DataGrid的列和数据,但我们的问题焦点在combotree,所以重点在树形数据。 ## 问题分析 前端 combotree 组件需要的数据格式通常是树形结构(带有children属性的嵌套结构)。而后端Service层需要返回这样的树形结构,并且可能还需要支持选中状态(即某些节点默认选中)。 ### 前端 combotree 数据要求 根据代码片段: ```javascript $('#surveyind').combotree({ valueField: 'id', textField: 'text', data : JSON.parse('${surveyinds}'), // ... 其他配置 }); ``` 它要求数据源`${surveyinds}`是一个JSON字符串,解析后是一个树形结构的数组,每个节点至少包含`id`和`text`属性。此外,如果希望某些节点默认选中,节点可能还需要有`checked`属性(根据EasyUI combotree的文档)。 ### 后端Service层调整 我们需要调整Service层,使其返回的数据结构满足以下要求: 1. 树形结构,每个节点包含id、text、children(如果有子节点)等属性。 2. 支持选中状态:可能需要在节点上设置`checked: true`(根据EasyUI combotree,也可以使用`selected`属性,但combotree的多选模式通常用`checked`)。 ## 解决方案 ### 步骤1:定义树节点数据结构 在后端(Java)中,定义一个树节点类,例如: ```java public class TreeNode { private String id; // 对应valueField private String text; // 对应textField private boolean checked; // 是否选中 private List<TreeNode> children; // 子节点 // 构造方法、getter和setter省略 } ``` ### 步骤2:构建树形结构数据 在Service层,我们需要构建树形结构的数据。假设我们有一个实体类`Surveyind`,它包含自身的id、名称和父id,我们可以通过以下方法构建树: ```java public List<TreeNode> buildSurveyindTree(List<Surveyind> surveyindList) { // 先将所有节点按父节点分组 Map<String, List<Surveyind>> parentMap = new HashMap<>(); for (Surveyind item : surveyindList) { String parentId = item.getParentId(); if (!parentMap.containsKey(parentId)) { parentMap.put(parentId, new ArrayList<>()); } parentMap.get(parentId).add(item); } // 从根节点(假设根节点的父id为null或0)开始构建树 List<TreeNode> rootNodes = new ArrayList<>(); // 假设根节点的父id为"0" List<Surveyind> roots = parentMap.get("0"); if (roots != null) { for (Surveyind root : roots) { TreeNode rootNode = convertToTreeNode(root, parentMap); rootNodes.add(rootNode); } } return rootNodes; } private TreeNode convertToTreeNode(Surveyind item, Map<String, List<Surveyind>> parentMap) { TreeNode node = new TreeNode(); node.setId(item.getId()); node.setText(item.getName()); // 设置选中状态:这里需要根据业务逻辑判断,比如某些条件满足则设置为true // node.setChecked(...); // 递归构建子节点 List<Surveyind> children = parentMap.get(item.getId()); if (children != null && !children.isEmpty()) { List<TreeNode> childNodes = new ArrayList<>(); for (Surveyind child : children) { childNodes.add(convertToTreeNode(child, parentMap)); } node.setChildren(childNodes); } return node; } ``` ### 步骤3:在Controller中返回树形数据 在Controller中,调用Service方法获取树形数据,并返回给前端。注意,前端需要的是JSON字符串,但Spring MVC的`@ResponseBody`会自动将对象序列化为JSON。 ```java @RequestMapping("/getSurveyindTree") @ResponseBody public List<TreeNode> getSurveyindTree() { // 1. 获取所有Surveyind数据(从数据库查询) List<Surveyind> surveyindList = surveyindService.findAll(); // 2. 构建树形结构 return surveyindService.buildSurveyindTree(surveyindList); } ``` ### 步骤4:前端数据传递 在JSP页面中,我们不再需要将数据作为字符串直接内嵌,而是通过AJAX异步加载。这样避免JSON字符串在JSP中转义的问题。 修改前端代码: ```javascript $('#surveyind').combotree({ valueField: 'id', textField: 'text', url: '${ctx}/getSurveyindTree', // 通过URL加载数据 lines: true, editable: true, multiple: true, prompt: "请选择", onShowPanel: function() { $('.tree-folder').remove(); $('.tree-file').remove(); } }); ``` ### 步骤5:处理选中状态 如果我们需要在加载时设置某些节点为选中状态,有两种方法: 1. **后端设置**:在构建树节点时,根据业务逻辑设置`checked`属性(如上文代码中的注释部分)。例如,如果用户之前已经选择过某些指标,那么这些指标的节点应该被选中。 2. **前端设置**:如果后端返回的数据中已经包含`checked: true`的节点,combotree会自动选中。另外,也可以在combotree加载完成后,通过`setValues`方法设置选中值。 例如,假设我们已知要选中的节点id数组,可以在combotree初始化后设置: ```javascript $('#surveyind').combotree('setValues', [id1, id2, ...]); ``` ### 注意事项 1. **避免重复解析**:如果使用`url`配置,则不需要在页面内嵌JSON字符串,避免了之前遇到的JSON解析错误。 2. **特殊字符转义**:使用AJAX方式加载数据,避免了在JSP中处理JSON字符串的转义问题。 3. **性能优化**:如果树节点数据量很大,可以考虑懒加载(combotree支持逐级加载),但需要后端提供按父节点查询子节点的接口。 ## 总结 通过调整Service层构建树形结构数据,并通过Controller返回JSON,前端使用URL异步加载,可以解决combotree的数据渲染问题。同时,通过设置节点的`checked`属性或使用`setValues`方法,可以实现选中状态。 §§相关问题§§ 1. 如何构建树形结构数据? 2. EasyUI combotree 如何实现多选和选中状态? 3. 如何通过AJAX加载combotree数据?</think>要解决前端 combotree 数据渲染与后端 Service 层逻辑问题,确保正确支持数据展示和选中状态,需要修改 Service 层代码以生成符合 combotree 要求的树形数据结构。以下是系统化的解决方案: ### 🔧 后端 Service 层修改方案 #### 1. **构建树形数据结构**(参考引用[2]) ```java // Service 层方法 public List<TreeNode> buildSurveyindTree() { // 1. 查询原始数据(示例) List<Surveyind> allInds = surveyindDao.findAll(); // 2. 构建树形结构 List<TreeNode> treeNodes = new ArrayList<>(); Map<String, TreeNode> nodeMap = new HashMap<>(); // 创建所有节点 for (Surveyind ind : allInds) { TreeNode node = new TreeNode(); node.setId(ind.getId()); node.setText(ind.getName()); node.setChildren(new ArrayList<>()); nodeMap.put(ind.getId(), node); } // 构建父子关系 for (Surveyind ind : allInds) { TreeNode node = nodeMap.get(ind.getId()); if (ind.getParentId() == null || ind.getParentId().isEmpty()) { treeNodes.add(node); // 根节点 } else { TreeNode parent = nodeMap.get(ind.getParentId()); if (parent != null) { parent.getChildren().add(node); } } } return treeNodes; } ``` #### 2. **添加选中状态支持**(参考引用[1]的选中逻辑) ```java // 在构建树节点时添加选中状态 public List<TreeNode> buildSurveyindTreeWithSelection(Set<String> selectedIds) { List<TreeNode> tree = buildSurveyindTree(); // 递归设置选中状态 setCheckedStatus(tree, selectedIds); return tree; } private void setCheckedStatus(List<TreeNode> nodes, Set<String> selectedIds) { for (TreeNode node : nodes) { if (selectedIds.contains(node.getId())) { node.setChecked(true); // combotree 识别的选中属性 } if (node.getChildren() != null && !node.getChildren().isEmpty()) { setCheckedStatus(node.getChildren(), selectedIds); } } } ``` #### 3. **Controller 层返回 JSON 树**(参考引用[2][3]) ```java @Controller @RequestMapping("/survey") public class SurveyController { @Autowired private SurveyService surveyService; @RequestMapping(value = "/tree", method = RequestMethod.GET) @ResponseBody public List<TreeNode> getSurveyTree( @RequestParam(value = "selected", required = false) String[] selectedIds) { Set<String> selectedSet = selectedIds != null ? new HashSet<>(Arrays.asList(selectedIds)) : Collections.emptySet(); return surveyService.buildSurveyindTreeWithSelection(selectedSet); } } ``` ### 🌳 树节点数据结构(关键) ```java public class TreeNode { private String id; // 对应 combotree 的 valueField private String text; // 对应 combotree 的 textField private boolean checked; // 选中状态 private List<TreeNode> children; // 子节点 // Getters 和 Setters (必须) } ``` ### 🚀 前端优化建议(参考引用[1][5]) ```javascript $('#surveyind').combotree({ valueField: 'id', textField: 'text', url: '/survey/tree', // 动态加载数据 queryParams: { selected: getPreSelectedIds() // 传入需要选中的ID }, onLoadSuccess: function() { // 确保选中状态生效 $(this).combotree('setValues', getPreSelectedIds()); } }); ``` ### ⚙️ 配套工具方法 ```java // 防止JSON序列化问题(参考引用[3]) public static String toSafeJson(Object obj) { return new GsonBuilder() .serializeNulls() .disableHtmlEscaping() .create() .toJson(obj); } // JSP中使用(参考引用[4]) <script> const preSelected = [${selectedIds}]; // EL表达式输出数组 function getPreSelectedIds() { return preSelected; } </script> ``` ### ✅ 验证要点 1. **数据结构验证**: ```json // 正确结构示例 [ { "id": "node1", "text": "Node 1", "checked": true, "children": [ {"id": "node1_1", "text": "Child 1", "checked": false} ] } ] ``` 2. **特殊字符处理**:确保文本字段中的 `"` 等字符被正确转义 3. **空数据处理**:对无子节点的分支返回 `children: []` 而非 `null` > **关键提示**:combotree 要求严格的树形结构,每个节点必须包含 `id` 和 `text` 属性,选中状态由 `checked` 属性控制[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值