java 如何在 Spring MVC 中维护会话?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12457461/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 08:57:46  来源:igfitidea点击:

How to maintain session in spring MVC?

javaspringsessionspring-mvc

提问by Anand

Using spring MVC, I need to store my object into session and I should use the same object in several jsp pages using jstl. I have tried like this:

使用 spring MVC,我需要将我的对象存储到会话中,我应该使用 jstl 在几个 jsp 页面中使用相同的对象。我试过这样:

ModelAndView modelAndView = new ModelAndView("admin/addproduct", "category", categorynameList);

But I can't access the category to other jsp pages except addproductpage.

但是我无法访问除页面之外的其他jsp页面的类别addproduct

How can I do that?

我怎样才能做到这一点?

回答by Costi Ciudatu

Spring MVC provides more than one mechanisms that hide the plain use of HttpSessionfrom you.

Spring MVC 提供了不止一种机制来隐藏你的简单使用HttpSession

Have a look at the @SessionAttributesannotation, which allows you to define the attributes that will be stored in the session by your controller; this mechanism is mainly intended to maintain the conversational state for your handler and that state is usually cleared once the conversation is complete.

查看@SessionAttributes注释,它允许您定义控制器将存储在会话中的属性;此机制主要用于维护处理程序的对话状态,一旦对话完成,该状态通常会被清除。

Also, you can define your bean as session scoped in the application context and then make use of a ScopedProxyFactoryBean (by simply adding an <aop:scoped-proxy/>element in your bean definition), thus being able to inject that bean in your singleton controllers.

此外,您可以将 bean 定义为应用程序上下文中的会话范围,然后使用 ScopedProxyFactoryBean(只需<aop:scoped-proxy/>在 bean 定义中添加一个元素),从而能够将该 bean 注入到您的单例控制器中。

回答by Assen Kolov

You can pass the session directly to any annotated controller method:

您可以将会话直接传递给任何带注释的控制器方法:

