JSF best Way to pass parameters

女生的网名这么多〃 提交于 2021-02-19 05:23:41

问题


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.


回答1:


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:

  • Communication in JSF 2



回答2:


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...



来源:https://stackoverflow.com/questions/13362897/jsf-best-way-to-pass-parameters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!