移动web最后的大作业我们组做的是实现类似新浪微博的功能。基本功能包括修改个人信息、发微博、看微博和回复数据库设计微博。我认为整个工程可以分为数据库设计、前台HTML、JSP和CSS开发、后台JavaScript设计。下面就依次看这几个部分。
一、数据库设计
用户类:登录不看微博的用户,个人属性包括用户id、用户姓名、登录密码、个性签名和头像。其中,用户姓名是不能重复的,登录密码和个性签名可以修改,头像上传功能没有实现(这个是我最遗憾的地方)
其他类我就不一一讲了,回复和评论有什么区别呢?评论是针对博客的,而回复是针对评论的(这种设计是根据QQ空间、新浪博客等平台的功能:你发了一个说说,好友可以对它发表评论,然后你又可以针对这个评论回复看法),但是在设计的时候不知道出了什么问题,回复竟然也是和博客有关的。当时应该是贪方便,没有设计得更完善。
所以啊,一开始数据库的设计很重要,不要以为看起来它很简单,就不认真设计,因为不合理的设计会导致后面网页开发的时候出现很大的困难。
二、JSP设计
1、数据库
① 数据库准备工作
写好了数据库代码之后,肯定要先在本地创建好数据库。在这里我用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代码获取时间。
2、其他部分
由于其他部分的代码比较多,我们就按照的博客的点开顺序来讲一下每一个JSP的关键点。但是在这之前再讲一个每一个JSP都要添加的一个东西:设置编码方式:
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
如果没有这两行的设置,浏览器在打开JSP的时候,不会打开一个网页,而会显示要下载JSP文件。
(1) 登录(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;
}
(2)注册账号(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;
}
(3)修改密码(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>");
}
}
(4)查看自己的所有博客(MyWB.jsp)
主要就是for循环和<% %>之间的嵌套:
(5)修改个人信息(account.jsp)
三、JavaScript
由于我对JavaScript的掌握还不够,所以设计基本是沿用模板,只是添加了返回时间(因为通过Java获取时间的话必须刷新网页,而发博客、发评论是不用刷新网页的)的代码,以及其他方面的处理。我就展示一下报告中的知识吧。
最后再说说innerHTML和outerHTML、innerText、value之间的区别:
innerHTML:对象从起始到终止位置的全部内容,包括HTML标签,不包括对象本身
outerHTML:innerHTML的内容加上对象本身
innerText:innerText去除HTML标签
value:表单元素一般没有innerHTML(除了select),用value取出值。另外textarea还可以用innerText