如何在Spring-mvc中使用Session属性

115

你能帮我写一个Spring MVC风格的代码,与这段代码类似吗?

 session.setAttribute("name","value");

如何将使用@ModelAttribute注释的元素添加到会话中,并获得对它的访问权限?

10个回答

208
如果你想在每次响应后删除对象,你不需要会话(session);
如果你想在用户会话期间保留对象,则有以下几种方式:
  1. directly add one attribute to session:

    @RequestMapping(method = RequestMethod.GET)
    public String testMestod(HttpServletRequest request){
       ShoppingCart cart = (ShoppingCart)request.getSession().setAttribute("cart",value);
       return "testJsp";
    }
    

    and you can get it from controller like this :

    ShoppingCart cart = (ShoppingCart)session.getAttribute("cart");
    
  2. Make your controller session scoped

    @Controller
    @Scope("session")
    
  3. Scope the Objects ,for example you have user object that should be in session every time:

    @Component
    @Scope("session")
    public class User
     {
        String user;
        /*  setter getter*/
      }
    

    then inject class in each controller that you want

       @Autowired
       private User user
    

    that keeps class on session.

  4. The AOP proxy injection : in spring -xml:

    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
    
      <bean id="user"    class="com.User" scope="session">     
          <aop:scoped-proxy/>
      </bean>
    </beans>
    

    then inject class in each controller that you want

    @Autowired
    private User user
    

5.将HttpSession传递给方法:

 String index(HttpSession session) {
            session.setAttribute("mySessionAttribute", "someValue");
            return "index";
        }

6. 通过 @SessionAttributes("ShoppingCart") 将 ModelAttribute 存入会话:

  public String index (@ModelAttribute("ShoppingCart") ShoppingCart shoppingCart, SessionStatus sessionStatus) {
//Spring V4
//you can modify session status  by sessionStatus.setComplete();
}

或者您可以像以下方法,将模型添加到整个控制器类中:

@Controller
    @SessionAttributes("ShoppingCart")
    @RequestMapping("/req")
    public class MYController {

        @ModelAttribute("ShoppingCart")
        public Visitor getShopCart (....) {
            return new ShoppingCart(....); //get From DB Or Session
        }  
      }

每种方法都有优点和缺点: @session在云系统中可能会占用更多的内存,因为它会将会话复制到所有节点中。直接方法(1和5)的方法比较混乱,不利于单元测试。 要访问jsp会话。
<%=session.getAttribute("ShoppingCart.prop")%>

在Jstl中:

<c:out value="${sessionScope.ShoppingCart.prop}"/>

在Thymeleaf中:
<p th:text="${session.ShoppingCart.prop}" th:unless="${session == null}"> . </p>

6
如果您的控制器是单例的,那么在使用会话范围注入组件时,需要定义proxyMode = ScopedProxyMode.TARGET_CLASS。@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS) - Vadim Kolesnikov
1
将控制器作用域设置为会话范围是最糟糕的选择,尽管它看起来简单易用。但是,如果您想在未来扩展应用程序,您可能会遇到麻烦,因为您可能需要分布式会话存储(例如Redis),除非您使用粘性会话(以方便为代价牺牲可用性)。 因此,会话作用域的bean通常应该是愚蠢的可序列化POJO。这样,如果需要扩展规模,您就已经做好了准备。 - chris
RequestContextHolder是怎么样的呢? - user1589188
只有在调用与session作用域相同的类中的bean时,注入User bean才能正常工作。否则,如果没有会话存在,则会抛出异常,因为在注入user bean到另一个类时,上下文@runtime中不会有任何活动会话! - Jose Mhlanga

45

1
你如何利用sessionAttributes在控制器之间传递对象? - Akah

30

SessionAttribute注释是最简单和直接的,而不是从请求对象中获取会话并设置属性。 在控制器中可以向模型添加任何对象,如果它的名称与@SessionAttributes注释中的参数匹配,则该对象将存储在会话中。 在下面的例子中,personObj将可用于会话。

@Controller
@SessionAttributes("personObj")
public class PersonController {

    @RequestMapping(value="/person-form")
    public ModelAndView personPage() {
        return new ModelAndView("person-page", "person-entity", new Person());
    }

    @RequestMapping(value="/process-person")
    public ModelAndView processPerson(@ModelAttribute Person person) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("person-result-page");

