課程Project總結 - 移動web大作業(不看微博)
移動web最后的大作業我們組做的是實現類似新浪微博的功能。基本功能包括修改個人信息、發微博、看微博和回復數據庫設計微博。我認為整個工程可以分為數據庫設計、前臺HTML、JSP和CSS開發、后臺JavaScript設計。下面就依次看這幾個部分
數據庫設計

用戶類:登錄不看微博的用戶,個人屬性包括用戶id、用戶姓名、登錄密碼、個性簽名和頭像。其中,用戶姓名是不能重復的,登錄密碼和個性簽名可以修改,頭像上傳功能沒有實現(這個是我最遺憾的地方)
其他類我就不一一講了,回復和評論有什么區別呢?評論是針對博客的,而回復是針對評論的(這種設計是根據QQ空間、新浪博客等平臺的功能:你發了一個說說,好友可以對它發表評論,然后你又可以針對這個評論回復看法),但是在設計的時候不知道出了什么問題,回復竟然也是和博客有關的。當時應該是貪方便,沒有設計得更完善。
所以啊,一開始數據庫的設計很重要,不要以為看起來它很簡單,就不認真設計,因為不合理的設計會導致后面網頁開發的時候出現很大的困難。
JSP設計
數據庫
數據庫準備工作
寫好了數據庫代碼之后,肯定要先在本地創建好數據庫。在這里我用wampServer提供的mysql,然后用下面的指令導入:(要先創建Blog database)
mysql -u root -p blog < blog.sql
用Navicat查看數據庫是否成功創建:

