I have a sample project configured with JAAS, JSF-2 and Primefaces. Here is my web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>JAASProject</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>start</param-value>
</context-param>
<context-param>
<param-name>primefaces.SUBMIT</param-name>
<param-value>partial</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>resources.application</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
<security-constraint>
<web-resource-collection>
<web-resource-name>Protected Area</web-resource-name>
<url-pattern>/app/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>adbADRealm</realm-name>
<form-login-config>
<form-login-page>/login.xhtml</form-login-page>
<form-error-page>/login.xhtml</form-error-page>
</form-login-config>
</login-config>
<security-role>
<role-name>*</role-name>
</security-role>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
</web-app>
I have set <session-timeout> for testing purpose. The welcome file index.jsp is:
<%
response.sendRedirect("app/home.xhtml");
%>
So that when I am browsing localhost:8080/JAASProject I am navigating to the login page, but the URL remains localhost:8080/JAASProject/app/home.xhtml. I guess it is desired. In login.xhtml I have:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Login</title>
</h:head>
<h:body>
<h:form>
<h:panelGrid columns="2" cellpadding="5">
<p:outputLabel value="Username" />
<p:inputText value="#{authenticationController.username}" required="true"/>
<p:outputLabel value="Password" />
<p:password value="#{authenticationController.password}" required="true"/>
<f:facet name="footer">
<p:commandButton id="loginButton" actionListener="#{authenticationController.login}" value="Login"/>
</f:facet>
</h:panelGrid>
</h:form>
</h:body>
</html>
And the AuthenticationController is:
package com.myself.jassproject.controller;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
#ManagedBean(name = "authenticationController")
#ViewScoped
public class AuthenticationController implements Serializable{
private static final long serialVersionUID = 7083052321396088714L;
private String originalURL;
private String username;
private String password;
public AuthenticationController() {
}
#PostConstruct
public void initialize() {
ExternalContext externalContext = getExternalContext();
originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);
if (originalURL == null) {
originalURL = externalContext.getRequestContextPath() + "/app/home.xhtml";
}
System.out.println(originalURL);
}
public void login(ActionEvent event){
System.out.println("==");
try {
getServletRequest().login(username, password);
getExternalContext().redirect(originalURL);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private ExternalContext getExternalContext() {
return getFacesContext().getExternalContext();
}
private FacesContext getFacesContext() {
return FacesContext.getCurrentInstance();
}
private HttpServletRequest getServletRequest() {
return (HttpServletRequest) getExternalContext().getRequest();
}
}
The authentication is working and I am getting navigated to the home. In home I have three buttons: one Primesfaces', one JSF's (non-ajax) and one JSF's (ajax-enabled).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>Home</title>
</h:head>
<h:body>
<h:form>
<p:commandButton value="Click me (Primefaces)" actionListener="#{homeController.doSomething}"/>
<h:commandButton value="Click me (JSF)" actionListener="#{homeController.doSomething}" />
<h:commandButton value="Click me (JSF - AJAX)" actionListener="#{homeController.doSomething}">
<f:ajax execute="#form"/>
</h:commandButton>
</h:form>
</h:body>
</html>
So far everything goes well untill now. When the session timeout occur and if I click on the Primefaces's button or the ajax enabled JSF's button it does nothing, neither any exception nor the actionListener get called; that is okay; but I am excepting that I would get navigated to the login page.
I can see a POST get fired if I click on the ajax enabled buttons by Firebugging but that is it. If I click on the JSF's button (non-ajax) I am navigating to the login page but not if I click on the other two.
Does JAAS works with AJAX POST? Is it an issue of my code? Am I missing something?
My configuration is:
Server - JBoss AS 7.1
Mojara - 2.1.7
Primefaces - 3.4.2
Related
I am using Spring Security 3.1.3.RELEASE in my maven pom because the book am reading is 2013 and that is what they used and have the following code snippets:
// AdminController
#Controller
#RequestMapping("/admin")
public class AdminController {
#RequestMapping(method=RequestMethod.POST, value="/movies")
#ResponseBody
public String createMovie(#RequestBody String movie) {
System.out.println("Adding movie!! "+movie);
return "created";
}
}
// LoginController
#Controller
#RequestMapping("")
public class LoginController {
#RequestMapping(method= {RequestMethod.GET, RequestMethod.POST}, value="/custom_login")
public String showLogin() {
return "login";
}
}
// web.xml
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext-security.xml</param-value>
</context-param>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>terrormovies</servlet-name>
<servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>terrormovies</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
// Spring security Config :: applicationContext-security.xml
<security:http auto-config="true">
<security:intercept-url pattern="/admin/**/*" access="ROLE_ADMIN" />
<security:form-login login-page="/custom_login" username-parameter="user_param" password-parameter="pass_param"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user authorities="ROLE_ADMIN" name="admin" password="admin" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
//login.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Terror movies</title>
</head>
<body>
<form action="/j_spring_security_check" method="POST">
Username<input type="text" name="user_param"/><br/>
Password<input type="password" name="pass_param"/><br/>
<input type="submit" value="Login"/>
</form>
</body>
<% if(request.getParameter("error") != null){
out.println("ERROR LOGIN");
}
%>
</html>
When I start my application I get the login page with the form alright. I enter admin/admin as username/password respectively. When i click on the login button I get this error page saying:
Problem accessing /admin/movies. Reason:
Request method 'GET' not supported
Powered by Jetty://
instead of going to the method createMovie(#RequestBody String movie) in the
AdminController.
The address of this error page is :: http://localhost:8080/admin/movies
The LoginController and AdminController are in the same package.
What am I missing here?
Updated
In the form action:: <form action="/j_spring_security_check" method="POST">,
where does "/j_spring_security_check"` leads to? I think that is where the problem is. Am beginner in Spring Security so I can't figure it out now. I did a search but not any good answer.
The error response message you are receiving tells you exactly what the problem is:
When i click on the login button i get this error page saying::
Problem accessing /admin/movies. Reason:
Request method 'GET' not supported
Powered by Jetty://
And in your controller you have set this method:
#Controller
#RequestMapping("/admin")
public class AdminController {
#RequestMapping(method=RequestMethod.POST, value="/movies")
#ResponseBody
public String createMovie(#RequestBody String movie) {
System.out.println("Adding movie!! "+movie);
return "created";
}
}
And just as the message says, the /admin/movies method is mapped just for POST requests, so a GET request which is what is generated on redirection from the login success cannot be handled.
So here the trouble is not really the spring-security config, the problem is just that after login you are making a request to a request-mapping annotated method which does not support GET requests.
To solve it you could just configure this method into the existing AdminController:
#RequestMapping(method=RequestMethod.GET, value="/movies")
public String createMovieForm() {
return "createMovieForm";
}
And create a jsp with a form which points to the POST mapped controller method:
<form action="/admin/movies" method="POST">
Movie<input type="text" name="movie"/><br/>
<input type="submit" value="Login"/>
</form>
I would be easier too if you delete the #RequestBody annotation in the POST method, so finally the AdminController should end like this:
#Controller
#RequestMapping("/admin")
public class AdminController {
#RequestMapping(method=RequestMethod.POST, value="/movies")
#ResponseBody
public String createMovie(String movie) {
System.out.println("Adding movie!! "+movie);
return "created";
}
#RequestMapping(method=RequestMethod.GET, value="/movies")
public String createMovieForm() {
return "createMovieForm";
}
}
There are other questions about this but none of them solved my problem.
viewscope bean is instantiated(its constructor is called) whenever I refresh same page in browser.
here is xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">
<f:view contentType="text/html">
<h:head>
</h:head>
<h:body>
<h:form>
<h:dataTable value="#{products.list}" var="p" id="betDt1"
styleClass="tableSorter">
<h:column>
<f:facet name="header">name </f:facet>
#{p.pname}
</h:column>
</h:dataTable>
</h:form>
</h:body>
</f:view>
</html>
viewscoped bean:
import java.io.Serializable;
import java.util.List;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.hibernate.Session;
import model.Product;
#ViewScoped
#ManagedBean
public class Products implements Serializable {
private List<Product> list;
private Session ss;
#SuppressWarnings("unchecked")
public Products() {
this.ss = FaceUtils.openHibernateSession();
System.out.println("products constructor called");
ss.getTransaction().begin();
list = ss.createCriteria(Product.class).list();
this.ss.getTransaction().commit();
}
public List<Product> getList() {
return list;
}
public void setList(List<Product> list) {
this.list = list;
}
public String delete(Product pro) {
FaceUtils.log.finest("delete pro.id" + pro.getId());
FaceUtils.hibernateDelete(this.ss, pro);
list.remove(pro);
return null;
}
/**
*
*/
private static final long serialVersionUID = -2018425860394584424L;
}
And web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>fazlastoks</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>
index.xhtml
</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>org.omnifaces.FACES_VIEWS_SCAN_PATHS</param-name>
<param-value>/*.xhtml</param-value>
</context-param>
Any idea what may cause the problem?
I am currently building a prototype using PrimeFaces with reference from our current production-running Java web application (jsp - servlet - java). I have a minor problem with PrimeFaces' watermark component.
In the login.jsf there are two InputText components - "Username" and "Password". And there are 2 Watermark components for each of the InputText.
All was fine until I added filter in the web.xml. In the filter, it is specified that if the request URL is not "login.jsf"; and anything ending with ".js.jsf" and ".js"; and anything that contains ".css", ".png" and ".gif" to be verified if the user is logged in or not. If the user is not logged in, the filter will redirect to logout.jsf.
The logout.jsf is a simple page with a CommandLink to the login.jsf". By clicking the link, it brings the user to the login.jsf page but, the watermark is not displayed. But if the login.jsf is accessed directly by typing it in the browser address bar then the watermark does display.
I am scratching my head as to why the watermark does not display when I clicked on a link which brings me to the login.jsf. Is there any resources which I have blocked? or am I doing the filter wrong?
The libraries I am using are PrimeFaces 3.3.1, GlassFish 3.1.2.2, Java JDK 6u32.
login.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>PROFITEDI Login</title>
<h:outputStylesheet name="styles.css" library="css" />
</h:head>
<h:body>
<h:form id="frmLogin">
<p:panel styleClass="panelLogin">
<p:messages id="messages" autoUpdate="true" />
<f:facet name="header">
<h:outputText value="Login" />
</f:facet>
<h:panelGrid columns="2" cellpadding="5">
<p:inputText id="username" value="#{loginController.username}" required="true" />
<p:watermark for="username" value="User ID" />
<p:password id="password" value="#{loginController.password}" required="true" />
<p:watermark for="password" value="Password" />
<p:outputLabel value="Remember Me" for="rememberme" />
<p:selectBooleanCheckbox id="rememberme" value="#{loginController.rememberme}" />
</h:panelGrid>
<f:facet name="footer">
<h:panelGroup>
<p:commandButton id="btnReset" type="Reset" value="Reset" />
<p:spacer width="10" />
<p:commandButton id="btnLogin" type="Submit" value="Submit"
action="#{loginController.doLogin}" />
</h:panelGroup>
</f:facet>
</p:panel>
</h:form>
</h:body>
logout.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>PROFITEDI - Logout</title>
</h:head>
<h:body>
<h:form id="frmLogout">
You have been logged-out. Click here to <p:commandLink value="login" type="button" action="login" /> again.
</h:form>
</h:body>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- Context Param -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<!-- this is to treat empty fields as NULL instead of blank. -->
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
<!-- Servlet -->
<servlet>
<servlet-name>facesServlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<!-- Welcome file -->
<welcome-file-list>
<welcome-file>index.jsf</welcome-file>
</welcome-file-list>
<!-- Session Configuration -->
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<!-- Listener -->
<listener>
<listener-class>com.qrra.PROFIT.web.SessionListener</listener-class>
</listener>
<!-- URL Filter -->
<filter>
<filter-name>SecurityFilter</filter-name>
<filter-class>com.qrra.PROFIT.web.SecurityFilter</filter-class>
<init-param>
<param-name>PAGE_LOGIN</param-name>
<param-value>login.jsf</param-value>
</init-param>
<init-param>
<param-name>PAGE_LOGOUT</param-name>
<param-value>logout.jsf</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SecurityFilter</filter-name>
<url-pattern>*.jsf</url-pattern>
</filter-mapping>
SecurityFilter
package com.qrra.PROFIT.web;
import com.qrra.util.QRUtil;
import java.io.IOException;
import javax.ejb.EJB;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qrcom.webedi.ejb.AduserFacade;
import qrcom.webedi.jpa.Aduser;
/**
*
* #author Alvin Sim
*/
public class SecurityFilter extends GenericFilter {
// Actions ---------------------------------------------------------------------------------------------------------
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest;
HttpServletResponse httpServletResponse;
String pageLogin;
String pageLogout;
String requestUrl;
if (request instanceof HttpServletRequest) {
httpServletRequest = (HttpServletRequest) request;
httpServletResponse = (HttpServletResponse) response;
pageLogin = (String) httpServletRequest.getAttribute("PAGE_LOGIN");
pageLogout = (String) httpServletRequest.getAttribute("PAGE_LOGOUT");
requestUrl = (String) httpServletRequest.getRequestURI();
if (QRUtil.isStringEmpty(pageLogin)) {
pageLogin = "/login.jsf";
}
if (QRUtil.isStringEmpty(pageLogout)) {
pageLogout = "/logout.jsf";
}
// logger.debug("requested URL: {}", requestUrl);
if (requestUrl.endsWith(pageLogin) == false && requestUrl.endsWith(".js.jsf") == false
&& requestUrl.contains(".css") == false && requestUrl.contains(".gif") == false
&& requestUrl.contains(".png") == false && requestUrl.endsWith(".js") == false) {
logger.debug("URL blocked: {}", requestUrl);
if (verifyUser(httpServletRequest, httpServletResponse) == false) {
gotoLogoutPage(httpServletRequest, httpServletResponse, pageLogout);
}
}
}
chain.doFilter(request, response);
}
private void gotoLogoutPage(HttpServletRequest request, HttpServletResponse response, String pageLogout)
throws IOException, ServletException {
RequestDispatcher dispatcher = request.getSession().getServletContext().getRequestDispatcher(pageLogout);
dispatcher.forward(request, response);
}
private boolean verifyUser(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
Aduser aduser = (Aduser) request.getSession().getAttribute("aduser");
if (aduser == null || QRUtil.isStringEmpty(aduser.getUsrId()) == false
|| request.isRequestedSessionIdValid() == false) {
logger.debug("Invalid user session. Proceed to logout user {}.", (aduser == null) ? "" : aduser.getUsrId());
return false;
}
else {
return true;
}
}
// Services --------------------------------------------------------------------------------------------------------
#EJB
private AduserFacade aduserFacade;
// Constants -------------------------------------------------------------------------------------------------------
private final Logger logger = LoggerFactory.getLogger(SecurityFilter.class);
}
GenericFilter
package com.qrra.PROFIT.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
*
* #author Alvin Sim
*/
public class GenericFilter implements Filter {
#Override
public void destroy() {
this.filterConfig = null;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
protected FilterConfig filterConfig = null;
}
I managed to find a fix for this. It's not actually the filter's fault, but the CommandLink at the logout.jsf. As I was debugging, I saw that upon clicking on the login link, I was getting JavaScript errors in jquery.js.jsf?ln=primefaces. There were few objects which were undefined. So I tried to set the CommandLink's ajax attribute to "false" and it worked.
Why? I am not too sure.
This question already has answers here:
Identifying and solving javax.el.PropertyNotFoundException: Target Unreachable
(18 answers)
Closed 7 years ago.
I want to create a simple Book Management in JSF. I am using Glashfish Server 3.1
Book Controller:
#Named(value = "bookController")
#SessionScoped
public class BookController implements Serializable {
#EJB
BookFacadeLocal bookFacade;
Book book = new Book();
private List<Book> booklist = new LinkedList<Book> ();
/** Creates a new instance of BookController */
public BookController() {
}
public Book getBook() {
if (book == null)
book = new Book();
return book;
}
public void setBook(Book book) {
this.book = book;
}
public List<Book> getBooklist() {
return booklist;
}
public void setBooklist(List<Book> booklist) {
this.booklist = booklist;
}
public String createNewBook()
{
setBook(new Book());
return "createBook";
}
public String saveNewBook()
{
bookFacade.create(book);
booklist=bookFacade.findAll();
return "listBooks";
}
public String createBookList()
{
booklist=bookFacade.findAll();
return "listBooks";
}
}
CreateBook View:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<title>Facelet Title</title>
</h:head>
<h:body>
Create Book
<h:form id="createBook">
<h:panelGrid id="grid" columns="2" >
<h:outputLabel value="Title" for="title"></h:outputLabel>
<h:inputText id="title" value="#{bookController.book.title}"></h:inputText>
<h:outputLabel value="Price" for="price"></h:outputLabel>
<h:inputText id="price" value="#{bookController.book.price}"></h:inputText>
<h:outputLabel value="Description" for="description"></h:outputLabel>
<h:inputTextarea id="description" value="#{bookController.book.description}"></h:inputTextarea>
<h:outputLabel value="ISBN" for="isbn"></h:outputLabel>
<h:inputText id="isbn" value="#{bookController.book.isbn}"></h:inputText>
<h:outputLabel value="Pages" for="pages"></h:outputLabel>
<h:inputText id="pages" value="#{bookController.book.nbOfPage}"></h:inputText>
<h:outputLabel value="Illustration" for="illustrations"></h:outputLabel>
<h:selectBooleanCheckbox id="illustrations" value="#{bookController.book.illustrations}"> </h:selectBooleanCheckbox>
<h:panelGroup> </h:panelGroup>
<h:commandButton id="submit" value ="Save" action="#{bookController.saveNewBook}"> </h:commandButton>
</h:panelGrid>
</h:form>
</h:body>
</html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
</web-app>
BookController: #{bookController} --> BookController: at.em.controller.BookController#107dd383
Error:
/createBook.xhtml #13,82 value="#{bookController.book.title}": Target
Unreachable, 'null' returned null
/createBook.xhtml #13,82 value="#{bookController.book.title}": Target Unreachable, 'null' returned null
The #{bookController} is not available anywhere in the scope. This is normally the responsibility of #Named annotation. This annotation will only be scanned on webapp's startup when there's a /WEB-INF/beans.xml file present. So make sure that that file is present (it can be kept empty).
Alternatively, you can also just use the standard JSF annotations:
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
#ManagedBean
#ViewScoped
public class BookController {
// ...
}
(note that I didn't use javax.faces.bean.SessionScoped because that's the wrong scope for a normal controller; if it was used, the same bean instance would be shared among multiple browser tabs/windows in the same session which would only lead to unintuitive webapp behaviour)
We're working on our first JSF project, and we have some problems. We are making the login functionality, and when we hit the login button, it throws:
an IllegalArgumentException - null
source
a NullPointerException -
Servlet.service() for servlet [Faces
Servlet] in context with path
[/jsf-blank] threw exception
Do you have any idea why it's not working? Please enlighten us.
Here is out User bean:
public class User
{
private long id;
private String username;
private String password;
public User()
{
}
public User(String username, String password)
{
this.username = username;
this.password = password;
}
public User(long id, String username, String password)
{
super();
this.id = id;
this.username = username;
this.password = password;
}
public String getNextPage()
{
return "failure"; //or "admin" or "client"
}
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getUsername()
{
return username;
}
public String getPassword()
{
return password;
}
public void setUsername(String username)
{
this.username = username;
}
public void setPassword(String password)
{
this.password = password;
}
}
Our login.jsp page:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%# taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Login</title>
</head>
<body>
<f:view>
<h:form>
Username: <h:inputText value="#{userBean.username}"></h:inputText>
<br />
Password: <h:inputText value="#{userBean.password}"></h:inputText>
<br />
<h:commandButton value="Login" action="#{userBean.getNextPage}" ></h:commandButton>
</h:form>
</f:view>
</body>
</html>
Our faces-config.xml:
<?xml version="1.0"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<managed-bean>
<managed-bean-name>userBean</managed-bean-name>
<managed-bean-class>data_layer.model.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-action>#{userBean.getNextPage}</from-action>
<from-outcome>admin</from-outcome>
<to-view-id>/admin.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{userBean.getNextPage}</from-action>
<from-outcome>failure</from-outcome>
<to-view-id>/failure.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-action>#{userBean.getNextPage}</from-action>
<from-outcome>client</from-outcome>
<to-view-id>/client.jsp</to-view-id>
</navigation-case>
</navigation-rule>
</faces-config>
Our web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<!-- <welcome-file>index.html</welcome-file> -->
</welcome-file-list>
</web-app>
And our directory structure is:
You're intermixing JSF 1.x and JSF 2.x approaches. Maybe you're reading from an outdated book/tutorial which is targeted on JSF 1.x while the IDE is autogenerating JSF 2.x stuff?
JSF 2.0 doesn't support JSP by default anymore. The legacy JSP has been succeeded by Facelets which offers far more superior templating capabilities. Although you can configure JSF 2.0 to use the vintage JSP again, I strongly recommend to not do so. Rather rewrite login.jsp to login.xhtml:
<!DOCTYPE html>
<html lang="en"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Login</title>
</head>
<body>
<h:form>
Username: <h:inputText value="#{userBean.username}" />
<br />
Password: <h:inputText value="#{userBean.password}" />
<br />
<h:commandButton value="Login" action="#{userBean.getNextPage}" />
</h:form>
</body>
Unrelated to the problem, with JSF 2.0 you can also get rid of the whole faces-config.xml as you currently have. Add the following javax.faces.bean annotations to the User class:
#ManagedBean(name="userBean")
#RequestScoped
public class User {
// ...
}
With the new implicit navigation, the outcome will be by default treated as filename of the view. You've already done it fine, so you don't need those navigation rules at all.