Spring Session与Spring MVC的多个浏览器会话

时间:2018-02-11 19:03:43

标签: java spring spring-mvc spring-boot spring-session

我编写的应用程序使用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中拥有所有必要的代码,而不需要任何重定向。

0 个答案:

没有答案