接著把mysql-connector-java-5.1.36-bin.jar文件拷貝到tomcat目錄的lib子目錄下,這樣JSP才能引入連接數據庫的庫。
數據庫數據類型引入
數據庫里的實體集有用戶、博客、評論和回復,為了之后方便存儲數據,在JSP中也創建這幾個類,然后定義相同的屬性和方法。比如用戶,有uid、name和signature等
// Test.jsp - User類
class User{
public String nickname;
public String password;
public String signature;
public String head;
public User(String n, String p, String s, String h) {
nickname = n;
password = p;
signature = s;
head = h;
}
public User() {
nickname = password = signature = head = "";
}
}
注意:雖然這個JSP文件的User類沒有定義uid,但是在展示博客的JSP頁面的User類有uid。有沒有uid其實是看頁面的要求,可以靈活變通。
連接數據庫
代碼如下:
String connectString = "jdbc:mysql://localhost:3306/blog"
+ "?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8";
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(connectString, "root", "");
} catch (Exception e) {
try {
out.print(e.getStackTrace());
}
catch (Exception ee) {}
}
數據庫操作(選擇、插入、修改、刪除)
四種操作中,最復雜的就是選擇,因為后三種操作返回的就是一個整數,表示受影響的行數。而選擇操作返回的是一個ResultSet,相當于一個Iterator,可以用遍歷的方式獲取里面的數據。
首先看看插入操作:
boolean insertUser(User user){
try {
String sql = String.format("insert into User(nickname, password, signature, head)"+
"values('%s', '%s', '%s', '%s');", user.nickname, user.password, user.signature, user.head);
state = conn.createStatement();
resultInt = state.executeUpdate(sql);
}
catch (Exception e) {return false;}
return resultInt >= 1;
}
修改和刪除操作不同之處就是指令。再看看選擇操作,這里選擇了最復雜的部分,獲取所有的博客:
Blog[] getAllBlog() {
List<Blog> list = new ArrayList<Blog>();
try {
String sql = "select * from Blog";
state = conn.createStatement();
resultSet = state.executeQuery(sql);
while (resultSet.next()) {
String bid = resultSet.getString("bid");
String content = resultSet.getString("content");
String btime = resultSet.getString("btime");
list.add(new Blog(bid, content, btime));
}
}
catch (Exception e) {}
return (Blog[]) list.toArray(new Blog[list.size()]);
}
關鍵在于通過resultSet獲取每一行的數據的方法(getString(columnName))以及把 list 轉化為數組的方法。
獲取當前時間
博客、評論、回復都需要存儲創建的時間。JSP(Java)用下面的方式獲取:
String getCurrentTime() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//return df.format(new Date());
String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());
return date;
}
但是要注意:這種方法獲取的時間在頁面刷新之后才會更新,所以在獲取發微博的時間的時候不能用這種方法,因為頁面不用刷新。而應該用JavaScript代碼獲取時間。
其他部分
由于其他部分的代碼比較多,我們就按照的博客的點開順序來講一下每一個JSP的關鍵點。但是在這之前再講一個每一個JSP都要添加的一個東西:設置編碼方式:
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
如果沒有這兩行的設置,瀏覽器在打開JSP的時候,不會打開一個網頁,而會顯示要下載JSP文件。
登錄(login.jsp)
登錄界面最重要的功能就是登錄,首先輸入賬號和密碼,然后按登錄按鈕,檢查賬號和密碼是否正確,如果正確就跳轉到另一個界面,否則依然回到登錄界面。還有一些到修改密碼界面、注冊新用戶的功能。
判斷登錄賬號和密碼是否正確
這里用到了POST方法來傳輸數據,依然發送到login.jsp,所以頁面首先會刷新一下,再進行判斷。判斷的方法很簡單:檢查數據庫里是否有相同的賬號和密碼。
<%
// 如果登錄失敗,顯示提示信息
String name = request.getParameter("userId");
String password = request.getParameter("passWord");
NAME = name;
boolean loginSuccess = false;
if (name == null || password == null) {}
else if (connect() && login(name, password)) {
loginSuccess = true;
}
else {
%>
<br/><br/>
<font id="LoginFail" style=" font-size:20px; color:red; margin-left: 255px;">登錄失敗!</font>
<%
}
%>
boolean login(String nickname, String password) {
try {
String sql = String.format("select * from User where nickname = '%s';", nickname);
state = conn.createStatement();
resultSet = state.executeQuery(sql);
if (resultSet != null && resultSet.next()) {
// 說明找到了用戶
if (password.equals(resultSet.getString("password"))) return true;
else return false;
}
else return false;
}
catch (Exception e) {return false;}
}
補充:后來我覺得,登錄失敗的文字不應該直接在網站上顯示,用顯示對話框的形式可能會更好:
if (name == null || password == null) {}
else if (connect() && login(name, password)) {
loginSuccess = true;
}
else {
out.print("<script>alert('登錄失敗!');</script>");
}
可見通過JSP代碼顯示JavaScript很簡單,用out.print("<script>alert('string')</script>");這種形式就可以了。
登錄成功后的跳轉
一開始我用上面的函數跳轉網頁:
public void jump3(HttpServletRequest request, HttpServletResponse response, String username) throws Exception{
response.setCharacterEncoding("utf-8");
response.setHeader("iso-8859-1","utf-8");
request.setCharacterEncoding("utf-8");
String name = request.getParameter("name");
String psd = request.getParameter("psd");
response.setHeader("Refresh","1;url=MyWB.jsp?user="+username);
}
但是這種方法比較麻煩,還有一種方法,就是用到上面通過out.print()展示JavaScript代碼的方式。代碼如下:
if (loginSuccess) {
String urlUser = getUrlString(NAME);
out.print("<script>window.location.href='MyWB.jsp?user="+urlUser+"'</script>");
}
不過這種方法要先對參數處理一下。如果參數中有空格,直接作為url傳輸是不行的,必須把空格替換成%20:
//獲取用于URL傳輸的字符串
String getUrlString(String str) {
String urlStr = "";
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == ' '){
urlStr += "%20";
}
else urlStr += String.valueOf(str.charAt(i));
}
return urlStr;
}
注冊賬號(register.jsp)
首先看看注冊界面是怎樣的:

所以注冊界面主要的功能就是輸入用戶的信息(包括用戶名、個性簽名、密碼和確認密碼、確認條款)。不過這些信息的輸入是有要求的:用戶名不能和當前已有的重復、密碼和確認密碼必須一樣、以及必須確認條款。所以,注冊成功是一種情況,注冊失敗分幾種情況,下面是判斷注冊情況的代碼:
int registerSuccess = ALLNULL;
String name = request.getParameter("userID");
String signature = request.getParameter("userName");
String password = request.getParameter("userPass");
String rPassword = request.getParameter("userRpass");
String[] checkbox = request.getParameterValues("checkbox");
if (name == null || password == null || rPassword == null) {
registerSuccess = ALLNULL;
}
else if (name == "" || password == "" || rPassword == "") {
registerSuccess = SOMENULL;
}
else if (checkbox == null) {
// 當這個為空的時候,說明沒有同意協議
registerSuccess = NOTAGREE;
}
else if (!password.equals(rPassword)) registerSuccess = PASSWORDDIFF;
else if (connect() && insertUser(new User(name, password, signature, ""))) {
registerSuccess = SUCCESS;
}
else registerSuccess = FAIL;
為什么要有ALLNULL這種情況分析呢?因為注冊界面是通過login.jsp跳轉過來的,所以第一次跳轉到注冊界面的時候,通過string.getParameter()獲取的變量都是null,所以ALLNULL代表的意思就是第一次進入注冊界面。特別判斷這種情況的目的是區分其他注冊失敗的情況,避免ALLNULL的時候也輸出登錄失敗的結果。
SOMENULL的意思就是注冊信息不完整,無法注冊。
通過這兩種情況的區分,我們可以知道通過POST傳遞的數據,如果是通過本網頁跳轉,而且沒有輸入,那么返回的結果就是空字符串(checkbox除外,接下來會講)。如果是通過其他網頁跳轉過來的,url中沒有這個參數,那么得到的就是null。
NOTAGREE就是沒有確認條款的情況。注意:checkbox用POST方法傳送的是一個字符串數組。如果沒有勾選相同name的任何checkbox,返回的自字符串數組就為null,否則字符串里面的值就是checkbox的value屬性值(不指明則為on)。
下面通過TestCheckbox.jsp測試:
<body>
<%
String[] checkbox = request.getParameterValues("checkbox");
if (checkbox != null) {
out.print("<p>" + checkbox.length + "</p>");
for (String str : checkbox) {
out.print(str);
}
}
else out.print("checkbox為空!");
%>
<form action="TestCheckbox.jsp">
<input name="checkbox" type="checkbox" id="checkbox1" value="呵呵呵"/> 這是checkbox1 <br />
<input name="checkbox" type="checkbox" id="checkbox2" value="哈哈哈"/> 這是checkbox2 <br />
<input value="點擊提交" id="button" type="submit" />
</form>
</body>


