【Java学习笔记】63:从一个使用Model2模式的例子认识Servlet

还是跟着课本学习, 昨天一天都在配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>

测试运行

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值