您的位置:首页 > Web前端 > JavaScript

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

2016-10-10 19:23 627 查看
接下来我们来做结合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();

4000
}
}
}
}


接下来,需要一个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_USER
INCREMENT BY 1
START WITH 1
MAXVALUE 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, ?, ?, ?, ?, ?)” <
11603
br>
有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="篮球">  
足球 <input type="checkbox" name="interest" value="足球">  
网球 <input type="checkbox" name="interest" value="网球">  
</td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="add"> 
</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="篮球">  
足球 <input type="checkbox" name="interest" value="足球" >  
网球 <input type="checkbox" name="interest" value="网球">  
</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;

@Override
protected 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);

}

}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}


}

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



至此一个简单的JDBC结合JSP和Servlet技术的综合应用完成。

可以看出该例子只是做了一个最基本的主业务处理,就是实现用户的增删该查,因为Web Model2本身存在较多缺陷,所以本例子就不多做其他健壮性判断和设计上的优化了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: