現要做一個簡單的登錄頁面,如果用戶通過驗證,會顯示Welcome用戶名的歡迎詞,反之則返回登錄頁面讓用戶再次輸入 這部分的完整代碼是JSPDemo項目里的login.jsp,下麵來分析一下關鍵代碼。 代碼位置 視頻位置 code/第3章/JSPDemo 視頻/第3章/JSP案例的講解 代碼位置 視頻 ...
現要做一個簡單的登錄頁面,如果用戶通過驗證,會顯示Welcome用戶名的歡迎詞,反之則返回登錄頁面讓用戶再次輸入
這部分的完整代碼是JSPDemo項目里的login.jsp,下麵來分析一下關鍵代碼。
代碼位置 |
視頻位置 |
code/第3章/JSPDemo |
視頻/第3章/JSP案例的講解 |
根據JSP的語法,可以通過@import來導入需要的jar包。這裡需要導入支持MySQL的庫文件,這部分的代碼如下所示。
1 <%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
2 <%@ page import="java.sql.*"%>
3 <%@ page import="com.mysql.jdbc.Driver" %>
JSP相當於在HTML頁面加上Java代碼,一般在<body>標簽里放入主要代碼。
首先來分析一下業務,當進入這個頁面的時候,需要判斷是否有用戶名和密碼信息輸入,以此來做不同的動作,所以在開始部分,需要用一個內嵌對象request來完成這個功能,主要代碼如下。
4 <body>
5 <%
6 if(request.getParameter("username") == null)
7 {
8 %>
9 <form method="post" action="login.jsp" name="userInfo" id="userInfo">
10 <table>
11 <tr>
12 <td>User Name</td>
13 <td><input type="text" name="username" id="username" /></td>
14 </tr>
15 <tr>
16 <td>Password </td>
17 <td><input type="password" name="password" id="password" /></td>
18 </tr>
19 <tr>
20 <td colospan="2" align="center">
21 <input type="submit" name="logon" value="Login" />
22 <input type="reset" name="reset" value="Reset" />
23 </td>
24 </tr>
25 </table>
26 </form>
我們看到,在JSP里是用<%...%>把Java代碼包含起來的,這裡用request.getParameter來讀取是否有username這個信息。request是個內嵌對象,可以不用定義就能直接使用,這裡用到它的獲取參數的方法。
在JSP里有不少內嵌對象,在項目里經常用到的是request、response、Session、out等,關於內嵌對象的知識大家不用硬記,可以在用到的時候查現成的API。
一旦發現沒有用戶名的信息輸入,那麼就需要用一個HTML的form來顯示供用戶輸入的視窗。
如果request.getParameter("username")不是null,即用戶已經輸入了用戶名,那麼就需要獲取用戶名和密碼信息,併到資料庫進行驗證,代碼如下所示。
27 <%
28 }
29 else
30 {
31 String username = request.getParameter("username").toString();
32 String pwd = "";
33 if(request.getParameter("password") != null)
34 {
35 pwd = request.getParameter("password").toString();
36 }
37 //connect to DB
38 Class.forName("com.mysql.jdbc.Driver");
39 Connection connection = null;
40 connection = DriverManager.getConnection(
41 "jdbc:mysql://localhost:3306/book", "root", "123456");
42 String sql = "select username from users where UserName = ?and Pwd = ?";
43 PreparedStatement pst = connection.prepareStatement(sql);
44 pst.setString(1, username);
45 pst.setString(2, pwd);
46 ResultSet rs=pst.executeQuery();
47 //can login
48 if(rs.next())
49 {
50 %>
51 Welcome,<%= rs.getString("username") %>
從上述代碼中的第31和35行得到了用戶名和密碼之後,用第38行的Class.forName載入了JDBC的驅動程式,然後在第43行定義了一個PreparedStatement來執行SQL語句,併在第46行用一個ResultSet來接收運行結果。
請大家註意,這裡用到的PreparedStatement是為了避免SQL註入,這部分的知識點大家可以看本書的資料庫相關的內容。
一旦通過第48行的if語句判斷rs.next()有返回對象,那麼就需要先在第50行用%>結束Java部分的JDBC訪問資料庫的代碼,隨後在第51行顯示Welcome的字樣。這裡能看到JSP的另外一個語法,用<%=%>來顯示變數的結果。
如果第48行里rs.next沒有返回,也就是說,在資料庫里找不到匹配的用戶信息,那麼就需要返回到登錄頁面,讓用戶再次輸入登錄信息,這部分的代碼如下。
52 <%
53 }
54 else
55 {
56 %>
57 <form method="post" action="login.jsp" name="userInfo" id="userInfo">
58 <table>
59 <tr>
60 <td>User Name</td>
61 <td><input type="text" name="username" id="username" /></td>
62 </tr>
63 <tr>
64 <td>Password </td>
65 <td><input type="password" name="password" id="password" /></td>
66 </tr>
67 <tr>
68 <td colospan="2" align="center">
69 <input type="submit" name="logon" value="Login" />
70 <input type="reset" name="reset" value="Reset" />
71 </td>
72 </tr>
73 </table>
74 </form>
75 <%
76 }
77 }
78 %>
79 </body>
80 </html>
這裡其實是代碼複製,又寫了一遍提供用戶名和密碼輸入的form。
JSP的語法不算簡單,但大家可以有選擇性地瞭解,從而把學習時間用到更重要的知識點(比如框架思想、優化思想)的學習上。
在上述代碼給出的例子中,能看到如下的缺陷:
①出現了代碼複製,把供用戶輸入的form複製了兩次。
②頻繁地切換JSP和HTML的邏輯,導致閱讀上和開發上的困擾,日後如果別人來維護這部分代碼,會很困難。
剛開始開發的時候這種缺陷還不明顯,當深入開發的時候,這種缺陷就會爆發。
①修改點一:我們需要調整供用戶驗證身份的Form代碼,加入驗證碼的輸入框。
我們不得不修改兩個重覆且相同的代碼,這樣不僅會增加工作量,而且一個疏忽就會導致忘記修改其中一個,增加代碼維護的難度。
②修改點二:要改成Oracle資料庫,而且數據表名和欄位都變了。
我們不僅需要修改JDBC的代碼,而且還要修改Welcome xxx這部分的顯示代碼,也就是說,資料庫方面的修改會直接牽涉其他類型的業務代碼。
③修改點三:需要實現“三次驗證不過就要鎖用戶”功能。
我們需要在JDBC部分的代碼計數,如果登錄次數小於3,那麼就需要重覆性地複製Form的代碼。如果超過三次,則還需要在Java代碼里夾雜一個“提示鎖屏”的顯示頁面,這會導致JSP更加混亂。
不是危言聳聽,我們見過不少頁面數量小於10的小項目,開發人員為了省事,直接在JSP里放入所有的功能,就像前面給出的例子一樣,交貨兩三個月後,當完成用戶提出若幹改進意見後,這些個JSP代碼就變得像天書一樣,閱讀性很差。
在提面試問題的時候,如果發現候選人使用“大而全”的開發方式,我們會讓面試者說出理由,如果理由類似“項目緊,缺人手,權衡下來寧可犧牲代碼的質量”,那麼說明面試者至少和MVC開發模式比較過,可以接受。如果面試者直接不知道MVC的開發模式,甚至不知道“大而全”的缺點,那麼我們的評價至少是“沒架構意識”。
如何改進?分解業務,用分層的方式來分解不同類型的業務。
具體來說,在JSP頁面里,剝離與顯示無關的代碼,一個好的JSP頁面里,應該少見甚至不用<%%>包含起來的Java代碼。