2016年4月6日 星期三

登入跳轉 (Servlet 九)

跳轉之前講的不太清楚,這裡寫一個登入功能會比較容易了解

我看了API後,理解如下:
HttpServletResponse的sendRedirect
參數不是「/」開頭,為相對路徑
是「/」開頭,表示ServletContext路徑
如果resp已commit,會拋出IllegalStateException
1.瀏覽器req給servlet
2.servlet將設定的路徑回傳給瀏覽器
3.瀏覽器依這個路徑再req
4.servlet再回傳
所以有兩次的req
因為是resp,所以網址會改變


ServletRequest的getRequestDispatcher取得javax.servlet的RequestDispatcher
有以下兩個方法

1.forward(主控權是別人)
轉發給servlet、JSP、HTML
如果resp已commit,會拋出IllegalStateException

2.include(主控權是自己)
將servlet、JSP、HTML包括到自己的servlet
所包含的servlet不能改變resp狀態碼或設定header,如果有改變將被忽略。

這兩個方法都是req,所以網址不會改變


※web.xml

<filter>
    <filter-name>zzz</filter-name>
    <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>zzz</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>



※LoginServlet.java

@WebServlet(urlPatterns = { "/xxx" })
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String enc = super.getServletConfig().getInitParameter("encoding");
        resp.setContentType("text/html; charset=" + enc);
    
        String username = req.getParameter("username");
        String password = req.getParameter("password");
    
        if (username.trim().equals("aaa") && password.trim().equals("bbb")) {
            String fruit = req.getParameter("ooo");
            String[] xxx = req.getParameterValues("xxx");
            List<String> tl = Arrays.asList("ttt", "lll");
    
            if (xxx != null) {
                for (String s : req.getParameterValues("xxx")) {
                    // 老虎獅子吃香蕉
                    if (tl.contains(s) && "bbb".equals(fruit)) {
                        // forward 轉發給設定的servlet、jsp、HTML,主導權也送出去
                        System.out.println("before:" + req.getServletPath());
                        req.getRequestDispatcher("/abc").forward(req, resp);
                        // req.getRequestDispatcher("/WEB-INF/success.jsp").forward(req,
                        // resp);
                        System.out.println("after:" + req.getServletPath());
    
                        // include包含設定的servlet、jsp、HTML,主導權並沒有送出去
                        // System.out.println("before:" + req.getServletPath());
                        // req.getRequestDispatcher("/abc").include(req, resp);
                        // req.getRequestDispatcher("/WEB-INF/success.jsp").include(req,
                        // resp);
                        // System.out.println("after:" + req.getServletPath());
                        break;
                    } else {
                        if ("rrr".equals(s)) {
                            resp.sendRedirect(req.getContextPath() + "/fail.jsp");
                            System.out.println("456");// 有執行到
                        } else {
                            continue;
                        }
                    }
                }
            } else {
                resp.sendRedirect("http://www.google.com");
            }
        } else {
            // sendRedirect是兩次的request,所以req.setAttribute抓不到
            // req.setAttribute("fail", "帳密錯誤");
            req.getSession().setAttribute("fail", "帳密錯誤");
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
        }
    }
}

※sendRedirect也可以直接呼叫一般的網址,而WEB-INF是特殊的資料夾,resp當然不能拿來用

※include、forward 差在 getRequestDispatcher 是另一個 servlet 時
forward 後,主導權不在,include 還在
所以 forward 的 response 不會執行;而 include 跳轉的頁面返回後,繼續執行 response

假設有 ServletA 和 ServletB
使用 forward 跳頁後就不管了
使用 include 跳頁執行完後,會再回來繼續執行其他的部分


※TestAaa.java

@WebServlet(urlPatterns = { "/abc" })
public class TestAaa extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("in:" + req.getServletPath());// include進來是xxx,forward進來是abc
    }
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get接收");
    }
}

※include和forward呼叫這支servlet時,會發現不一樣的地方

※如果login.jsp呼叫doGet,那abc也會呼叫doGet



※login.jsp

<form action="xxx" method="post">
    <font color="red">${fail}</font><br />
    使用者:<input type="text" name="username" value="user" /><br />
    
    密碼:<input type="password" name="password" value="pass" /><br />
    
    登入密語:
    <input type="checkbox" name="xxx" value="ttt" />tiger
    <input type="checkbox" name="xxx" value="rrr" />rabit
    <input type="checkbox" name="xxx" value="lll" />lion<br />
    
    <input type="radio" name="ooo" value="aaa" />apple
    <input type="radio" name="ooo" value="bbb" />banana
    <input type="radio" name="ooo" value="ppp" />pineapple<br />
    <input type="reset" />
    <input type="submit" />
</form>

※fail.jsp和success.jsp自己隨便寫

※有些書用servlet寫jsp,可是現在工作時都在用MVC,所以現在應該很少人這樣寫了,檢核使用者輸入的值也都是前端用jQuery、ajax了,所以我全部沒寫

沒有留言:

張貼留言