@RequestMapping("somePathName")
public String someHandler(HttpSession session) {
  session.setAttribute(...

回答by user7440521

The annotation @SessionAttributes is used on class level. Typically it's used on the @Controller class. It's 'value' element is of type String[] whose values are the matching names used in @ModelAttribute either on method level or on handler's method parameter level.

注释@SessionAttributes 用于类级别。通常它用于@Controller 类。它的 'value' 元素是 String[] 类型,其值是@ModelAttribute 在方法级别或处理程序的方法参数级别中使用的匹配名称。

Let's consider following arrangement:

让我们考虑以下安排:

@Controller
@SessionAttributes("visitor")
@RequestMapping("/trades")
public class TradeController {

    @ModelAttribute("visitor")
    public Visitor getVisitor (....) {
        return new Visitor(....);
    }
  ....
}

In above code, when a request comes in, the first thing Spring will do is to notice @SessionAttributes('visitor') and then attempt to find the value of 'visitor' in javax.servlet.http.HttpSession. If it doesn't find the value, then the method with @ModelAttribute having the same name 'visitor' (method getVisitor()) will be invoked. The returned value from such method will be used to populate the session with name 'visitor'.

在上面的代码中,当一个请求进来时,Spring 要做的第一件事就是通知@SessionAttributes('visitor'),然后尝试在javax.servlet.http.HttpSession 中找到'visitor'的值。如果未找到该值,则将调用具有相同名称“访问者”的@ModelAttribute 方法(方法 getVisitor())。这种方法的返回值将用于填充名称为“visitor”的会话。

Now that 'visitor' with it's value is already in HttpSession, let's consider following arrangement:

现在 'visitor' 的值已经在 HttpSession 中,让我们考虑以下安排:

@Controller
@SessionAttributes("visitor")
@RequestMapping("/trades")
public class TradeController {

    @RequestMapping("/**")
    public String handleRequestById (@ModelAttribute("visitor") Visitor visitor,
                                     Model model,
                                     HttpServletRequest request) {
        model.addAttribute("msg", "trades request, serving page " +
                                                 request.getRequestURI());
        visitor.addPageVisited(request.getRequestURI());
        return "traders-page";
    }
   .......
}

On finding @ModelAttribute("visitor") in the target handler method, Spring will retrieve the value of 'visitor' from the session and will assign the value to the Visitor parameter and will invoke the method. At this step, Spring doesn't care how the session was populated with 'visitor', Whether it was populated using the last arrangement or some other way, it doesn't matter, Spring only requires the annotation @SessionAttributes('visitor'), the handler method parameter with @ModelAttribute("visitor") and the value of 'visitor' in HttpSession. If spring can't find it in the session and last arrangement is not available then following exception will be thrown:

在目标处理程序方法中找到 @ModelAttribute("visitor") 时,Spring 将从会话中检索 'visitor' 的值,并将该值分配给 Visitor 参数并调用该方法。在这一步,Spring 并不关心 session 是如何填充 'visitor' 的,无论是使用最后的排列还是其他方式填充都没有关系,Spring 只需要注解 @SessionAttributes('visitor') ,带有@ModelAttribute("visitor")的handler方法参数和HttpSession中'visitor'的值。如果 spring 在 session 中找不到它并且最后的安排不可用,则将抛出以下异常:

org.springframework.web.HttpSessionRequiredException: Expected session attribute 'visitor'

org.springframework.web.HttpSessionRequiredException:预期的会话属性“访问者”

In other words: when the target handler method is invoked first time in a given session, then method with @ModelAttribute('visitor) is invoked, the returned value is populated in HttpSession and the handler method with the same value is invoked. For the subsequent requests within the same HTTPSession, Spring retrieves the same object from the session and doesn't call the method with @ModelAttribute('visitor') again till the end of the session

换句话说:当在给定会话中第一次调用目标处理程序方法时,然后调用带有@ModelAttribute('visitor) 的方法,返回值填充在 HttpSession 中,并调用具有相同值的处理程序方法。对于同一个 HTTPSession 中的后续请求,Spring 从会话中检索相同的对象,并且直到会话结束才再次调用带有 @ModelAttribute('visitor') 的方法

Following is the complete controller class:

以下是完整的控制器类:

@Controller
@SessionAttributes("visitor")
@RequestMapping("/trades")
public class TradeController {

    @RequestMapping("/**")
    public String handleRequestById (@ModelAttribute("visitor") Visitor visitor,
                                     Model model,
                                     HttpServletRequest request) {
        model.addAttribute("msg", "trades request, serving page " +
                                                 request.getRequestURI());
        visitor.addPageVisited(request.getRequestURI());
        return "traders-page";
    }

    @ModelAttribute("visitor")
    public Visitor getVisitor (HttpServletRequest request) {
        return new Visitor(request.getRemoteAddr());
    }
}

In above example we are tracking the user visited pages within the same HTTP session. We are using the wildcard '/**' so that all request starting with 'trades' will map to this controller.

在上面的例子中,我们在同一个 HTTP 会话中跟踪用户访问的页面。我们使用通配符“/**”,以便所有以“trades”开头的请求都将映射到此控制器。

回答by Oleksandr Bondarenko

Inject session to your controller classes, store your object there and use it when you need it, e.g.:

将会话注入您的控制器类,将您的对象存储在那里并在您需要时使用它,例如:

@Controller
public class SomeController {

  //@Autowired
  //private HttpSession session; This is not desired. See the discussion in the 
  //comments.

  @RequestMapping("somePathName")
  public String someHandler(HttpSession session) { //Session will be injected by 
    //Spring without any additional annotations.
    //...
    session.setAttribute("category", yourObject);
  }
}

If you need to access categoryon other pages than admin/addproductyou will need to add it to respective models as follows:

如果您需要category在其他页面上访问,admin/addproduct则需要将其添加到相应的模型中,如下所示:

@RequestMapping("somePathName")
public String someHandler(Model model) {
  //...
  model.addAttribute("category", yourObject);
  //...
  return "yourPageName";
}

Update: according to ALex's comment that injecting HttpSessioninstance into field is stronglynot desired due to thread safety concerns I've changed the source respectively.

更新:根据 ALex 的评论,由于线程安全问题,不需要将HttpSession实例注入字段,strongly我已经分别更改了源代码。