        modelAndView.addObject("pers", person);
        modelAndView.addObject("personObj", person);

        return modelAndView;
    }

}

会话仅适用于同一控制器实例中的请求。如果需要将控制发送到另一个控制器,此会话将被销毁,并在必要时创建新会话。 - Akah
1
@larrytech 怎么可能呢?我认为你只是忘记在第二个控制器中添加SessionAttributes了。 - Yura

19
下面的带注释代码将把"value"设置为"name"。
@RequestMapping("/testing")
@Controller
public class TestController {
@RequestMapping(method = RequestMethod.GET)
public String testMestod(HttpServletRequest request){
    request.getSession().setAttribute("name", "value");
    return "testJsp";
  }
}

要在JSP中访问相同的内容,请使用${sessionScope.name}

有关@ModelAttribute的详细信息,请参阅此链接


5

这样做不是最简单且最短吗?我知道并测试过- 在这里完美运行:

@GetMapping
public String hello(HttpSession session) {
    session.setAttribute("name","value");
    return "hello";
}

p.s. 我来到这里寻找答案:“如何在Spring-mvc中使用会话属性”,但是阅读了很多篇文章却没有看到我已经在我的代码中写了最明显的答案。我没有看到它,所以认为它是错误的,但实际上不是。因此,让我们分享这个问题的最简单解决方案的知识。


1
你说得对!这正是我想的,因为当你在控制器方法(GET/POST请求)中声明它们时,你可以直接访问我们需要的所有Http对象。 - Shessuky

1
尝试这个...
@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {

    @ModelAttribute("types")

    public Collection<PetType> populatePetTypes() {
        return this.clinic.getPetTypes();
    }

    @RequestMapping(method = RequestMethod.POST)
    public String processSubmit(@ModelAttribute("pet") Pet pet, 
            BindingResult result, SessionStatus status) {
        new PetValidator().validate(pet, result);
        if (result.hasErrors()) {
            return "petForm";
        }else {
            this.clinic.storePet(pet);
            status.setComplete();
            return "redirect:owner.do?ownerId="
                + pet.getOwner().getId();
        }
    }
}

1
在Spring 4 Web MVC中,您可以在控制器级别的方法中使用@SessionAttributes@SessionAttribute来保留会话属性。
@Controller
@SessionAttributes("SessionKey")
public class OrderController extends BaseController {

    GetMapping("/showOrder")
    public String showPage(@SessionAttribute("SessionKey") SearchCriteria searchCriteria) {
     // method body
}

0
当我尝试登录我的Bootstrap模态框时,我使用了@sessionattributes注释。但问题是,当视图是重定向("redirect:/home")时,我输入到会话中的值显示在URL中。一些互联网来源建议遵循http://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#mvc-redirecting 但我使用了HttpSession。这个会话将一直存在,直到你关闭浏览器。以下是示例代码。
        @RequestMapping(value = "/login")
        @ResponseBody
        public BooleanResponse login(HttpSession session,HttpServletRequest request){
            //HttpServletRequest used to take data to the controller
            String username = request.getParameter("username");
            String password = request.getParameter("password");

           //Here you set your values to the session
           session.setAttribute("username", username);
           session.setAttribute("email", email);

          //your code goes here
}

在视图方面,你不需要改变特定的东西。

<c:out value="${username}"></c:out>
<c:out value="${email}"></c:out>

登录后,将上述代码添加到您网站的任何位置。如果会话正确设置,您将在那里看到值。请确保正确添加了jstl标签和El表达式(这里是设置jstl标签的链接https://menukablog.wordpress.com/2016/05/10/add-jstl-tab-library-to-you-project-correctly/)。


0

使用这个方法非常简单易用

HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getNativeRequest();

                                                            request.getSession().setAttribute("errorMsg", "your massage");

在 JSP 中,一旦使用就要删除。

<c:remove var="errorMsg" scope="session"/>      

0
很多有趣的答案...但对于我们这些经典的Spring MVC开发者来说,这个方法非常接近以前的方式:
package test;

import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class ControllerClass {

    @GetMapping(value = "/someValue")
    public String requestHandler(HttpServletRequest request, Model model) throws Exception {
        String value = request.getSession().getAttribute("someAttribute");
        model.addAttribute("attributeName", "value is "+ value);

        return "JspFileName";
    }
} 

这个与被接受的答案有何不同? - sanitizedUser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接