最后是數據庫的操作了,先判斷當前的用戶名是否在數據庫中已經存在,如果沒有,就插入User,否則返回false。
boolean insertUser(User user){
try {
// 首先要檢查用戶名是否已經被其他人注冊過,如果是的話,不能注冊
String sql = String.format("select * from User where nickname = '%s';", user.nickname);
state = conn.createStatement();
resultSet = state.executeQuery(sql);
if (resultSet.next()) {
// 說明這個用戶名注冊過,返回false
isExist = true;
return false;
}
isExist = false;
sql = String.format("insert into User(nickname, password, signature, head) "+
"values('%s', '%s', '%s', '%s');", user.nickname, user.password, user.signature, user.head);
//state = conn.createStatement();
resultInt = state.executeUpdate(sql);
}
catch (Exception e) {return false;}
return resultInt >= 1;
}
修改密碼(findpassword.jsp -> 這個名字有點問題)

修改密碼的邏輯比較簡單,首先輸入的當前密碼要正確,其次,新密碼和重復新密碼要一致。不過解釋了。
ref_username = request.getParameter("username");
if (ref_username != null) {
// 第一次到這個jsp,到達ref_username獲取password
user = getUser(ref_username);
// 如果user為空,說明用戶不存在,則會跳回到login
//out.print("<script>alert('呵呵呵');</script>");
if (user == null) {
out.print("<script>alert('用戶不存在!');window.location.href='login.jsp';</script>");
}
else oldPass = user.password;
}
else {
// 通過提交按鈕到達,此時需要檢查兩個地方:一個是新密碼和重復新密碼是否相同,另一個是舊密碼是否匹配
String pass1 = request.getParameter("textfield1");
String pass2 = request.getParameter("textfield2");
String pass3 = request.getParameter("textfield3");
if (pass1 == "") {
out.print("<script>alert('請輸入當前密碼!')</script>");
}
else if (pass2 == "") {
out.print("<script>alert('請輸入新密碼!')</script>");
}
else if (!pass2.equals(pass3)) {
out.print("<script>alert('新密碼和重復新密碼不一致!')</script>");
}
else if (!pass1.equals(oldPass)) {
out.print("<script>alert('當前密碼錯誤!')</script>");
}
else {
// 現在可以更新了
updatePass(user.nickname, pass2);
out.print("<script>alert('修改密碼成功!')</script>");
}
}
查看自己的所有博客(MyWB.jsp)

主要就是for循環和<% %>之間的嵌套:

修改個人信息(account.jsp)

JavaScript
由于我對JavaScript的掌握還不夠,所以設計基本是沿用模板,只是添加了返回時間(因為通過Java獲取時間的話必須刷新網頁,而發博客、發評論是不用刷新網頁的)的代碼,以及其他方面的處理。我就展示一下報告中的知識吧。

最后再說說innerHTML和outerHTML、innerText、value之間的區別:
innerHTML:對象從起始到終止位置的全部內容,包括HTML標簽,不包括對象本身
outerHTML:innerHTML的內容加上對象本身
innerText:innerText去除HTML標簽
value:表單元素一般沒有innerHTML(除了select),用value取出值。另外textarea還可以用innerText

浙公網安備 33010602011771號