Servlet与JSF连接空指针问题求助及JavaEE书籍推荐
排查NullPointerException问题&JavaEE书籍推荐
一、NullPointerException原因分析与解决
你遇到的NPE是因为Servlet从Session中获取section_Model实例时拿到了null,咱们一步步拆解问题根源和修复步骤:
1. Managed Bean的致命冗余代码
你的Section_Model里自己注入了自己:
@Inject private Section_Model section_Model;
这完全是多余的操作,还会引发循环依赖问题,直接删掉这行代码即可。
2. 核心问题:JSF Bean未被初始化
你在JSF页面里用了普通的HTML <form>提交到Servlet,而非JSF原生的<h:form>:
<form action="inputSections" method="post">
普通HTML表单提交不会触发JSF的生命周期流程,导致你的@SessionScoped注解的Section_Model根本没被创建,Session里自然没有这个属性,Servlet获取时就会得到null,调用sm.getSection()时直接抛出NPE。
修复方案二选一:
方案A:改用JSF表单处理提交(推荐,符合JSF架构设计)
把普通HTML表单替换成JSF组件,让JSF自动管理Bean的生命周期:
<h:form> <h:inputText value="#{section_Model.section.nameAlias}" required="true" requiredMessage="The NameAlias field is required."/> <h:inputText value="#{section_Model.section.codeSS}"/> <h:inputText value="#{section_Model.section.visible}"/> <h:commandButton value="Ok" action="#{section_Model.create}"/> </h:form>
点击按钮时,JSF会自动初始化Section_Model并存入Session,之后如果需要跳转页面,可以在create()方法里返回导航字符串,比如return "testJSF?faces-redirect=true";,完全不需要再用Servlet处理提交逻辑。
方案B:Servlet中手动初始化Bean(不推荐,破坏JSF架构)
如果一定要保留Servlet处理提交,需要在Servlet中先检查Session里的Bean是否存在,不存在则手动创建并放入Session:
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("---------------------Begin-----------------------------------------------"); try { HttpSession session = request.getSession(); Section_Model sm = (Section_Model) session.getAttribute("section_Model"); // 若Bean不存在,手动创建并放入Session if (sm == null) { sm = new Section_Model(); session.setAttribute("section_Model", sm); } // 处理参数时增加非空判断,避免NumberFormatException sm.getSection().setNameAlias(request.getParameter("nameAlias")); String codeSSParam = request.getParameter("codeSS"); if (codeSSParam != null && !codeSSParam.isEmpty()) { sm.getSection().setCodeSS((Sections) sm.findSpecific(Integer.parseInt(codeSSParam))); } String visibleParam = request.getParameter("visible"); sm.getSection().setVisible(visibleParam != null && Boolean.parseBoolean(visibleParam)); sm.create(); request.getRequestDispatcher("WEB-INF/testJSF.xhtml").forward(request, response); } catch (Exception ex) { Logger.getLogger(inputSections.class.getName()).log(Level.SEVERE, null, ex); } }
但这个方案会失去CDI自动注入(比如@Inject、@EJB)的优势,需要手动处理依赖,非常繁琐,所以优先推荐方案A。
3. 其他优化建议
- 用
@PostConstruct代替手动调用init():
给init()方法加上@PostConstruct注解,这样Bean初始化时会自动执行该方法,无需每次调用create()都手动初始化:@PostConstruct public void init(){ controller=new SectionsJpaController(utx, em.getEntityManagerFactory()); } - 统一持久层方式:你的Bean里同时用了
SectionsFacadeLocal(EJB)和SectionsJpaController,建议选一种方式实现数据库操作,避免代码混乱。比如直接用EJB的sectionsFacade,删掉JpaController相关代码。
二、深入JavaEE书籍推荐
结合你做电商页面、使用JSF搭建分层架构的需求,推荐几本实用的书籍:
- 《Java EE 8实战》:覆盖Java EE全栈核心技术(JSF、EJB、JPA、CDI等),实战案例丰富,能帮你系统掌握JavaEE,对电商这类企业级应用的架构设计也有参考价值。
- 《Pro JSF 2.2 and Java EE 8》:专门针对JSF的深入书籍,从基础到高级特性(复合组件、AJAX、CDI集成等)讲解透彻,适合想要精通JSF开发的你。
- 《Head First Servlets & JSP》:虽然版本稍旧,但对Servlet、JSP的底层原理和基础概念讲解生动易懂,能帮你巩固JavaEE基础,也涉及JSF的入门内容。
内容的提问来源于stack exchange,提问作者Hers
相关产品推荐
相关产品推荐

