登陸成功後返回前一個頁面

背景說明

之前自己寫了一個Web日誌工具,使用Spring MVC+mybatis進行實現。由於我自己一天到晚都要使用,而有時頁面會放在那裏一段時間,就常會遇到session過期後跳轉到登陸界面進行登陸。但是登陸後是轉向了一個默認界面,這樣我每次都還在多一次點擊才能來到目標頁面。於是,我必須要解決登陸之後跳轉到前一個頁面的問題以提高效率。
首先,我使用了SessionFilter對Session進行過濾,在Session過期時就會在這個方法中轉向到login界面。
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpSession session = ((HttpServletRequest) request).getSession();
    HttpServletResponse rep = (HttpServletResponse) response;
    HttpServletRequest req = (HttpServletRequest) request;

    String url = req.getRequestURI();

    if (url.contains("user/login")
            || url.endsWith(".css")
            || url.endsWith(".js")
            || url.endsWith(".png")
            || url.endsWith(".jpg")) {
        chain.doFilter(request, response);
    } else if ((session == null || session.getAttribute("user") == null)) {
        rep.sendRedirect(req.getContextPath() + "/user/login);
    } else {
        chain.doFilter(request, response);
    }
}
然後,在LoginController中分GET和POST對用戶登陸進行處理。
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login() {
    final ModelAndView m = new ModelAndView("login");
    return m;
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView login(HttpSession session, String userName, String password) {
    ReturnStatus rs = service.login(userName, MD5Tool.getMD5(password.getBytes()));
    if (rs.getCode() == 1) {
        session.setAttribute("user", service.get(userName));
        return new ModelAndView("redirect:/task/week");
    } else {
        final ModelAndView m = new ModelAndView("login");
        m.addObject("message", "用戶名或者密碼不正確,請重新輸入");
        return m;
    }
}

解決方案

我首先想到的就是在filter中轉向到login頁面時,將登陸成功後要轉向的頁面fromUrl傳過去。假設原始鏈接是:http://localhost:8084/personal/task/update?id=DTASK1167778733413045&mode=week。
  1. req.getRequestURI(),獲取到的是/personal/task/update,不帶query string,不符合
  2. req.getRequestURL(),獲取到的是http://localhost:8084/personal/task/update,也不帶query string,不符合
  3. 於是我百度了一下,找到一下方法可以獲得完整的請求url(http://localhost:8084/personal/task/update?id=DTASK1167778733413045&mode=week),但是遺憾的是POST過來的數據還是無法
    • public static String getUrl(HttpServletRequest req) {
          String reqUrl = req.getRequestURL().toString();
          String queryString = req.getQueryString();
          if (queryString != null) {
              reqUrl += "?" + queryString;
          }
          return reqUrl;
      }
  4. 我試圖從request中把POST過來的數據設置到response的Header中,但是在login頁面經過SpringMVC後再次分發我又不會(感覺會很麻煩)
    • private void setHeader(HttpServletRequest req, HttpServletResponse rep) {
          for (Map.Entry<String, String[]> entry : req.getParameterMap().entrySet()) {
              try {
                  String name = entry.getKey();
                  String value = new String(req.getParameter(name).getBytes("ISO8859-1"), "UTF8");
                  rep.setHeader(name, value);
              } catch (UnsupportedEncodingException ex) {
                  Logger.getLogger(SessionFilter.class.getName()).log(Level.SEVERE, null, ex);
              }
          }
      }
  5. 於是決定,在POST的情況下就不再做POST操作,而是轉向到POST之前的界面(這樣有丟失數據的危險,暫時先這樣吧)
    • from Url = req.getHeader("Referer")

最終,思路確定如下:Session過濾時,如果是POST過來的,就取前一個頁面的url(第5點中的方法),如果是其他請求方式過來的(主要是GET),就使用當前要轉向的url(第3點中的方法)。將url通過GET方式傳入到login頁面後,POST login時也帶到後臺,待確認登陸成功後轉向到該url。

最終代碼

SessionFilter

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpSession session = ((HttpServletRequest) request).getSession();
    HttpServletResponse rep = (HttpServletResponse) response;
    HttpServletRequest req = (HttpServletRequest) request;

    String url = req.getRequestURI();

    if (url.contains("user/login")
            || url.endsWith(".css")
            || url.endsWith(".js")
            || url.endsWith(".png")
            || url.endsWith(".jpg")) {
        chain.doFilter(request, response);
    } else if ((session == null || session.getAttribute("user") == null)) {
        String fromUrl;
        if ("POST".equalsIgnoreCase(req.getMethod())) {
            fromUrl = req.getHeader("Referer");
        } else {
            fromUrl = getUrl(req);
        }
        rep.sendRedirect(req.getContextPath() + "/user/login?fromUrl=" + URLEncoder.encode(fromUrl, "UTF8"));
    } else {
        chain.doFilter(request, response);
    }
}

public static String getUrl(HttpServletRequest req) {
    String reqUrl = req.getRequestURL().toString();
    String queryString = req.getQueryString();
    if (queryString != null) {
        reqUrl += "?" + queryString;
    }
    return reqUrl;
}

LoginController

@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView login(HttpServletRequest request, @RequestParam(defaultValue = "") String fromUrl) {
    final ModelAndView m = new ModelAndView("login");
    m.addObject("fromUrl", fromUrl);
    return m;
}

@RequestMapping(value = "/login", method = RequestMethod.POST)
public ModelAndView login(HttpSession session, String userName, String password,
        @RequestParam(defaultValue = "") String fromUrl) {
    ReturnStatus rs = service.login(userName, MD5Tool.getMD5(password.getBytes()));
    if (rs.getCode() == 1) {
        session.setAttribute("user", service.get(userName));

        if (fromUrl.equals("")) {
            return new ModelAndView("redirect:/task/week");
        } else {
            return new ModelAndView("redirect:" + fromUrl);
        }
    } else {
        final ModelAndView m = new ModelAndView("login");
        m.addObject("message", "用戶名或者密碼不正確,請重新輸入");
        m.addObject("fromUrl", fromUrl);
        return m;
    }
}

http://www.alanzeng.cn/2016/01/login-redirect/


發佈了94 篇原創文章 · 獲贊 39 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章