<c:forEach>标签报isValid()==false错问题

博主遇到了关于JSTL标签的错误,并提及给出的图是正确写法,围绕JSTL标签的使用展开。

今天遇到了这样一个错,关于jstl标签的错误,上图是正确写法。


<%@ page contentType="text/html;charset=UTF-8"%> <%@ include file="/WEB-INF/include/adminCommon.jsp"%> <tags:wjs items="calendar.js"></tags:wjs> <body> <!-- 导航条区 --> <c:import url="/WEB-INF/views/admin/adminNavbar.jsp"></c:import> <div id="content"> <div class="container-fluid"> <div class="row-fluid"> <div class="span3"> <!-- 个人信息区 --> <c:import url="/WEB-INF/views/admin/adminInfo.jsp"></c:import> <hr /> <!-- 左侧菜单区 --> <c:import url="/WEB-INF/views/admin/adminLeft.jsp"></c:import> </div> <!-- /span3 --> <div class="span9"> <!--这里是操作完成的消息提示区 --> <c:import url="/WEB-INF/include/message.jsp"></c:import> <!-- 标题区 --> <ul class="breadcrumb"> <li>项目管理<span class="divider">/</span></li> <li><a href="${ctx}/processArea">过程域管理</a> <span class="divider">/</span></li> <li class="active">添加过程</li> </ul> <!-- 表单区 --> <form id="searchForm1" action="${ctx}/processArea/submitadd" method="post"> <div class="widget-header"> <i class="icon-plus"></i> <h3>添加过程</h3> </div> <!-- /widget-header --> <div class="widget-content" style="margin-bottom: 15px;"> <table style="width: 100%"> <tr> <td>过城域标识</td> <td><input type="text" id="txt_processAreaID" name="processAreaID" class="input-medium"></td> </tr> <tr> <tr> <td>过程名称</td> <td><input type="text" id="txt_processAreaName" name="processAreaName" class="input-medium"></td> </tr> <td>过程类型</td> <td> <select id="txt_processAreaType" name="processAreaType" style="width:160px;"> <option value="">--请选择--</option> <c:forEach items="${processAreaList }" var="processAreaType"> <option value="${processArea.processAreaKey }">${processArea.processAreaName }</option> </c:forEach> </select> </td> </tr> <tr> <td>简介</td> <td><textarea rows="10" cols="10" name="remark"></textarea> </td> </tr> <tr> <td align="right" colspan="4"><input class="btn" type="button" onclick="window.history.back(-1)" value="返回"> <input class="btn btn-primary" type="submit" value="确定"> </td> </tr> </table> </div> </form> </div> </div> <!-- /row --> </div> <!-- /container --> </div> <!-- /content --> <!-- 页脚区 --> <c:import url="/WEB-INF/views/admin/adminFooter.jsp"></c:import> </body> <!-- 表单校验区 --> <script type="text/javascript"> $(document).ready(function() { $("#searchForm1").validate({ rules : { processAreaName : { required : true, remote : { url : "${ctx}/processArea/processNameUnique", type : "post", dataType : "json", data : { systemName : function() { return $("#txt_processAreaName").val(); } } } }, processAreaID : { required: true, remote : { url : "${ctx}/processArea/processIDUnique", type : "post", dataType : "json", data : { systemID : function() { return $("#txt_processAreaID").val(); } } } } }, messages : { processAreaName : { remote : "该过程域名称已存在" }, processAreaID : { remote : "该过程标识已存在" } } }); }); </script>
最新发布
09-25
<think> 我们正在分析一个JSP页面,该页面用于添加过程域。问题出现在之前的异常堆栈中,指向了分页标签的空指针异常。但现在我们看到的页面是添加表单页面,与分页无关。因此,我们需要检查整个应用中的自定义标签使用情况,特别是分页标签是否在其他页面(如列表页面)中正确使用。 然而,当前提供的JSP代码是`processAreaList.jsp`(根据之前的异常)还是`添加过程`页面?根据代码中的标题和表单操作,这是添加过程域的页面(add页面),而不是列表页面。 但之前的异常发生在`processAreaList.jsp`的第119行,而我们现在看到的代码是添加页面。因此,我们需要确认问题是否已经转移到添加页面,或者我们是否在查看正确的文件。 根据当前代码,我们注意到以下几个可能的问题点: 1. 在过程类型的选择框中,使用了`${processAreaList }`进行循环,但循环变量为`processAreaType`,而选项的值和文本却是`${processArea.processAreaKey }`和`${processArea.processAreaName }`。这里明显有误,应该是`${processAreaType.processAreaKey}`和`${processAreaType.processAreaName}`吗?或者循环变量名应该是`processArea`?实际上,变量名不一致会导致无法获取到数据。 2. 另外,在过程类型选择框的选项中,`<c:forEach>`的items属性是`${processAreaList}`,而var属性是`processAreaType`,但在option中却使用`processArea`(未定义的变量)。这会导致空指针异常,因为`processArea`不存在。 3. 在JavaScript中,表单验证使用了`processAreaName`和`processAreaID`的远程验证,但远程验证的URL返回的数据类型是json,需要确保控制器返回正确的json格式(如{ "valid": true }或{ "valid": false })。 4. 在表单中,有一个输入框的id为`txt_processAreaID`,但在验证规则中,对于`processAreaID`的远程验证,从`#txt_processAreaID`取值。这里注意,HTML元素的id和name属性不同,但jQuery选择器使用id,所以这里没有问题。 具体问题修正: 对于过程类型选择框的问题误代码: ```jsp <c:forEach items="${processAreaList }" var="processAreaType"> <option value="${processArea.processAreaKey }">${processArea.processAreaName }</option> </c:forEach> ``` 这里应该使用`processAreaType`而不是`processArea`: ```jsp <c:forEach items="${processAreaList}" var="processAreaType"> <option value="${processAreaType.processAreaKey}">${processAreaType.processAreaName}</option> </c:forEach> ``` 或者,如果后台传递的列表中的每个元素就是过程域对象,并且属性名正确,那么修改循环变量名即可。 但是,我们注意到在循环中,我们使用的是`processAreaType`,但在option中却写成了`processArea`,这明显是笔误。 因此,修正后的代码: ```jsp <select id="txt_processAreaType" name="processAreaType" style="width:160px;"> <option value="">--请选择--</option> <c:forEach items="${processAreaList}" var="item"> <option value="${item.processAreaKey}">${item.processAreaName}</option> </c:forEach> </select> ``` 这里我将循环变量名改为`item`以避免混淆。 另外,我们还需要确保在控制器中,添加过程域的表单处理方法和进入添加页面方法都正确设置了`processAreaList`属性。 例如,在进入添加页面的控制器方法中: ```java @GetMapping("/add") public String showAddForm(Model model) { // 获取过程类型列表,注意这里应该是一个列表,用于下拉框 List<ProcessArea> processAreaList = processAreaService.getAllProcessAreaTypes(); model.addAttribute("processAreaList", processAreaList); return "bsif/processArea/processAreaAdd"; // 注意视图名称 } ``` 如果这个列表数据为空,则不会渲染任何选项,但不会导致空指针异常。如果`processAreaList`为null,则JSTL的forEach不会进入循环,也不会。 此外,在之前的异常中,分页标签的空指针异常应该是在列表页面(processAreaList.jsp)中发生的,而现在是添加页面,所以添加页面本身可能不会触发分页标签的异常。但我们需要确保列表页面中的分页标签问题已经按照之前的方案修复。 现在,针对当前添加页面的代码,我们还需要注意: 1. 表单验证的远程验证URL是否正确,以及后端是否实现了`/processArea/processNameUnique`和`/processArea/processIDUnique`接口,并返回json数据,如:`{ "valid": false }`或`{ "valid": true }`(根据jquery.validate的remote要求,返回true表示验证通过,返回false表示验证失败,也可以返回字符串作为误消息)。 2. 在远程验证中,我们传递的参数名是`systemName`和`systemID`,但后端可能需要的是`processAreaName`和`processAreaID`。这里参数名可能不匹配,需要调整。 修正参数名: ```javascript remote: { url: "${ctx}/processArea/processNameUnique", type: "post", dataType: "json", data: { processAreaName: function() { return $("#txt_processAreaName").val(); } } } ``` 同理,对于ID的远程验证: ```javascript remote: { url: "${ctx}/processArea/processIDUnique", type: "post", dataType: "json", data: { processAreaID: function() { return $("#txt_processAreaID").val(); } } } ``` 这样,后端接收的参数名就是`processAreaName`和`processAreaID`。 总结: 1. 修正选择框中的循环变量名。 2. 确保控制器为添加页面提供了`processAreaList`属性。 3. 修正远程验证的参数名。 4. 确保后端验证接口的实现。 下面给出一个后端验证接口的示例: ```java @PostMapping("/processNameUnique") @ResponseBody public Map<String, Boolean> checkProcessNameUnique(@RequestParam String processAreaName) { boolean exists = processAreaService.existsByProcessAreaName(processAreaName); // 返回的json中,key为"valid"表示是否通过验证,当不存在时为true(通过),存在时为false(不通过) return Collections.singletonMap("valid", !exists); } ``` 注意:jquery.validate的remote要求返回true表示验证通过(即该值可用),所以我们返回`!exists`。 同样的,对于ID的验证: ```java @PostMapping("/processIDUnique") @ResponseBody public Map<String, Boolean> checkProcessIDUnique(@RequestParam String processAreaID) { boolean exists = processAreaService.existsByProcessAreaID(processAreaID); return Collections.singletonMap("valid", !exists); } ``` 最后,注意在添加表单页面中,我们使用了`<form id="searchForm1">`,这个id可能不够语义化,建议改为`addForm`等。 由于问题描述中并没有具体的异常信息指向这个添加页面,所以以上修改是基于代码审查发现的问题。如果问题仍然存在,请检查日志以确定具体的异常位置。 另外,如果问题是在列表页面,那么我们需要回到列表页面进行修复,但当前提供的代码是添加页面。因此,我们假设问题已经被定位到添加页面,并且出现了上述问题。 如果问题不是发生在添加页面,那么请提供具体的异常信息。 由于问题描述有限,我们只能根据看到的代码进行修正。 最后,请确保在列表页面(processAreaList.jsp)中,我们已经按照之前的分页标签修复方案进行了修改(避免空指针)。 如果问题仍然存在,请提供最新的异常堆栈信息。 </think> ### JSP页面代码分析与问题诊断 您提供的JSP页面是一个添加过程域的表单页面,但存在几个关键问题需要修复。我将分析问题并提供完整的解决方案。 #### 主要问题分析 1. **过程类型下拉框误**: ```jsp <c:forEach items="${processAreaList }" var="processAreaType"> <option value="${processArea.processAreaKey }">${processArea.processAreaName }</option> </c:forEach> ``` - 循环变量是`processAreaType`但选项中使用的是`processArea` - 变量名不匹配导致选项为空 2. **表单验证问题**: ```javascript data : { systemName : function() { return $("#txt_processAreaName").val(); } } ``` - 后端期望`processAreaName`参数但发送的是`systemName` - 重复使用相同的参数名`systemName`和`systemID`导致冲突 3. **安全风险**: - 直接使用用户输入值而没有转义,存在XSS风险 - 表单提交没有CSRF保护 4. **用户体验问题**: - 缺少客户端实时验证反馈 - 表单字段没有必填标识 #### 完整修复方案 ##### 1. 修复过程类型下拉框 ```jsp <td>过程类型</td> <td> <select id="txt_processAreaType" name="processAreaType" class="input-medium"> <option value="">--请选择--</option> <c:forEach items="${processAreaTypes}" var="type"> <option value="${type.key}"> <c:out value="${type.name}"/> </option> </c:forEach> </select> </td> ``` **后端控制器示例**: ```java @GetMapping("/add") public String showAddForm(Model model) { // 获取过程类型数据 List<ProcessAreaType> types = processAreaService.getAllTypes(); model.addAttribute("processAreaTypes", types); // 添加空表单对象 model.addAttribute("processArea", new ProcessArea()); return "bsif/processArea/add"; } ``` ##### 2. 修复表单验证逻辑 ```javascript $(function() { $("#addForm").validate({ rules: { processAreaName: { required: true, maxlength: 50, remote: { url: "${ctx}/processArea/checkNameUnique", type: "post", data: { name: function() { return $("#txt_processAreaName").val(); } } } }, processAreaID: { required: true, pattern: /^[A-Z0-9_]+$/, // 仅允许大写字母、数字和下划线 remote: { url: "${ctx}/processArea/checkIdUnique", type: "post", data: { id: function() { return $("#txt_processAreaID").val(); } } } } }, messages: { processAreaName: { required: "过程名称不能为空", remote: "该名称已被使用" }, processAreaID: { required: "过程标识不能为空", pattern: "仅允许大写字母、数字和下划线", remote: "该标识已被使用" } }, errorPlacement: function(error, element) { error.appendTo(element.parent()); } }); }); ``` ##### 3. 添加CSRF保护和XSS防护 在Spring Security配置中启用CSRF: ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .and() // 其他配置... } } ``` 在JSP中添加CSRF令牌: ```jsp <form id="addForm" action="${ctx}/processArea/save" method="post"> <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> <!-- 表单内容 --> </form> ``` ##### 4. 增强表单结构和用户体验 ```jsp <div class="control-group"> <label class="control-label" for="txt_processAreaID"> <span class="required">*</span> 过程域标识 </label> <div class="controls"> <input type="text" id="txt_processAreaID" name="processAreaID" class="input-medium" required placeholder="请输入大写标识符"> <span class="help-inline"></span> </div> </div> <div class="control-group"> <label class="control-label" for="txt_processAreaName"> <span class="required">*</span> 过程名称 </label> <div class="controls"> <input type="text" id="txt_processAreaName" name="processAreaName" class="input-medium" required placeholder="请输入过程名称"> <span class="help-inline"></span> </div> </div> ``` #### 后端验证控制器实现 ```java @RestController @RequestMapping("/processArea") public class ProcessAreaValidationController { @Autowired private ProcessAreaService processAreaService; @PostMapping("/checkNameUnique") public ResponseEntity<Map<String, Boolean>> checkNameUnique( @RequestParam String name, @RequestParam(required = false) Long id) { boolean isUnique = processAreaService.isNameUnique(name, id); return ResponseEntity.ok(Collections.singletonMap("unique", isUnique)); } @PostMapping("/checkIdUnique") public ResponseEntity<Map<String, Boolean>> checkIdUnique( @RequestParam String id) { boolean isUnique = processAreaService.isIdentifierUnique(id); return ResponseEntity.ok(Collections.singletonMap("unique", isUnique)); } } ``` #### 最佳实践建议 1. **使用Spring表单标签库**: ```jsp <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> <form:form modelAttribute="processArea" id="addForm" action="${ctx}/processArea/save"> <form:input path="processAreaID" cssClass="input-medium"/> <form:errors path="processAreaID" cssClass="error"/> </form:form> ``` 2. **添加实时反馈**: ```javascript // 实时验证反馈 $(".input-medium").on("blur", function() { $(this).valid(); }); ``` 3. **表单提交处理**: ```javascript $("#addForm").submit(function(e) { e.preventDefault(); if($(this).valid()) { $.ajax({ url: $(this).attr("action"), type: "POST", data: $(this).serialize(), success: function(response) { if(response.success) { window.location.href = "${ctx}/processArea"; } else { showError(response.message); } } }); } }); ``` 4. **后端实体绑定**: ```java @PostMapping("/save") public String saveProcessArea(@Valid ProcessArea processArea, BindingResult result, RedirectAttributes redirectAttrs) { if (result.hasErrors()) { return "bsif/processArea/add"; } try { processAreaService.save(processArea); redirectAttrs.addFlashAttribute("success", "过程域添加成功"); return "redirect:/processArea"; } catch (DuplicateKeyException e) { result.rejectValue("processAreaID", "duplicate", "标识已存在"); return "bsif/processArea/add"; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值