用于用户管理的 Vaadin ThreadLocal
Vaadin ThreadLocal for User Management
我目前正在 Java 开发一个 Web 应用程序,该应用程序将被多个用户同时访问,因此需要存储用户数据以便根据他们的个人需求定制应用程序(例如他们是哪家公司等等)。
我使用 2 个 classes 来管理它。用户、MainSystem 详情如下:
用户
@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;
}
主系统:
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();
}
理想情况下,我想做的是从另一个 class 访问 ThreadLocal 变量,例如 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());
}
}}
但是,我发现它为我提供了一个 "null" 值?我担心我可能误解了 ThreadLocal 的工作原理。但基本上我想要实现的是在 MainSystem 中存储 User.Class 的实例相关变量以供其他 class 使用?
如有任何帮助,我们将不胜感激。
我的解决方案:
我的解决方案是将 User.class 存储在 VaadinSession 属性中,如下所示:
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;
}
}
然后在其他 classes 中,如果我想使用该属性,我会像这样检索它:
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = (User)VaadinSession.getCurrent().getAttribute("user");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
问题是不能保证 MainSystem.Login()
和 EditProfileView.enter()
会在同一个线程上发生。每个用户操作都作为单独的 HTTP 请求处理,servlet 容器将在任何可用线程上 运行。
对于这种功能,我建议将用户信息存储在 HTTP 会话中。如果您没有任何自定义 servlet 等,您可以在自己的自定义 UI
class 中有一个包含用户对象的字段。 Vaadin 负责通过 Vaadin 使 UI.getCurrent()
始终 return 成为所有 运行 代码中的正确值。
如果您还与其他 servlet 功能集成,则可以将用户存储在 HttpSession
中。通用 servlet 代码可以通过 getSession()
方法找到会话,例如servlet 请求和响应。在 Vaadin 的代码 运行 中,您可以使用 VaadinSession().getCurrent().getSession()
获取基于相同 HttpSession
数据的 WrappedSession
实例。
还有一种方法。相反,可以创建@SessionScoped 用户服务,以及@Inject 或@Autowire,这取决于您使用的是CDI 还是Spring。这样做时,将由 bean 管理器负责将正确的实体与您的视图绑定。
我目前正在 Java 开发一个 Web 应用程序,该应用程序将被多个用户同时访问,因此需要存储用户数据以便根据他们的个人需求定制应用程序(例如他们是哪家公司等等)。
我使用 2 个 classes 来管理它。用户、MainSystem 详情如下:
用户
@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;
}
主系统:
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();
}
理想情况下,我想做的是从另一个 class 访问 ThreadLocal 变量,例如 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());
}
}}
但是,我发现它为我提供了一个 "null" 值?我担心我可能误解了 ThreadLocal 的工作原理。但基本上我想要实现的是在 MainSystem 中存储 User.Class 的实例相关变量以供其他 class 使用?
如有任何帮助,我们将不胜感激。
我的解决方案:
我的解决方案是将 User.class 存储在 VaadinSession 属性中,如下所示:
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;
}
}
然后在其他 classes 中,如果我想使用该属性,我会像这样检索它:
@Override
public void enter(ViewChangeListener.ViewChangeEvent event) {
try {
aUser = (User)VaadinSession.getCurrent().getAttribute("user");
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
问题是不能保证 MainSystem.Login()
和 EditProfileView.enter()
会在同一个线程上发生。每个用户操作都作为单独的 HTTP 请求处理,servlet 容器将在任何可用线程上 运行。
对于这种功能,我建议将用户信息存储在 HTTP 会话中。如果您没有任何自定义 servlet 等,您可以在自己的自定义 UI
class 中有一个包含用户对象的字段。 Vaadin 负责通过 Vaadin 使 UI.getCurrent()
始终 return 成为所有 运行 代码中的正确值。
如果您还与其他 servlet 功能集成,则可以将用户存储在 HttpSession
中。通用 servlet 代码可以通过 getSession()
方法找到会话,例如servlet 请求和响应。在 Vaadin 的代码 运行 中,您可以使用 VaadinSession().getCurrent().getSession()
获取基于相同 HttpSession
数据的 WrappedSession
实例。
还有一种方法。相反,可以创建@SessionScoped 用户服务,以及@Inject 或@Autowire,这取决于您使用的是CDI 还是Spring。这样做时,将由 bean 管理器负责将正确的实体与您的视图绑定。