Reputation: 803
I'm currently developing a web application in Java which will be accessed by multiple users at the same time and as such need to store userdata in order to tailor the application to their individual requirements (such as what company they are apart of etc).
There are 2 classes that i use to manage this. User, MainSystem detailed below:
User
@Entity
public class User implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String username;
private String password;
private String type;
private String company;
private String DOB;
private String email;
private int PayrollId;
public User(String firstName, String lastName, String username, String password, String type, String company, String DOB, String email) {
this.firstName = firstName;
this. lastName = lastName;
this.username = username;
this.password = password;
this.type = type;
this.company = company;
this.DOB = DOB;
this.email = email;
}
MainSystem:
public class MainSystem {
public UserController userController;
private UserRepository userRepository;
private static ThreadLocal<User> loggedInUser = new ThreadLocal<>();
public DbController dbController;
public MainSystem(){
userController = new UserController(userRepository);
loggedInUser.set(new User());
}
public Boolean Login(String username, String password) {
if(userController.checkUser(username,password)){
User aUser = userController.getUser(username);
setLoggedInUser(userController.getUser(username));
VaadinSession.getCurrent().setAttribute("username",loggedInUser.get().getUsername());
System.out.println("Logged in User: "+loggedInUser.get().getUsername());
return true;
}
else {
return false;
}
}
public static void setLoggedInUser(User user){
loggedInUser.set(user);
}
public static User getLoggedInUser() {
return loggedInUser.get();
}
Ideally what i'd like to do is access the ThreadLocal variable from another class, for instance the ViewProfile.View:
public class EditProfileView extends VerticalLayout implements View {
MainSystem main = new MainSystem();
NavigatorUI aUI = new NavigatorUI();
User aUser = main.getLoggedInUser();
TextField username = new TextField("Username");
TextField Id = new TextField("Id");
TextField email = new TextField("Email");
TextField firstName = new TextField("First name");
TextField lastName = new TextField("Last name");
TextField type = new TextField("Type");
PasswordField oldPassword = new PasswordField("Current Password");
PasswordField changePassword1 = new PasswordField("New Password");
PasswordField changePassword2 = new PasswordField("Confirm Password");
private UserController userController;
private UserRepository userRepository;
public EditProfileView() {
setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
userController = new UserController(userRepository);
setStyleName("backgroundImage");
setMargin(true);
setSizeFull();
addComponent(aUI.getHeader());
FormLayout content = new FormLayout(generateInfo());
Panel aPanel = new Panel("Edit User",content);
aPanel.setWidthUndefined();
content.setMargin(true);
aPanel.setStyleName(ValoTheme.PANEL_WELL);
addComponent(aPanel);
}
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = main.getLoggedInUser();
System.out.println( aUser.getUsername());
Id.setValue(aUser.getId().toString());
username.setValue(aUser.getUsername());
firstName.setValue(aUser.getFirstName());
lastName.setValue(aUser.getLastName());
type.setValue(aUser.getType());
email.setValue(aUser.getEmail());
aUI.setUserMenu();
aUI.refreshPayroll();}
catch (Exception e){
System.out.println(e.getMessage());
}
}}
However, i'm finding that it is presenting me with a "null" value? I fear i may have missunderstood how ThreadLocal works. but essentially what i'm trying to achieve is to Store an instance relevant variable of the User.Class in MainSystem for other classes to use?
Any help would be appreciated.
My Solution:
My solution to this was to store the User.class in a VaadinSession Attribute like so:
public Boolean Login(String username, String password) {
if(userController.checkUser(username,password)){
User aUser = userController.getUser(username);
VaadinSession.getCurrent().setAttribute("user",aUser);
VaadinSession.getCurrent().setAttribute("username",loggedInUser.get().getUsername());
System.out.println("Logged in User: "+loggedInUser.get().getUsername());
return true;
}
else {
return false;
}
}
Then in other classes if i want to use that attribute i retrieved it like so:
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = (User)VaadinSession.getCurrent().getAttribute("user");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
Upvotes: 0
Views: 416
Reputation: 10643
There is also another approach. Instead it could be possible to make @SessionScoped user service, and either @Inject or @Autowire that depending whether you are using CDI or Spring. When doing this way, it will be the bean manager that takes care of binding correct entity with your view.
Upvotes: 0
Reputation: 8001
The problem is that there's no guarantee that MainSystem.Login()
and EditProfileView.enter()
will happen on the same thread. Every user action is processed as a separate HTTP request that the servlet container will run on any available thread.
For this kind of functionality, I would instead recommend storing the user information in the HTTP session. If you don't have any custom servlets or such, you could instead have a an field that contains the user object in your own custom UI
class. Vaadin takes care of making UI.getCurrent()
always return the right value in all code that is run through Vaadin.
If you instead also are integrating with other servlet functionality, you could store the user in the HttpSession
instead. Generic servlet code can find the session through the getSession()
method in e.g. servlet requests and response. In code run by Vaadin, you can use VaadinSession().getCurrent().getSession()
to get a WrappedSession
instance that is based on to the same HttpSession
data.
Upvotes: 2