2

i'm currently working with JSF, but since i'm a old and grouchy php-dev i always mess up with the GET-Parameters of an request. (In PHP you can access the request Paramerts whenever you want, using the $_GET["paramname"] Array.

Now, i'm working on an User Managment System. (CRUD) Usually i go with a list of all available users, having options like edit / delete. The edit link is then pointing to http:\\localhost\editUser.xhtml?userId=5 for example.

I have also an Controller called UserEditController which basically holds the user entity and invokes the update.

So, inside this Controller I'm using the @PostConstruct Annotation to load the user with the id 5 from the DataService and store it inside a property.

Problem here is: Wenn entering PostConstruct-Method in the APPLY_REQUEST_VALUES-Phase im not able to access the request Parameter Map of Faces Context (Will return null for userId)

Controller (simplified):

@Named @RequestScoped UserEditController{ @Inject private UserDataService userDataService; private User currentUser; @PostConstruct public void initValues(){ String id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("userId"); this.currentUser = userDataService.getUserById(id); } public String saveCurrentUser(){ userDataService.updateUser(this.currentUser); return "userManagement"; //return to overview after saving } //getter and setter } 

This works as intened. All the Form-Fields now are bound to user's properties like #{userEditController.currentUser.forename} etc.

I now added a save button with action attribute {userEditController.saveCurrentUser()}

However the script then enters the APPLY_REQUEST_VALUES-Phase And the UserEditController's initValues is called again.

  • this results in a nullpointer Exception, when trying to access the RequestParameterMap
  • and obviously i dont want to reload the user BEFORE saving it :-)

This sounds like a stupid question but i think i'm messing up between the PHP-Style and the JSF-Style to handle things.

Any Help would be appreciated.

2 Answers 2

3

The common way to pass the user (or userID) to your BackingBean, is using one of the following options:

http://www.mkyong.com/jsf2/4-ways-to-pass-parameter-from-jsf-page-to-backing-bean/

I think the main problem is that your bean is @RequestScoped. If you push the save button on your edit-page you are sending a new request, so a new instance of a request scoped bean will be created. Just change your bean to @ViewScoped.

More info:

Sign up to request clarification or add additional context in comments.

1 Comment

In the mean time i managed to solve it, using a ConversationScoped bean and conversation.begin() when setting the user to edit, along with conversation.end() when saving the user. Your post pointed me in the right direction, so i rate it up even if it's not "the solution".
0

I tried to change it to ViewScoped but then its ending up with "calling the constructor" for the bean everytime i access a property...

Meanwhile i tried a lot of things, nothing worked as expected:

The ONLY case where i can get it to work is setting the Controllers to "SessionScoped". But i don't think this is a good approach since i would need to take care of "cleaning" values and cause a lot of unneded (initialized) beans...

I've created a simple Project to play arround. Heres the Session Scoped Version that is working. But if i change the scope, i would need to "reload" the current user when hitting the save button. And without access to request parameters i have no clue, how to achieve that.

(i tried passing the users id again with the "form", but then i have problems to pass the id "for the first time")

Heres my sample. (Getter and Setter are available and not mentioned to keep it short)

User-Class:

public class User { private String firstname; private String lastname; public User (String f, String l){ this.firstname = f; this.lastname = l; } } 

DBSimulator:

@Named("dbSimulator") @SessionScoped public class DBSimulator implements Serializable { /** * */ private static final long serialVersionUID = 659826879566280911L; private Map<String, User> data; public DBSimulator() { //Load data User u1 = new User("Mickey", "Maus"); User u2 = new User("Peter", "Pan"); this.data = new HashMap<String, User>(); this.data.put("Mickey", u2); this.data.put("Max", u1); } public List<User> getUserList(){ List<User> l = new LinkedList<User>(); for (Map.Entry<String, User> user : data.entrySet()) { l.add(user.getValue()); } return l; } public void saveUser(User user){ this.data.put(user.getFirstname(), user); } } 

UserManagement-Controller:

@Named @SessionScoped public class UserManagementController implements Serializable { /** * */ private static final long serialVersionUID = -4300851229329827994L; @Inject private DBSimulator dbSimulator; private List<User> users; public UserManagementController() { System.out.println("UserManagementController:construct()"); } @PostConstruct public void LoadUsers(){ this.setUsers(this.dbSimulator.getUserList()); } } 

UserEdit Controller

@Named @SessionScoped public class UserEditController implements Serializable{ /** * */ private static final long serialVersionUID = 1867483972880755108L; @Inject private DBSimulator dbSimulator; private User user; public UserEditController() { System.out.println("UserEditController:construct()"); } public String activateUser(User user){ this.setUser(user); System.out.println("setting User"); return "userEdit"; } public String save(){ //Save user this.dbSimulator.saveUser(user); return "userManagement"; } } 

and finaly both XHTML files: UserManagement.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <title>Test</title> </h:head> <h:body> <h:outputText value="Select user to edit." /> <h:dataTable value="#{userManagementController.users}" var="user"> <h:column> <f:facet name="header">Firstname</f:facet> <h:outputText value="#{user.firstname}" /> </h:column> <h:column> <f:facet name="header">Lastname</f:facet> <h:outputText value="#{user.lastname}" /> </h:column> <h:column> <f:facet name="header">Options</f:facet> <h:form> <h:commandLink action="userEdit" actionListener="#{userEditController.activateUser(user)}" value="edit user" /> </h:form> </h:column> </h:dataTable> </h:body> </html> 

UserEdit.xhtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core"> <h:head> <title>Test</title> </h:head> <h:body> <h:form> <h:inputText value="#{userEditController.user.firstname}"></h:inputText> <br /><br /> <h:inputText value="#{userEditController.user.lastname}"></h:inputText> <br /><br /> <h:commandButton value="save" action="#{userEditController.save}"></h:commandButton> </h:form> </h:body> </html> 

ps.: I don't want anyone to "correct" my code - but maybe with the complete example somebody is able to see, where my headeck comes from :)

Working with ViewScoped Beans generates the following console Output:

[pageload] 12:07:49,126 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:07:49,334 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:07:49,341 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() [edit click] 12:08:35,410 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,411 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,412 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,413 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,414 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,414 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,415 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,416 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,416 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,417 INFO [stdout] (http--0.0.0.0-8090-3) UserManagementController:construct() 12:08:35,476 INFO [stdout] (http--0.0.0.0-8090-3) UserEditController:construct() 12:08:35,478 INFO [stdout] (http--0.0.0.0-8090-3) setting User 12:08:35,494 INFO [stdout] (http--0.0.0.0-8090-3) UserEditController:construct() 12:08:35,497 INFO [stdout] (http--0.0.0.0-8090-3) UserEditController:construct() 

And obviously the user is not set anymore, because the (ViewScoped) UserEditController has been reconstructed twice after setting the user...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.