【问题标题】:How do i use variable defined in one controller be used across multiple different controller?如何使用在一个控制器中定义的变量在多个不同的控制器中使用?
【发布时间】:2021-08-14 15:39:32
【问题描述】:

我有一个控制器:

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    protected int userId; // I need to use it across many other controllers. HOW?

    @GetMapping("/")
    private String viewHomePage(Model model) {
        
        return "eAccounts";
    }

    @GetMapping("/dashboard")
    private String getDashboardPage() {
        return "dashboard";
    }

    @GetMapping("/signup")
    private String getSignupPage(Model model) {
        User user = new User();
        model.addAttribute("user", user);
        return "signup";
    }

    @PostMapping("/verifySignup")
    private String verifySignup(@ModelAttribute("user") User user, Model model, HttpServletRequest request) {
    if (userService.verifySignup(user) == 1) {
        userId = user.getId();// save user id for later use
        return "redirect:/dashboard";
    }

    return "signup";
    }
}

并且有多个控制器(例如assetController、liabilityController等):

@Controller
public class AssetController {
    @Autowired
    private AssetService assetService;

    @GetMapping("/assets")
    public String getAssetsPage(Model model) {
        model.addAttribute("listAssets", assetService.getAllAssets(userId)); // here i need to use userId, and at many more places
        return "assets";
    }
}

我不想将我所有的控制器代码合并到一个控制器中。 我只需要在用户注册或登录网站时保存 userId,然后在许多其他控制器中使用它。任何干净的解决方案将不胜感激。

【问题讨论】:

    标签: java spring-boot model-view-controller


    【解决方案1】:

    假设您希望在会话的多个控制器之间共享用户 ID。

    在这种情况下,您可以使用会话范围的 bean 来存储 userId。将为每个会话创建会话范围 bean 的新实例,并将在该会话中保持活动状态。一旦会话失效,会话范围的 bean 将被自动销毁。有关如何创建会话范围 bean 及其用法,请参考以下示例:

    会话范围的 bean:

    @Getter
    @Setter
    @NoArgsConstructor
    @Component
    @SessionScope //scope of this bean is session
    public class UserDetails {
        private String userId;
    }
    

    将会话范围的 bean 注入您的控制器:

    用户控制器

    @Controller
    public class UserController {
        @Autowired
        private UserService userService;
    
        @Autowired
        private UserDetails userDetails; //adding session scoped bean
    
        @GetMapping("/")
        private String viewHomePage(Model model) {
    
            return "eAccounts";
        }
    
        @GetMapping("/dashboard")
        private String getDashboardPage() {
            return "dashboard";
        }
    
        @GetMapping("/signup")
        private String getSignupPage(Model model) {
            User user = new User();
            model.addAttribute("user", user);
            return "signup";
        }
    
        @PostMapping("/verifySignup")
        private String verifySignup(@ModelAttribute("user") User user, Model model, HttpServletRequest request) {
            if (userService.verifySignup(user) == 1) {
                userDetails.setUserId(user.getId());// save user id in session scoped bean
                return "redirect:/dashboard";
            }
    
            return "signup";
        }
    }
    

    资产控制器

    @Controller
    public class AssetController {
        @Autowired
        private AssetService assetService;
    
        @Autowired
        private UserDetails userDetails;
    
        @GetMapping("/assets")
        public String getAssetsPage(Model model) {
            model.addAttribute("listAssets", assetService.getAllAssets(userDetails.getUserId())); //get user id from session scoped bean
    
            return "assets";
        }
    }
    

    有关session scoped beans 的更多信息,请参阅 spring 文档。

    注意:请确保您没有在活动会话之外访问会话范围的 bean。

    【讨论】:

      【解决方案2】:

      Spring 中 bean 的默认作用域是 singleton。由于我在你的代码中没有看到任何改变它的东西,我会假设你的控制器是单例的。

      您不想在单例类中创建依赖于会话的实例变量。拥有这个protected int userId 实例变量是个坏主意。例如,如果您有两个用户同时浏览您的应用程序,则一个用户可能会使用另一个用户的userid 检索信息。

      通常推荐的获取用户信息的方法是使用SecurityContext(另一个question的用法示例。我们可以从SecurityContextHolder检索SecurityContext

      其他解决方案是在端点注入AuthenticationPrincipal,例如:

      @Controller
      public class MyController {
      
          @RequestMapping(value = "/username", method = RequestMethod.GET)
          @ResponseBody
          public String currentUserName(Principal principal) {
              return principal.getName();
          }
      }
      

      这两种解决方案都假设我们已经使用 Spring Security 正确实现了身份验证。

      【讨论】:

        【解决方案3】:

        与其将其保存为 UserController 的局部变量,不如将其保存在另一个 Bean 中,例如在 UserService 中,所有控制器都会对其执行 @Autowired 操作并获取用户 ID 信息。

        【讨论】:

          【解决方案4】:

          您可以使用会话, 会话将在自定义时间段内存储来自用户的自定义值的值,持续时间可能是应用程序启动的时间。

          要存储,您可以像这样设置控制器:

          @RequestMapping(method = RequestMethod.GET)
          public String testMestod(HttpServletRequest request){
             User user= (User)request.getSession().setAttribute("userId",value);
             return "test";
          }
          

          要获取值,您可以使用此方法:

          User user= (user)session.getAttribute("userId");
          

          有关此链接的更多信息 https://www.techgeeknext.com/spring-boot/spring-boot-session-management

          【讨论】:

            猜你喜欢
            • 2021-11-02
            • 2017-11-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-18
            • 2012-04-24
            • 1970-01-01
            • 2017-01-05
            相关资源
            最近更新 更多