2015-04-09 1 views
1

Я использую весеннюю сессию, и мне она очень нравится. Однако я думаю, что у меня что-то не хватает. В моем приложении поток выглядит следующим образом: 1) Пользователь запрашивает HomepageController и контроллер пытается поставить атрибут в запросе:Сессия по первому требованию

HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); 

    final String sessionIds = sessionStrategy.getRequestedSessionId(request); 

    if (sessionIds != null) { 
     final ExpiringSession session = sessionRepository.getSession(sessionIds); 
     if (session != null) { 
      session.setAttribute("attr", "value"); 
      sessionRepository.save(session); 
      model.addAttribute("session", session); 
     } 
    } 

Как вы можете видеть, что это будет пытаться получить SESSIONID из запроса-печенья , и если в репозитории есть сеанс с этим идентификатором, чем использовать его (добавить атрибут). Это прекрасно, но только после второго запроса. Зачем? Потому что, если я перезапущу сервер, а cookie останется со старым значением, а затем первый запрос не найдет сессию в репозитории. После того, как ответ будет завершен, хотя cookie будет обновлен, так что запрос второй будет правильным. И вот вопрос: что не так с моей логикой и как разработать приложение для поддержки первого запроса?

Кстати, вот пример приложения, который демонстрирует проблему:

https://github.com/paranoiabla/spring-session-issue

+0

Почему так сложно? вы можете просто получить сеанс и использовать его. Вся идея заключается в том, что она максимально прозрачна, вы должны просто использовать «HttpSession», а не свою сложную логику. –

+0

Потому что, опять же, я работаю с сеансом около db-слоя (у меня есть «SessionService», который работает с «SessionRepository»), и он выглядит уродливым для работы с «HttpServletSession» рядом с db-слоем - он выглядит лучше, когда вы работаете с интерфейсом 'Session'. –

+0

ИМХО вы не должны. Вы указываете, что этот код находится в контроллере, и это связано с сетью. Вы должны imho работать только с «HttpSession» и помещать туда вещи, сессия будет храниться для вас в рамках. Похоже, вы пытаетесь работать вокруг Spring Session вместо того, чтобы обнимать его. Я бы даже осмелился сказать, что ваш контроллер сложный. –

ответ

2

Если вы желаете, чтобы получить сеанс, вы не должны использовать запрошенный идентификатор сеанса. Запрошенный идентификатор сеанса - это только то, что запрашивает браузер. Некоторые проблемы с использованием запрошенной сессии (некоторые из которых вы уже указали):

  • Если вы очистите все свои файлы cookie и сделаете запрос, браузер не запрашивает сеанс.
  • Как вы указали, если хранилище данных перезапускается и не является постоянным, то запрашиваемый идентификатор сеанса является недействительным
  • Если сессия истекает, то запрашиваемая сессия будет недействительной

Вместо этого, вы должны использовать идентификатор сессии:

final String sessionIds = request.getSession().getId(); 

Это будет использовать запрашиваемый идентификатор сеанса, если он действует, в противном случае она будет создавать новую сессию и обеспечить сеанс записывается в ответ (т.е. включены в ответ, как печенье) ,

+0

К сожалению, это не работает для меня. Рабочий процесс выглядит следующим образом: Чтобы получить 'sessionId', я делаю' request.getSession(). GetId() 'вызывает' SessionRepositoryFilter', который вызывает 'RedisOperationsSessionRepository', который создает сеанс, но делает НЕ сохраняйте его в Redis !!! .. Теперь у меня есть 'sessionId' и если я вызываю' sessionRepository.getSession (sessionId); 'репозиторий возвращает' null', поэтому вся моя логика выдает исключения. Затем ответ завершается, и в какой-то момент сеанс сохраняется в redis и мой запрос SECOND будет успешным (я получаю идентификатор сеанса, который и я нахожу сессию с этим id в redis repo) –

0

Я бы сказал, что ваш подход неправильный, ваш контроллер делает много, и вы должны просто использовать HttpSession, для которого Spring Session предоставляет поддержку. Вы также не должны ставить сеанс в model imho, поскольку вы должны просто получить доступ к HttpSession. Ваше приложение не должно знать о Spring Session.

Ваш контроллер должен выглядеть следующим образом

@Controller 
public class HomepageController { 

    @RequestMapping(value = "/", method = RequestMethod.GET) 
    public String home(HttpSession session) { 
     session.setAttribute("attr", "value"); 
     return "homepage"; 
    } 
} 

, если вы не хотите, чтобы заставить создание сеанса впрыскивать HttpServletRequest и сделать getSession(false) вместо инъекции HttpSession.

Все остальное (сохранение сеанса после обработки запроса и т. Д.) Будет обработано прозрачно с помощью Spring Session.