移动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()) {// 说明这个用户名注册过,返回falseisExist = 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获取passworduser = 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