还是跟着课本学习, 昨天一天都在配CentOS,我的Deepin又崩了,我再也不用32位的Deepin了。
简述
Model1模式下采用的是JSP+JavaBean+JDBC,其中JSP既负责向用户展示页面样式,又要负责和JavaBean交互。从MVC的视角来看,JavaBean在做模型的功能,JSP负责视图和控制器这两方面的功能。
而在Model2模式下,采用JSP+Servlet+JavaBean+JDBC的方式,其中的Servlet是一种运行在服务端的程序,可以接收并处理来自浏览器的请求。Servlet将原本Model1模式下JSP所具有的控制逻辑剥离,使JSP只剩下表现逻辑。从MVC的视角来看,JavaBean还是在做模型的功能,Servlet负责控制器的功能,此时JSP只需要关注视图这一功能。
数据库
在Java笔记62中建的TEST数据库中再建立一个LyTable表,用于存储留言:
USE TEST;
CREATE TABLE LyTable
(
id INT auto_increment PRIMARY KEY,
userId INT NOT NULL,
data DATETIME NOT NULL,
title VARCHAR(20) NOT NULL,
content VARCHAR(500) NOT NULL
);
如果数据库驱动已经放过在jre/lib/ext/目录下了,就不用再在WEB-INF/lib/下放了,不然可能引起冲突。
JSP文件
这类文件直接放在WebContent/(MyEclipse里叫WebRoot/)目录下,不可以放在受保护的WEB-INF/目录下。
login.jsp登录页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<%--设定背景颜色 --%>
<body bgcolor="#E3F0E3">
<%--登录页表单中使用处理登录的mainServlet,提交方式为post--%>
<form action="mainServlet" method="post">
<%--表格标签 --%>
<table>
<%--表格标题 --%>
<caption>用户登录</caption>
<%--每个tr双标签是表格中的一行 --%>
<tr>
<%--每个td双标签是表格中这一行中的一个普通列(单元格) --%>
<%--如果是th那就是表头单元格了 --%>
<td>用户名</td>
<td>
<%--输入文本框,输入的内容被命名为size,文本框长度为20 --%>
<input type="text" name="username" size="20">
</td>
</tr>
<tr>
<td>密码</td>
<td>
<%--密码框,输入内容被命名为username,密码框长度为20 --%>
<input type="password" name="password" size="20">
</td>
</tr>
</table>
<%--表单的提交 --%>
<input type="submit" value="登录" />
<input type="reset" value="重置"/>
</form>
<%--注链接到regis ter.jsp --%>
如果没有注册点击<a href="register.jsp">这里</a>注册.
</body>
</html>
error.jsp登录失败页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>出错</title>
</head>
<body>
登录失败!单击<a href="login.jsp">这里</a>返回。
</body>
</html>
register.jsp注册页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>[注册]简易留言板</title>
</head>
<body bgcolor="#E3F0E3">
<%--注册页表单中使用处理注册的registerServlet--%>
<form action="registerServlet" method="post">
<table>
<caption>欢迎加入简易留言板</caption>
<tr>
<td>
用户名
</td>
<td>
<input type="text" name="username"/>
</td>
</tr>
<tr>
<td>
密码
</td>
<td>
<input type="password" name="password"/>
</td>
</tr>
</table>
<input type="submit" value="注册"/>
<input type="reset" value="重置"/>
</form>
</body>
</html>
main.jsp留言板信息页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="myBean.*,myJDBC.*,java.util.*,java.sql.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>留言板信息</title>
</head>
<body bgcolor="#F3E3E3">
<%--这个表单的提交(按下留言时)指向单独的留言页面 --%>
<form action="liuyan.jsp" method="post">
<table border="1">
<caption>所有留言信息</caption>
<%--下面是表头 --%>
<tr>
<th>留言人</th>
<th>时间</th>
<th>标题</th>
<th>内容</th>
</tr>
<%--下面使用JSP脚本生成除了表头之外的行 --%>
<%
PreparedStatement ppstmt=null;
//建立连接
MySqlDBConn msdbc=new MySqlDBConn();
//获取连接的Connection对象的引用
Connection conn=msdbc.getConn();
//从session对象中获取之前查存进去的存所有留言的ArrayList
ArrayList<LyTable> al=(ArrayList<LyTable>)session.getAttribute("al");
//获得这个ArrayList的迭代器
Iterator<LyTable> itrtr=al.iterator();
//只要迭代到的位置其后还有需要迭代到的元素
while(itrtr.hasNext()){
//建立留言的JavaBean对象,获取这个需要迭代到的元素并存进去
LyTable ly=(LyTable)itrtr.next();
String usr=null;
try{
//建立备好的SQL语句对象:查找这个表每行的username
//这是因为username是没有存在这个session中的ArrayList里的
//但是在留言板的表中却要使用这个username
//因此单独把这一字段使用session中存的id查出来
String sql="SELECT username FROM userTable WHERE id=?";
ppstmt=conn.prepareStatement(sql);
//从ArrayList的这个元素中获得id,然后替代SQL中的'?'
ppstmt.setInt(1, ly.getUserId());
//执行查询:根据ArrayList里的各个id查出其留言着名username
ResultSet rs=ppstmt.executeQuery();
//if仅仅确保查出了用户名username
if(rs.next()){
usr=rs.getString(1);
}
}catch(SQLException e){
e.printStackTrace();
}
%>
<%--获得username以后,结合session中的ArrayList,
就具备留言板的所有信息了,将这些信息展示在表中 --%>
<tr>
<%--嵌入的java脚本中的变量,必须使用表达式才能放在html中 --%>
<td><%=usr%></td>
<%--其它的属性直接使用JavaBean的get*获取 --%>
<td><%=ly.getDate().toString()%></td>
<td><%=ly.getTitle()%></td>
<td><%=ly.getContent()%></td>
</tr>
<%
}
%>
</table>
<input type="submit" value="添加留言"/>
</form>
</body>
</html>
liuyan.jsp添加留言页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>留言板</title>
</head>
<body bgcolor="#F3E3E5">
<%--留言页表单中使用提交留言的addServlet--%>
<form action="addServlet" method="post">
<table border="1">
<caption>请输入留言内容</caption>
<tr>
<td>留言标题</td>
<td>
<%--表单输入控件:单行文本框 --%>
<input type="text" name="title">
</td>
</tr>
<tr>
<td>留言内容</td>
<td>
<%--表单输入控件:滚动文本框 --%>
<textarea name="content" rows="5" cols="35"></textarea>
</td>
</tr>
</table>
<input type="submit" value="提交" />
<input type="reset" value="重置" />
</form>
</body>
</html>
JavaBean类
myBean包下LyTable.java
package myBean;
import java.io.Serializable;
import java.sql.Date;
//留言表(LyTable)对应的JavaBean
public class LyTable implements Serializable {
private Integer id;
private Integer userId;
private Date date;
private String title;// 留言标题
private String content;// 留言内容
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
myBean包下UserTable.java
package myBean;
import java.io.Serializable;
//用户表(userTable)对应的JavaBean
public class UserTable implements Serializable {
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
数据库相关类
myJDBC包下MySqlDBConn.java
package myJDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
//用于操作数据库的类
public class MySqlDBConn {
private Statement stmt = null;
private Connection conn = null;
ResultSet rs = null;
// 在构造器中连接
public MySqlDBConn() {
try {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 建立连接
String url = "jdbc:mysql://localhost:3306/TEST?useSSL=true&characterEncoding=utf8";
conn = DriverManager.getConnection(url, "root", "3838438");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 获取Connection对象的引用,方便后面的编程
public Connection getConn() {
return this.conn;
}
// 提供做查询的服务
public ResultSet executeQuery(String sql) {
try {
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
// 关闭SQL语句对象
public void closeStmt() {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 关闭连接
public void closeConn() {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Servlet类
通过继承HttpServlet类并覆盖其doGet和doPost方法,可以快速构建基于HTTP协议访问服务器端资源时的Servlet服务。
myServlet包下AddServlet.java
package myServlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import myBean.LyTable;
import myBean.UserTable;
import myJDBC.MySqlDBConn;
//用于添加留言的Servlet:当用户提交留言标题和留言内容以做留言时
public class AddServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设定请求的编码
req.setCharacterEncoding("UTF-8");
// 获取提交来的留言标题
String title = req.getParameter("title");
// 获取提交来的留言内容
String content = req.getParameter("content");
// 获取session对象,因为已经登录了所以一定不为空
// 并且在前面登录用的Servlet中已经存了用户信息和所有的留言信息进去
HttpSession hs = req.getSession();
// 从session中获取用户信息的JavaBean对象
UserTable user = (UserTable) hs.getAttribute("user");
// 建立留言表对应的JavaBean,将用户提交的留言信息封装进去
LyTable ly = new LyTable();
ly.setUserId(user.getId());// 用户id
ly.setDate(new Date(System.currentTimeMillis()));// 系统当前时间,注意在包sql.Date
ly.setTitle(title);// 留言标题
ly.setContent(content);// 留言内容
// 读出session里保存的ArrayList
ArrayList<LyTable> al = (ArrayList<LyTable>) hs.getAttribute("al");
// 将这条新的留言添加进session
// 之所以这样做,而不是仅仅添加到数据库,是因为这样刷新主页时候就不用再去查询数据库留言表了
al.add(ly);
// 下面是将这条留言插入数据库的部分,这回使用另一种sql语句对象
PreparedStatement ppstmt = null;
// 连接数据库
MySqlDBConn msdbc = new MySqlDBConn();
// 获取连接好的对象connection对象的引用,给后面的PreparedStatement对象使用
Connection conn = msdbc.getConn();
try {
// 按插入语句的格式制定这个连接对象
ppstmt = conn.prepareStatement("INSERT INTO LyTable(userId,data,title,content) VALUES(?,?,?,?)");
// 为语句中的'?'替换为实际要使用的值
System.out.println(ly.getUserId() + "/" + ly.getDate() + "/" + ly.getTitle() + "/" + ly.getContent());
ppstmt.setInt(1, ly.getUserId());// 用户id
ppstmt.setDate(2, ly.getDate());// 留言时间
ppstmt.setString(3, ly.getTitle());// 留言标题
ppstmt.setString(4, ly.getContent());// 留言内容
int ok = ppstmt.executeUpdate();// 执行插入,注意是executeUpdate()
if (ok == 1)
resp.sendRedirect("main.jsp");// 当插入成功时才能执行到这句,跳转到主页面
} catch (SQLException e) {
e.printStackTrace();
// 当插入失败时,会在catch块里捕获到异常,这时去留言页面
resp.sendRedirect("liuyan.jsp");
}
}
// 在doPost中直接调用doGet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
myServlet包下MainServlet.java
package myServlet;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import myBean.LyTable;
import myBean.UserTable;
import myJDBC.MySqlDBConn;
//用于登录验证的Servlet:当用户提交用户名和密码登录时
public class MainServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求编码
req.setCharacterEncoding("UTF-8");
// 获取提交来的用户名
String usr = req.getParameter("username");
// 获取提交来的密码
String pwd = req.getParameter("password");
// 记录是否验证成功
boolean validated = false;
// 用构造器建立和数据库的连接
MySqlDBConn msdbc = new MySqlDBConn();
// 获得session对象用于保存登录用户信息
HttpSession hs = req.getSession();
// 用户表的JavaBean的对象
UserTable user = null;
// 尝试从session对象中获取,如session中已经没了则为空
user = (UserTable) hs.getAttribute("user");
// session对象里没有时才需要重新查询登录
if (user == null) {
String sql = "SELECT * FROM userTable";
ResultSet rs = msdbc.executeQuery(sql);
try {
while (rs.next()) {
System.out.println(rs.getString("username"));
System.out.println(rs.getString("password"));
System.out.println(usr);
System.out.println(pwd);
if ((rs.getString("username").trim().compareTo(usr) == 0)
&& (rs.getString("password").trim().compareTo(pwd) == 0)) {
// 如果查到了,建立这个JavaBean的对象
user = new UserTable();
user.setId(rs.getInt(1));
user.setUsername(rs.getString(2));
user.setPassword(rs.getString(3));
// 以"user"为名保存在session对象中,则下次就不需要验证了
hs.setAttribute("user", user);
// 验证成功
validated = true;
break;
}
}
rs.close();// 结果集用完直接关闭
} catch (SQLException e) {
e.printStackTrace();
}
msdbc.closeStmt();// SQL语句对象的关闭
}
// session对象里有时直接通过验证
else {
validated = true;
}
/* 根据是否验证成功,决定要跳转到哪个页面去 */
// 验证成功则需要去主界面
if (validated) {
// 用于暂存所有留言的ArrayList
ArrayList<LyTable> al = new ArrayList<LyTable>();
// 这个留言板是共用的,所以直接从留言表中取出所有信息
String sql = "SELECT * FROM LyTable";
ResultSet rs = msdbc.executeQuery(sql);
try {
// 对于留言表中的每一行
while (rs.next()) {
// 先放入临时的留言JavaBean对象中
LyTable ly = new LyTable();
ly.setId(rs.getInt(1));
ly.setUserId(rs.getInt(2));
ly.setDate(rs.getDate(3));
ly.setTitle(rs.getString(4));
ly.setContent(rs.getString(5));
// 再将这个对象放入ArrayList里存下来
// 这样下个循环建立ly的新引用时之前的对象也还在ArrayList里
al.add(ly);
}
rs.close();// 结果集用完直接关闭
} catch (SQLException e) {
e.printStackTrace();
}
msdbc.closeStmt();
// 将这些留言组成的ArrayList命名为al存在session中
hs.setAttribute("al", al);
// 验证成功需要跳转到main.jsp
resp.sendRedirect("main.jsp");
}
// 验证失败时
else {
// 直接跳转到失败页面
resp.sendRedirect("error.jsp");
}
}
// 在doPost中直接调用doGet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
myServlet包下RegisterServlet.java
package myServlet;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import myJDBC.MySqlDBConn;
//用于注册的Servlet:当用户提交用户名和密码注册时
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求编码
req.setCharacterEncoding("UTF-8");
// 获取提交来的用户名
String usr = req.getParameter("username");
// 获取提交来的密码
String pwd = req.getParameter("password");
// 向数据库中尝试插入提交来的用户名和密码
PreparedStatement ppstmt = null;
// 建立连接
MySqlDBConn msdbc = new MySqlDBConn();
// 获取连接对象,给PreparedStatement用
Connection conn = msdbc.getConn();
try {
// 备好要插入的表和插入格式
ppstmt = conn.prepareStatement("INSERT INTO userTable(username,password) VALUES(?,?)");
// 替换'?'
ppstmt.setString(1, usr);
ppstmt.setString(2, pwd);
int ok = ppstmt.executeUpdate();// 执行之
// 插入成功时,跳转回登录页面即可
if (ok == 1)
resp.sendRedirect("login.jsp");
} catch (SQLException e) {
e.printStackTrace();
// 插入失败时实际上可以再做点事情,课本上没做
}
}
// 在doPost中直接调用doGet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
XML配置文件
WEB-INF下的web.xml
这是最重要的一个项目配置文件,在建立项目时勾选生成,并修改这个文件,以配置包括但不限于起始页面和各个Servlet的使用名称等重要信息。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>JSPExample</display-name>
<welcome-file-list>
<!-- 登录页面作为起始页面 -->
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<!-- 对于三个Servlet的配置 -->
<servlet>
<!-- 自己起的Servlet的名称 -->
<servlet-name>mainServlet</servlet-name>
<!-- 指出Servlet是哪个类,如果在包里要把包也打上 -->
<servlet-class>myServlet.MainServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>addServlet</servlet-name>
<servlet-class>myServlet.AddServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>registerServlet</servlet-name>
<servlet-class>myServlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<!-- Servlet名,需要和上面一样 -->
<servlet-name>mainServlet</servlet-name>
<!-- Servlet运行路径名,自己起一个就行 -->
<url-pattern>/mainServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>addServlet</servlet-name>
<url-pattern>/addServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>registerServlet</servlet-name>
<url-pattern>/registerServlet</url-pattern>
</servlet-mapping>
</web-app>