Jdbc入门介绍第二章——Jdbc结合JSP和Servlet的简单综合应用

来源:互联网 发布:mac更改桌面图标大小 编辑:程序博客网 时间:2024/06/11 14:21

接下来我们来做结合Servlet和JSP技术的简单的综合应用。
首先新建一个web项目,将之前的工具类和oracle驱动贴在相应的位置,如图

这里写图片描述

Web项目添加驱动Jar有个方便的方法,直接将jar文件复制到WebRoot/WEB-INF/lib目录下就行类,当然用我上面讲述的方法同样适用。接下来,我在DBUtil工具类中添加了关闭资源的代码:

/**     * 关闭所有资源     */    public static void closeAll(ResultSet rs, Statement st)    {        try        {            //先从结果集关闭            if (null != rs)            {                rs.close();                rs = null;            }        }        catch (Exception e)        {            e.printStackTrace();        }        finally        {            try            {                //Statement接口关闭                if (null != st)                {                    st.close();                    st = null;                }            }            catch (SQLException e)            {                e.printStackTrace();            }            finally            {                try                {                    if (null != con)                    {                        if (con.getAutoCommit())                        {                            //最后数据库连接关闭                            con.close();                            con = null;                        }                    }                }                catch (SQLException e)                {                    e.printStackTrace();                }            }        }    }}                catch (SQLException e)                {                    e.printStackTrace();                }            }        }    }

接下来,需要一个jdbc操作模板,我们将JDBC对数据库的基本操作定义在这个模板类中,不再是上个例子中写在测试类中类,我将模板类命名为JDBCTemplate类。具体代码如下:

package com.java.jdbc.jdbctemplate;import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import java.util.ArrayList;import com.java.jdbc.util.DBUtil;public abstract class JDBCTemplate<T> {    private Connection con;    private PreparedStatement ps;    private ResultSet rs;    // 增删改    public boolean update(String sql, Object... params) throws Exception {        int res = 0;        con = DBUtil.getCon();        ps = con.prepareStatement(sql);        //params是一个存储参数的数组        if (null != params)            for (int i = 0; i < params.length; i++) {                ps.setObject(i + 1, params[i]);            }        res = ps.executeUpdate();        DBUtil.closeAll(rs, ps);        if (res > 0)            return true;        else            return false;    }    // 查    public ArrayList<T> select(String sql, Class c, Object... params) {        ArrayList<T> lst = new ArrayList<T>();        con = DBUtil.getCon();        try {            ps = con.prepareStatement(sql);            if (null != params)                for (int i = 0; i < params.length; i++) {                    ps.setObject(i + 1, params[i]);                }            rs = ps.executeQuery();            while (rs.next()) {                lst.add(getObject(rs, c));            }        } catch (SQLException e) {            e.printStackTrace();        } finally {            DBUtil.closeAll(rs, ps);        }        if (lst.size() == 0)            return null;        return lst;    }    /**     * 通过反射得到某个对象     */    private T getObject(ResultSet rs, Class c) {        T t = null;        String colName = null;        String methodName = null;        String colType = null;        try {            // 对象的实例            t = (T) c.newInstance();            // 所有公共方法            Method[] ms = c.getMethods();            // 得到元数据            ResultSetMetaData rsmd = rs.getMetaData();            // 查询的所有列            int colCount = rsmd.getColumnCount();            for (int i = 0; i < colCount; i++) {                // 得到列名                colName = rsmd.getColumnName(i + 1); //                // 得到类型                colType = rsmd.getColumnTypeName(i + 1);                // 拼接成set方法 setId setName setBirth setGender setAddress                methodName = "set" + colName.substring(0, 1).toUpperCase()                        + colName.substring(1);                // 得到set方法                for (Method m : ms) {                    if (m.getName().equalsIgnoreCase(methodName)) {                        // 调用set方法                        if ("NUMBER".equalsIgnoreCase(colType)) {                            try {                                m.invoke(t, rs.getInt(colName));                            } catch (Exception e) {                                m.invoke(t, rs.getBoolean(colName));                            }                        } else                            m.invoke(t, rs.getObject(colName));                    }                }            }        } catch (Exception e) {            e.printStackTrace();        }        return t;    }}

对JDBCTemplate做一下简单的分析:
boolean update(String sql, Object… params)
该方法用于增删改,返回布尔类型,与之前例子不同的是,它可以传递任意个参数,可以与通配符相匹配。可能说到这,有人已经明白,也有人不明白,先有个概念,这个例子会着重讲解JDBC通配符通过PreparedStatement对象的应用。

ArrayList select(String sql, Class c, Object… params)
该方法用于查询,返回一个集合 。运用到泛型和反射的一些技术。
其实本例中着重点还是JDBC和其他技术的综合应用,有些技术不会没关系,我们先有个概念,然后知道设计思路就OK了,代码千千万万,不同的项目,代码肯定是有所区别,关键掌握原理,理清思路。

接下来,我们需要建一张表,为了方便,我直接在oracle中建表,名为USERINFO。

CREATE TABLE USERINFO(   USERID INT PRIMARY KEY,   USERNAME VARCHAR2(40) UNIQUE,   PWD VARCHAR2(50) NOT NULL,   GENDER NUMBER(1) NOT NULL,   BIRTHDAY DATE NOT NULL,   INTEREST VARCHAR2(50) NOT NULL);

为了实现USERID自动增长,我定义类一个序列,代码如下:

CREATE SEQUENCE SE_USERINCREMENT BY 1START WITH 1MAXVALUE 100000;

USERINFO表创建完后,需要在定义一个实体类名为UserInfo
代码如下:

package com.java.test.entiy;import java.util.Date;public class UserInfo {    private int userId;    private String userName;    private String pwd;    private boolean gender;    private Date birthday;    private String interest;    public int getUserId() {        return userId;    }    public void setUserId(int userId) {        this.userId = userId;    }    public String getUserName() {        return userName;    }    public void setUserName(String userName) {        this.userName = userName;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }    public boolean isGender() {        return gender;    }    public void setGender(boolean gender) {        this.gender = gender;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public String getInterest() {        return interest;    }    public void setInterest(String interest) {        this.interest = interest;    }}

简单分析一下实体类,java是一门面向对象的语言,我们在数据库中创建类一张表,我们根据这张表创建一个对应的实体类,就可以通过操作该对象而映射到数据库表中。
建完实体类后,需要一个专门操作该实体类的操作类,把它定义为UserDao类,属于用户数据的访问层,该类用于专门操作USERINFO表的数据。具体代码如下:

package com.java.jdbc.dao;import java.util.ArrayList;import com.java.jdbc.jdbctemplate.JDBCTemplate;import com.java.test.entiy.UserInfo;/** * 用户数据访问层 * @author think */public class UserDao extends JDBCTemplate<UserInfo> {    // 查询所有用户    public ArrayList<UserInfo> findAll() {        return this.select("select * from UserInfo", UserInfo.class);    }    // add用户    public boolean AddUser(UserInfo userInfo) throws Exception {        return this.update(                "insert into USERINFO values(SE_USER.nextVal, ?, ?, ?, ?, ?)",                 userInfo.getUserName(),                userInfo.getPwd(),                userInfo.isGender() == true ? Integer.parseInt("1") : Integer.parseInt("0"),                 userInfo.getBirthday(),                 userInfo.getInterest());    }    // 根据主键删除学生    public boolean deleteUser(int id) throws Exception {        return this.update("delete from UserInfo where userid=?", id);    }    public boolean updateUser(UserInfo userInfo) throws Exception {        return update("update UserInfo set username = ?, pwd = ?, gender = ?, birthday = ?, interest = ? where userid=?",                userInfo.getUserName(),                userInfo.getPwd(),                userInfo.isGender() == true ? Integer.parseInt("1") : Integer.parseInt("0"),                 userInfo.getBirthday(),                 userInfo.getInterest(), userInfo.getUserId());    }}

简单分析一个该类,UserDao类继承之前的JDBC操作模板,即JDBCTemplate类,使之有了操作数据库的功能。
我在该类中定义类四个方法
1、public boolean AddUser(UserInfo userInfo)添加用户方法
这时传递的参数是一个UserInfo类型,当我们要添加的数据躲起来后,我们可以考虑用对象封装数据,而该方法又是添加用户信息,所以,这时候我们创建的实体类就发挥作用,存储我们需要添加到数据库USERINFO的数据,通过该法添加到数据库USERINFO中。

该方法返回语句中的
“insert into USERINFO values(SE_USER.nextVal, ?, ?, ?, ?, ?)”
有5个?,在之前提起过,这?就是JDBC的通配符,用于获取与之相对应的值。
比如USERINFO表的第一列是USERID,我固定用序列SE_USER的nextVal方法实现自增。第二列是USERNAME,是VARCHAR2类型,这时我们sql语句中的第一个通配符?就对应该列。以此类推第二个通配符对应USERINFO表的第三列……

到此有一个疑问,为什么通配符就能对应数据库中表的相应列呢?
这时我们回头看JDBCTemplate类中的public boolean update(String sql, Object… params)方法,有这么一段代码:
if (null != params)
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
可以看出,是PreparedStatement对象通过setObject方法完成通配符与表中列对应的作用。需要注意一点的是,该set方法一般和参数的类型相对应,比如String类型的参数,就应该setString( 第几位通配符 , param);

2、public boolean deleteUser(int id)通过主键删除用户,这时候传递的参数就不再是实体类型类,当参数较少时可以直接传递,无需封装。其中sql语句”delete from UserInfo where userid=?”原理与添加用户一致。
其他方法原理一致,也就不在阐述了。
至此数据库的数据访问完成。
接下来开始设计JSP页面(view)
先在WebRoot目录下新建一个adduser文件夹,在adduser文件夹添加adduser.jsp

这里写图片描述

adduser.jsp主要代码添加到<body>标签里如下:

<form action="showUser.html" method="post">        <table>            <tr>                <td>用户名:</td>                <td><input name="username" value=""></td>            </tr>            <tr>                <td>密码:</td>                <td><input type="password" name="pwd" value=""></td>            </tr>            <tr>                <td>性别:</td>                <td>                <input type="radio" name="gender" value="true"><input type="radio" name="gender" value="false"></td>            </tr>            <tr>                <td>生日:</td>                <td>                <select name="birthday">                        <option value="1995-8-1">1995-8-1</option>                        <option value="1995-8-2">1995-8-2</option>                        <option value="1995-8-3">1995-8-3</option>                </select>                </td>            </tr>            <tr>                <td>兴趣:</td>                <td>篮球 <input type="checkbox" name="interest" value="篮球">&nbsp;&nbsp;                    足球 <input type="checkbox" name="interest" value="足球">&nbsp;&nbsp;                    网球 <input type="checkbox" name="interest" value="网球">&nbsp;&nbsp;                </td>            </tr>            <tr>                <td colspan="2" align="center"><input type="submit" value="add">&nbsp;                </td>            </tr>        </table>    </form>

这里写图片描述

可以看出adduser.jsp主要应用<form>标签和<table>标签。

页面有了,我们需要定义一个控制器UserServlet,用于获取页面提交的数据和流程控制。此时UserServlet主要是起到获取请求参数和跳转页面的功能。获取请求参数就是获取adduser.jsp中表单传递的值,跳转页面就是将获取到的数据存储到HttpServletRequest中然后调用
request.getRequestDispatcher(URL).forward(request,response)方法跳转到showUserinfo.jsp。
我们在定义一个显示页面,新建一个showUserinfo文件夹,在该文件夹中添加一个showUserinfo.jsp,主要代码如下:

<table>           <tr>              <td>userId</td>              <td>userName</td>              <td>password</td>              <td>gender</td>              <td>birthday</td>              <td>interests</td>           </tr>           <c:forEach items="${userList }" var="userInfo">           <tr>               <td>${userInfo.userId}</td>               <td>${userInfo.userName}</td>               <td>${userInfo.pwd}</td>               <td>${userInfo.gender==true ? "男" : "女"}</td>               <td>${userInfo.birthday}</td>               <td>${userInfo.interest}</td>               <td><a style="text-decoration: none" href="showUser.html?userid=${userInfo.userId}&delete=1">删除</a></td>               <td><a style="text-decoration: none" href="updateuser/updateuser.jsp?userId=${userInfo.userId}&userName=${userInfo.userName}&pwd=${userInfo.pwd}&gender=${userInfo.gender}&birthday=${userInfo.birthday}&interest=${userInfo.interest}" >修改</a></td>           </tr>             </c:forEach>          </table> 

还需要在页面中添加指令
<%taglib uri=”http://java.sun.com/jsp/jstl/core” prefix=”c” %>
Myeclipse2015web项目自带jstl标签库,老的版本可自行下载jstl jar包然后添加到web项目中
简单分析下该页面,用到类EL表达式,通过${}的形式获取到控制器传来的数据并显示在页面,另外也用到jstl标签库的
<c:forEach></forEach>标签用于循环输出多个数据。

在最后设计删除和修改的超链接,用QueryString传值,通过?符号带上类似键值对的形式传值,若是要传多个值,可用&符号连接
在此我通过userid来删除用户,另外定义了个标识delete=1,用于控制器识别以便执行删除操作。修改设计思路基本一致。
href=”showUser.html?userid=${userInfo.userId}&delete=1”

当执行删除操作时,它会将userid和删除标识传递UserServlet控制器上,由UserServlet执行删除操作,然后再跳转到showUserInfo.jsp界面,显示删除过后还剩下的用户信息。
当执行修改操作时,它会通过QueryString传递目前的用户的数据到修改页面update.jsp,然后根据情况修改相应数据,把修改过后的数据提交到控制器UserServlet来处理修改用户的操作,最后跳转到showUserInfo.jsp界面。

update.jsp具体代码如下:

<form action="showUser.html"  method="post">    <input type="hidden" name="update" value="1">    <table>           <tr>              <td>userId</td>              <td><input name="userid" readonly="readonly" value="${param.userId }"></td>           </tr>           <tr>              <td>userName</td>              <td><input name="username" readonly="readonly" value="${param.userName}"></td>           </tr>           <tr>              <td>password</td>              <td><input name="pwd" value="${param.pwd}"></td>           </tr>           <tr>              <td>gender</td>              <td><input value="${param.gender}"></td>           </tr>           <tr>              <td>                <input type="radio" name="gender" value="true"><input type="radio" name="gender" value="false"></td>           </tr>           <tr>              <td>birthday</td>              <td><input name="birthday" value="${param.birthday}"></td>           </tr>           <tr>             <td>兴趣:</td>             <td>篮球 <input type="checkbox" name="interest" value="篮球">&nbsp;&nbsp;                 足球 <input type="checkbox" name="interest" value="足球" >&nbsp;&nbsp;                 网球 <input type="checkbox" name="interest" value="网球">&nbsp;&nbsp;             </td>          </tr>             <tr>               <td colspan="2" align="center">                <input type="submit" value="update">                </td>           </tr>    </table>    </form>

可以看出update.jsp主要是用来显示需要修改的用户信息,默认值通过EL默认对象param对象获取showUserInof.jsp通过QueryString传递的用户数据,当我们修改用户信息,同样将信息提交到控制器UserServlet上,进行修改,不过在传递时表单中多了个
<input type="hidden" name="update" value="1">控件,用于传递修改标志。
下面是控制器UserServlet的主要代码:

package com.java.jdbc.service.servlet;

import java.io.IOException;
import java.sql.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.java.jdbc.dao.UserDao;
import com.java.test.entiy.UserInfo;

@WebServlet(“/showUser.html”)
public class UserServlet extends HttpServlet {

private static final long serialVersionUID = 8487830562296199121L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException {    req.setCharacterEncoding("UTF-8");    resp.setCharacterEncoding("UTF-8");    boolean flag = false;    String userId = req.getParameter("userid");    // 删除用户    String delete = req.getParameter("delete");    // UserDao对象专门处理用户数据对象    UserDao userDao = new UserDao();    if ("1".equals(delete)) {        if (userId != null && !"".equals(userId)) {            try {                // 删除用户                flag = userDao.deleteUser(Integer.parseInt(userId));                // 跳转                goForward(req, resp, flag, userDao);                return;            } catch (NumberFormatException e) {                e.printStackTrace();            } catch (Exception e) {                e.printStackTrace();            }        }    }    // 获取用户数据    String userName = req.getParameter("username");    String pwd = req.getParameter("pwd");    String gender = req.getParameter("gender");    String birthday = req.getParameter("birthday");    // 兴趣是多个,对于同名的"interest",通过getParameterValues获取,返回一个String数组    String[] interests = req.getParameterValues("interest");    // 将多个兴趣以"interest1:interest2:..."形式存储到数据库中    StringBuilder sBuilder = new StringBuilder();    for (int i = 0; i < interests.length; i++) {        if (i == interests.length - 1) {            sBuilder.append(interests[i]);        } else {            sBuilder.append(interests[i] + ":");        }    }    UserInfo userInfo = new UserInfo();    // 将获取的用户信息存到实体对象中    userInfo.setUserName(userName);    userInfo.setPwd(pwd);    userInfo.setGender(Boolean.valueOf(gender));    userInfo.setBirthday(Date.valueOf(birthday));    userInfo.setInterest(sBuilder.toString());    // 删除标志    String update = req.getParameter("update");    if ("1".equals(update)) {        userInfo.setUserId(Integer.parseInt(userId));        try {            flag = userDao.updateUser(userInfo);            goForward(req, resp, flag, userDao);            return;        } catch (Exception e) {            e.printStackTrace();        }    }    try {        flag = userDao.AddUser(userInfo);    } catch (Exception e) {        e.printStackTrace();    }    goForward(req, resp, flag, userDao);    return;}/** *  * 跳转到显示页面 * @param req * @param resp * @param flag * @param userDao * @throws ServletException * @throws IOException */private void goForward(HttpServletRequest req, HttpServletResponse resp,        boolean flag, UserDao userDao) throws ServletException, IOException {    List<UserInfo> userList = userDao.findAll();    if (flag) {        // request范围        req.setAttribute("userList", userList);        req.getRequestDispatcher("showUserInfo/showUserInfo.jsp").forward(                req, resp);    }}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException {    doGet(req, resp);}

}

不要忘了,还有有一个db.properties配置文件,与上一个例子一样将该文件放在src包下。

这里写图片描述

至此一个简单的JDBC结合JSP和Servlet技术的综合应用完成。
可以看出该例子只是做了一个最基本的主业务处理,就是实现用户的增删该查,因为Web Model2本身存在较多缺陷,所以本例子就不多做其他健壮性判断和设计上的优化了。

0 0
原创粉丝点击