我编写了一个应用程序,它使用Spring Session在Sring MVC级别同时管理多个浏览器会话 . 但是,我不喜欢我的解决方案(它使用多个重定向),并希望找到改进它的方法 . 详情如下 .

我写了Spring Boot应用程序,它使用Spring Session 1.3.0,Spring MVC和Thymeleaf模板 . 我添加了它可能同时管理多个浏览器会话,即使在单独的选项卡中单个浏览器中打开也是如此 . 我从这里尝试了示例代码:https://github.com/spring-projects/spring-session/tree/1.3.x/samples/users并且它有效 . 但是我觉得除了转到servlet级别并编写大量自定义代码来管理会话之外,还有更好的方法可以做到这一点,就像在上面的链接中所做的那样:
UserAccountsFilter implements javax.servlet.Filter
LogoutServlet extends javax.servlet.http.HttpServlet
LoginServlet extends javax.servlet.http.HttpServlet
这个想法是在阅读的结果:https://docs.spring.io/spring-session/docs/1.3.2.RELEASE/reference/html5/guides/users.html我想在Spring MVC级别使用它,这是我到目前为止所做的:
1)SessionConfig:配置内存会话存储和CookieHttpSessionStrategy

@Configuration
@EnableSpringHttpSession
public class SessionConfig
{
    @Bean
    public CookieHttpSessionStrategy sessionStragegy()
    {
        return new CookieHttpSessionStrategy();
    }

    @Bean
    public MapSessionRepository sessionRepository()
    {
        return new MapSessionRepository();
    }
}

2)当用户打开链接http://mysite/employee.htm/startEdit?id=0时,则创建新员工,否则如果id> 0,则加载现有员工进行编辑 .

EmployeeEditStartController的目的是在多会话模式下启动新会话并加载到employee中,以便EmployeeEditController将其用作模型对象 .

@Controller
@RequestMapping(EmployeeEditController.URL)
public class EmployeeEditStartController extends AbstractController
{
    public static final String LOAD_USER = "loadUser";

    @Autowired EmployeeEditService employeeEditService;
    @Autowired CookieHttpSessionStrategy sessionManager;

    private String getFreeAliasUrl(HttpServletRequest request)
    {       
        String addAlias = sessionManager.getNewSessionAlias(request);
        return sessionManager.encodeURL("", addAlias);
    }

    //startEdit used only for creating new session if there is no one, for example if cookies does not exist or if they are deleted 
    @GetMapping("startEdit")
    public String startNewSession(@RequestParam(value = ID_PARAMETER, required = true) Long id, HttpServletRequest request)
    {
        request.getSession();
        return REDIRECT_PREFIX + "startEdit1" + "?" + ID_PARAMETER + "=" + id;
    }

    //startEdit1 should be run after new session is created 
    @GetMapping("startEdit1")
    public String startNewSession1(@RequestParam(value = ID_PARAMETER, required = true) Long id, HttpServletRequest request)
    {
        return REDIRECT_PREFIX + LOAD_USER + getFreeAliasUrl(request) + "&" + ID_PARAMETER + "=" + id;
    }   

    //load user into EmployeeForm and add it to session
    @GetMapping(LOAD_USER)
    public String addCommandToSession(@RequestParam(value = ID_PARAMETER, required = true) Long id, HttpSession session)
    {   
        session.setAttribute(EmployeeEditController.COMMAND, employeeEditService.getEmployeeForm(id));
        return REDIRECT_PREFIX;
    }
}

3)EmployeeEditController是添加/编辑员工主屏幕的控制器:

@Controller
@SessionAttributes(EmployeeEditController.COMMAND)
@RequestMapping(EmployeeEditController.URL)
public class EmployeeEditController extends AbstractController
{
    static final String COMMAND = "employeeForm";
    public static final String URL = "employee.htm";
    public static final String REDIRECT_URL = REDIRECT_PREFIX + URL;
    static final String VIEW = "employee/addEditEmployee/menu";

    @GetMapping
    public String get()
    {   
        return VIEW;
    }

    @PostMapping(params = DISPATCH_PARAMETER + "=save")
    public String saveEmployee(@Valid @ModelAttribute(COMMAND) EmployeeForm command, BindingResult bindingResult, SessionStatus status, HttpSession session)
    {
        //here we saving employee

        //each new session will have new id, old session will be destroyed completely and removed
        status.setComplete();
        session.invalidate();
        return REDIRECT_PREFIX + "/" + EmployeeViewController.MAIN_MENU_URL + "?_s=0";
    }
}

4)AbstractController只包含一些控制器使用的常用常量:

public class AbstractController
 {
    public static final String DISPATCH_PARAMETER = "dispatch";
    public static final String ID_PARAMETER = "id";
    public static final String INDEX_PARAMETER = "index";
    public static final String REDIRECT_PREFIX = "redirect:";
}

5)我有单独的控制器,用于更改员工姓名,设置部门等 . 我提供了其中一个(NameController)的示例,因为它显示了我如何管理其中的会话:

@Controller
@SessionAttributes({NameController.COMMAND, EmployeeEditController.COMMAND})
@RequestMapping(NameController.URL)
public class NameController extends AbstractController
{
    static final String VIEW = "employee/addEditEmployee/name";
    static final String COMMAND = "employeeName";
    static final String URL = "name";

    @Autowired private EmployeeEditService employeeEditService;

    @GetMapping
    public String get(ModelMap model, @ModelAttribute(EmployeeEditController.COMMAND) EmployeeForm employeeForm)
    {  
        model.addAttribute(COMMAND, employeeEditService.getPersonName(employeeForm.getEmployee()));
        return VIEW;
    }

    @PostMapping(params = DISPATCH_PARAMETER + "=ok")
    public String ok(@Valid @ModelAttribute(COMMAND) PersonName command, BindingResult bindingResult, @ModelAttribute(EmployeeEditController.COMMAND) EmployeeForm employeeForm)
    {
        //saving name here and then redirect
        return EmployeeEditController.REDIRECT_URL;
    }

    @PostMapping(params = DISPATCH_PARAMETER + "=cancel")
    public String cancel()
    {  
        return EmployeeEditController.REDIRECT_URL;
    }
}

我的方法有效,但在EmployeeEditStartController中我有3个控制器方法,通过重定向在链中调用: startNewSessionstartNewSession1addCommandToSession . 最后的重定向加载 EmployeeEditController#get . 感觉就像是超自然的解决方案 .

最后我的问题是:是否有可能摆脱方法 startNewSession1addCommandToSession 并使 startNewSession 方法中的所有工作都没有重定向(1重定向实际上将是:从 startNewSessionEmployeeEditController#get )并使其在Spring MVC级别上工作(不是servlet级别)?或者理想情况下在 EmployeeEditController#get 中包含所有必需的代码而根本不需要任何重定向 .