从test.jsp到test_jsp.java(文件分析)

本文介绍了一个具体的JSP页面实现方式,该页面通过继承HttpJspBase类并实现JspSourceDependent接口,处理请求和响应。文章展示了如何使用静态初始化块来管理依赖项,并详细解释了_jspService方法的工作原理。
test_jsp.java中源码:
这个类是final类继承了org.apache.jasper.runtime.HttpJspBase类,实现了org.apache.jasper.runtime.JspSourceDependent接口
public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent
   
如果在jsp中有"include"语句,则会在java中用静态初始化块来创建Vector,并添加数据。
例如:
  private static java.util.Vector _jspx_dependants;

  static {
    _jspx_dependants = new java.util.Vector(1);
    _jspx_dependants.add("/test/../../common/commheader.jsp");
  }

  public java.util.List getDependants() {
    return _jspx_dependants;
  }

方法_jspService用来处理request及给出回应response
public void _jspService(HttpServletRequest request, HttpServletResponse response)
        throws java.io.IOException, ServletException

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import com.midi.VendorActionEntrance;
import com.midi.IVendorConstants;

public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
    
implements org.apache.jasper.runtime.JspSourceDependent {

  
private static java.util.Vector _jspx_dependants;

  
static {
    _jspx_dependants 
= new java.util.Vector(1);
    _jspx_dependants.add(
"/caraudit/jsp/biz/warehouse/../../common/commheader.jsp");
  }


  
public java.util.List getDependants() {
    
return _jspx_dependants;
  }


  
public void _jspService(HttpServletRequest request, HttpServletResponse response)
        
throws java.io.IOException, ServletException {

    JspFactory _jspxFactory 
= null;
    PageContext pageContext 
= null;
    HttpSession session 
= null;
    ServletContext application 
= null;
    ServletConfig config 
= null;
    JspWriter out 
= null;
    Object page 
= this;
    JspWriter _jspx_out 
= null;


    
try {
      _jspxFactory 
= JspFactory.getDefaultFactory();
      response.setContentType(
"text/html;charset=gb2312");
      pageContext 
= _jspxFactory.getPageContext(this, request, response,
                  
nulltrue8192true);
      application 
= pageContext.getServletContext();
      config 
= pageContext.getServletConfig();
      session 
= pageContext.getSession();
      out 
= pageContext.getOut();
      _jspx_out 
= out;

      out.write(
" ");
    
    response.setHeader(
"Cache-Control","no-store"); //HTTP 1.1 
    response.setHeader("Pragma","no-cache"); //HTTP 1.0 
    response.setDateHeader ("Expires"0); //prevents caching at the proxy server 

      out.write(
" ");
      out.write(
' ');
      out.write(
' ');
    String strUrl 
= (String) request.getParameter("srcUrl");
    VendorActionEntrance vae 
= new VendorActionEntrance();
    vae.doPost(request, response);            
    
    Integer iAf 
= (Integer) request.getAttribute(IVendorConstants.AFFECTEDROW);
    
if (iAf.intValue() == -1{
        response.sendRedirect(
"../../common/error.jsp");
        
return;
    }


      out.write(
"   <html>   <head>     <title>test.jsp</title>    </head>     <body>test   </body> </html> ");
    }
 catch (Throwable t) {
      
if (!(t instanceof SkipPageException)){
        out 
= _jspx_out;
        
if (out != null && out.getBufferSize() != 0)
          out.clearBuffer();
        
if (pageContext != null) pageContext.handlePageException(t);
      }

    }
 finally {
      
if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
    }

  }

}

 
 
<think> 我们遇到了一个NullPointerException,发生在自定义标签`webpagination_tag`的第82行。 根据堆栈跟踪,这个标签在`processAreaList.jsp`页面中被调用。 问题分析: 1. 空指针异常发生在`webpagination_tag`标签的第82行。 2. 可能的原因: a. 标签的某个属性没有被正确设置(例如,从JSP页面传递过来的值为null)。 b. 标签内部处理时,没有对可能为null的对象进行判断。 解决方案: 1. 定位到`webpagination_tag`标签的第82行,查看具体代码,分析哪个变量为null。 2. 检查在JSP页面中使用该标签时,所有必需的属性是否都已正确传递且非空。 假设在`webpagination_tag`的第82行代码是: ```java int totalPages = (Integer) pageContext.findAttribute("totalPages"); ``` 如果`totalPages`属性不存在,则`pageContext.findAttribute`返回null,然后赋给int类型时就会抛出NullPointerException。 修复步骤: 1. 在标签代码中,确保对从页面获取的属性进行空值检查。 2.JSP页面中,确保传递给标签的属性值不为空。 具体代码修复示例: 原标签代码(有问题的部分): ```java // 假设第82行是: int totalPages = (Integer) pageContext.findAttribute("totalPages"); ``` 修复后: ```java Object totalPagesAttr = pageContext.findAttribute("totalPages"); if (totalPagesAttr == null) { throw new JspTagException("totalPages attribute is required"); } int totalPages = (Integer) totalPagesAttr; ``` 或者,我们可以设置一个默认值(根据业务需求): ```java int totalPages = 0; if (totalPagesAttr != null) { totalPages = (Integer) totalPagesAttr; } ``` 另外,在JSP页面中调用标签时,确保传递了`totalPages`属性,并且不为null: ```jsp <tags:pagination totalPages="${page.totalPages}" ... /> ``` 其中,`${page.totalPages}`是EL表达式,确保`page`对象和其`totalPages`属性在模型中存在且不为空。 如何确保后台传递了page对象? 在控制器中: ```java @GetMapping("/list") public String list(@RequestParam(defaultValue="0") int page, Model model) { Page<ProcessArea> pageResult = processAreaService.getProcessAreas(page, 10); model.addAttribute("page", pageResult); return "bsif/processArea/processAreaList"; } ``` 如果问题仍然存在,可以在JSP页面中临时打印属性值,以确认`totalPages`是否存在: ```jsp <c:out value="totalPages: ${page.totalPages}" /> ``` 自定义标签的完整修复示例: 假设我们的标签类为`WebPaginationTag`,修复后的代码片段如下: ```java public class WebPaginationTag extends SimpleTagSupport { // ... 其他属性和方法 ... @Override public void doTag() throws JspException, IOException { PageContext pageContext = (PageContext) getJspContext(); // 获取totalPages属性,并检查空值 Object totalPagesAttr = pageContext.findAttribute("totalPages"); if (totalPagesAttr == null) { throw new JspException("The attribute 'totalPages' is required."); } int totalPages = (Integer) totalPagesAttr; // 同样的方式处理其他属性,如currentPage等 // 然后进行分页渲染 // ... 其他代码 ... } } ``` 另外,也要检查其他属性(如currentPage)是否可能为null,并进行类似的空值处理。 为了防止在JSP页面中忘记传递必需的属性,可以在标签的TLD文件中设置`<required>true</required>`: ```xml <tag> <name>pagination</name> <tag-class>com.example.tags.WebPaginationTag</tag-class> <body-content>empty</body-content> <attribute> <name>totalPages</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <!-- 其他属性设置 --> </tag> ``` 总结: - 根本原因是标签内部代码没有对从页面上下文获取的属性进行空值检查。 - 修复方法是添加空值检查,并提供有意义的错误信息或合理的默认值。 - 同时确保在JSP页面中正确传递了所有必需的属性。 §§相关问题§§: 1. 如何编写自定义的JSP标签? 2. 在Spring MVC中如何实现分页功能? 3. 如何优雅地处理JSP页面中的空指针异常? 4. 自定义标签与JSTL标签相比有哪些优势和劣势? </think> ### JSP自定义标签空指针异常分析与解决方案 #### 问题深度分析 根据堆栈跟踪信息: ``` java.lang.NullPointerException at org.apache.jsp.tag.webpagination_tag.doTag(webpagination_tag.java:82) at org.apache.jsp.WEB_002dINF.views.bsif.processArea.processAreaList_jsp._jspx_meth_tags_005fpagination_005f0(processAreaList_jsp.java:632) ``` 关键问题: 1. **空指针异常**:发生在自定义标签 `webpagination_tag` 的第82行 2. **调用位置**:在 `processAreaList.jsp` 页面中使用分页标签时发生 3. **常见原因**: - 自定义标签依赖的参数未正确传递 - 标签内部逻辑未处理空值情况 - EL表达式引用了不存在的数据 - Spring模型属性未正确设置 #### 完整解决方案 ##### 1. 定位问题代码 在自定义标签类 `webpagination_tag.java` 中找到第82行: ```java // webpagination_tag.java 关键代码片段 public class WebPaginationTag extends SimpleTagSupport { private int totalPages; private int currentPage; @Override public void doTag() throws JspException, IOException { JspWriter out = getJspContext().getOut(); // 第82行附近 for (int i = 1; i <= totalPages; i++) { // 可能的第82行 if (i == currentPage) { out.print("<li class='active'><a href='#'>" + i + "</a></li>"); } else { out.print("<li><a href='?page=" + i + "'>" + i + "</a></li>"); } } } // 省略setter/getter } ``` ##### 2. 修复方案 ###### 方案1: 添加空值检查(标签内部) ```java public void doTag() throws JspException, IOException { // 添加空值检查 if (totalPages <= 0) { out.print("<div class='alert'>无分页数据</div>"); return; } for (int i = 1; i <= totalPages; i++) { // 添加currentPage有效性检查 if (currentPage < 1 || currentPage > totalPages) { currentPage = 1; // 重置为安全值 } // 原有逻辑... } } ``` ###### 方案2: 确保控制器正确设置模型属性 ```java @Controller @RequestMapping("/bsif/processArea") public class ProcessAreaController { @GetMapping("/list") public String list(@RequestParam(defaultValue = "1") int page, Model model) { Pageable pageable = PageRequest.of(page - 1, 10); Page<ProcessArea> result = repository.findAll(pageable); // 确保设置必要的分页属性 model.addAttribute("processAreas", result.getContent()); model.addAttribute("currentPage", page); model.addAttribute("totalPages", result.getTotalPages()); model.addAttribute("totalItems", result.getTotalElements()); return "bsif/processArea/processAreaList"; } } ``` ###### 方案3: JSP页面添加空值保护 在 `processAreaList.jsp` 中使用标签前添加判断: ```jsp <c:if test="${not empty totalPages and totalPages > 0}"> <tags:pagination totalPages="${totalPages}" currentPage="${currentPage}" totalItems="${totalItems}" /> </c:if> <c:if test="${empty totalPages or totalPages <= 0}"> <div class="no-data">暂无数据,无需分页</div> </c:if> ``` ###### 方案4: 增强自定义标签(推荐) 创建更健壮的分页标签: ```java public class SmartPaginationTag extends SimpleTagSupport { // 带默认值的属性 private int totalPages = 0; private int currentPage = 1; private String urlPattern = "?page=%d"; private String cssClass = "pagination"; @Override public void doTag() throws JspException, IOException { // 1. 空值和安全检查 if (totalPages <= 0 || currentPage < 1) { return; // 不渲染任何内容 } // 2. 修正currentPage范围 currentPage = Math.max(1, Math.min(currentPage, totalPages)); // 3. 安全渲染 JspWriter out = getJspContext().getOut(); out.print("<ul class=\"" + cssClass + "\">"); // 渲染页码... out.print("</ul>"); } // 省略setter } ``` ##### 5. 分页标签最佳实践 ```jsp <%-- 安全使用方式 --%> <tags:smart-pagination totalPages="${page.totalPages}" currentPage="${page.number + 1}" urlPattern="/bsif/processArea/list?page={page}" cssClass="pagination-lg" /> ``` #### 调试与预防措施 1. **启用详细日志**: ```java // 在logback.xml中添加 <logger name="org.apache.jsp" level="TRACE"/> ``` 2. **单元测试自定义标签**: ```java @Test public void testPaginationTag() throws Exception { SmartPaginationTag tag = new SmartPaginationTag(); tag.setTotalPages(5); tag.setCurrentPage(3); StringWriter sw = new StringWriter(); tag.setJspContext(new MockJspContext(new MockJspWriter(sw))); tag.doTag(); assertTrue(sw.toString().contains("?page=3")); } ``` 3. **使用EL函数替代复杂标签**: ```jsp <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <c:set var="pagination" value="${fn:generatePagination(page.totalPages, page.number + 1)}" /> ${pagination} ``` #### Spring Data分页最佳实践 ```java // 实体类 @Entity public class ProcessArea { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String processAreaKey; // 其他字段... } // Repository public interface ProcessAreaRepository extends JpaRepository<ProcessArea, Long> { @Query("SELECT p FROM ProcessArea p") Page<ProcessArea> findAllPaginated(Pageable pageable); } // 控制器 @GetMapping public String list(@PageableDefault(size = 10, sort = "id") Pageable pageable, Model model) { Page<ProcessArea> page = repository.findAllPaginated(pageable); model.addAttribute("page", page); // 包含分页信息 return "processArea/list"; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值