介绍
- commons-dbutils 是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能,因此dbutils成为很多不喜欢hibernate的公司的首选。
- API介绍
- org.apache.commons.dbutils.QueryRunner–核心
- org.apache.comons.dbutils.ResultSetHandler
- 工具类
- org.apache.commons.dbutils.DbUtils
QueryRunner runner = new QueryRunner();
List<Account> as = runner.query(JdbcUtils.getConnection(),sql,new BeanListHandler<Account>(Account.class));
for(Account a : as){
System.out.println(a);
}
手动封装数据
new ResultSetHandler<List<Account>>(){
public List<Account> handler(ResultSet rs) throws SQLException{
List<Account> as = new ArrayList<Account>();
while(rs.next()){
Account a new Account();
a.setId(rs.getInt("id"));
a.setName(rs.getString("name"));
a.setMoney(rs.getDouble("money"));
as.add(a);
}
return as;
}
}
dbutils 核心
- QueryRunner 类
- 用于执行SQL语句的类
- query 用于执行select
- update 用于执行update 、select、insert
- batch 批处理
- ResultSetHandler接口
- 用于定义结果集的封装,实现类是BeanListHandler()见手动封装结果集)
- 它提供了九个实现类,可以进行不同的封装
- DbUtils 类
- 提供关于关闭资源及事务rollback,commit 操作。
QueryRunner类
获取方式
- new QueryRunner();
- 该构造方式创建的QueryRunner,它的事务是手动控制
- new QueryRunner(DataSource rs )
- 该构造方式创建的QueryRuuner,它的事务是自动控制的,即一条SQL语句,一个事务。
核心方法
- query
- update
- batch
- 对于上述三种方法,它们提供很多重载
- 如果QueryRunner在创建时,没有床底DataSource 参数,那么在使用query ,update,batch方法时,要传递connection 参数
- 如果在创建QueryRunner 时,传递了DataSource参数,那么在使用query,update,batch方法时,不需要传递connection参数。
public void fun1(){
String sql = "select * from account";
QueryRunner runner = new QueryRunner();//事务手动控制
Connection con = DataSourceUtils.getConnection();
List<Account> list = runner.query(con,sql,new BeanListHandler<Account>(Account.class));//需要传递con 参数
}
public void fun2(){
String sql = "select * from account";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());//自动事务
List<Account> list = runner.query(sql,new BeanListHandler<Account>(Account.class));//不需要传递con
}
总结
QueryRunner runner = new QueryRunner();
runner.query(Connection,sql,ResultSetHandler,Object...param);
runner.update(Connection,sql,Object...param);
runner.batch(Connection con,sql,Object[][] objs);
QueryRunner runner = new QueryRunner(DataSource ds);
runner.query(sql,ResultSetHandler,Object...param);
runner.update(sql,Object...param);
runner.batch(sql,Object[][] objs);
ResultSetHandler接口
public void fun1() throws SqLException{
String sql = "select * from account where id=?";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Account a = runner.query(sql,new ResultSetHandler<Account>(){//ResultSetHandler上的泛型就是我们执行query方法后得到的结果
//重写handle方法,在这个方法中确定,怎样将结果集封装
public Account handle(ResultSet rs) throws SQLException{
Account a = null;
if(rs.next()){
a=new Account();
a.setId(rs.getInt("id"));
a.setName(rs.getString("name"));
a.setMoney(rs.getDouble("money"));
}
return a;
}
},2);
System.out.println(a);
}
模仿QueryRunner方法
public class MyQueryRunner{
//执行select操作
public Object query(){
return null;
}
//执行update操作
public int update(Connection con,String sql,Object ...params){
PreparedStatement pst = con.prepareStatement(sql);//得到一个预处理的Statement
//问题:SQL语句中可能存在参数,需要对参数赋值
ParameterMetaData pmd= pst.getParameterMetaData();
//可以得到有几个参数
int count = pmd.getParameterCount();
for(int i=1;i<=count;i++){
pst.setObject(i,params[i-1]);
}
return pst.executeUpdate();
}
}
ResultSetHandler的九个实现类
ArrayHandler
将结果集中的第一条记录封装到Object[],数组中的每一个元素就是记录中的字段值。
public void fun1() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Object[] obj = runner.query("select * from account",new ArrayHandler());
System.out.pritnln(Arrays.toString(obj));
}
ArrayListHandler
将结果集中每一条记录封装到Object[],数组中的每一个元素就是记录中的字段值,再将这些数组装入到List集合。
public void fun2() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
List<Object[]> objs=runner.query("select * from account",new ArrayListHandler());
for(Object[] obj:objs){
System.out.println(obj);
}
}
BeanHandler(重点)
将结果集中的第一条记录封装到一个JavaBean中
public void fun3() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Account obj = runner.query("select * from account",new Beanhandler<Account>(Account.class));
System.out.printnln(obj);
}
BeanListHandler(重点)
将结果集中的每一条记录封装到JavaBean中,再将JavaBean封装到List集合中。
public void fun4() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
List<Account> obj = runner.query("select * from account",new BeanListHandler<Account>(Account.class));
System.out.println(obj);
}
ColumnListHandler
把结果集中的指定列的值封装到了List集合里。
public void fun5() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
List<Object> obj = runner.query("select * from account",new ColumnListHandler("name"));
System.out.println(obj);
}
MapHandler
将结果集中第一条记录封装到Map集合中,集合中的key就是字段名称,value就是字段值
public void fun6() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Map<String,Object> obj = runner.query("select * from account",new MapHandler());
System.out.println(obj);
}
MapListHandler
将结果集中每一条记录封装到Map集合中,集合中的key就是字段名称,value就是字段名值,再将这些Map封装到List集合中。
public void fun7() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
List<Map<String,Object>> obj = runner.query("select * from account",new MapListHandler());
System.out.println(obj);
}
KeyedHandler
将结果集中每一条记录封装到一个Map集合,再使用指定的列的值作为一个Map集合的key,值为每一条记录的Map集合封装。
public void fun8() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
Map<Object,Map<String,Object>> obj = runner.query("select * from account",new KeyedHandler("name"));
System.out.println(obj);
}
ScalarHandler
进行单值查询 select count(*) from account;
public void fun9() throws SQLException{
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
long obj = (long)runner.query("select count(*) from account",new ScalarHandler());
System.out.println(obj);
//System.out.println(obj.getCalss().getName())
}
模仿实现BeanHandler
//从结果集方向封装数据
public Object handle(ResultSet rs) throws SQLException{
Objet obj = null;
//得到结果集元数据
ResultSetMetaData md = rs.getMetaData();
//得到所有字段名称
int count = md.getColumnCount();
if(rs.nest()){
try{
BeanInfo bif = Introspector.getBeanInfo(clazz);//得到BeanInfo
PropertyDescriptor[] pds = bif.getPropertyDescriptors();//得到JavaBean的所有属性描述器
obj = clazz.newInstance();
for(int i=1;i<=count ;i++){
String name = md.getColumnName(i);//得到每一列的名称
for(PropertyDescriptor pd:pds){
if(name.equals(pd.getName())){
pd.getWriteMethod().invoke(obj,rs.getObject(name));//使用setXXX方法将结果集中的字段值封装到JavaBean的对应属性上。
}
}
}
}
}
}
案例演示(客户信息展示)
客户信息
字段名 | 说明 | 类型 |
---|---|---|
Id | 编号 | varchar(40) |
name | 客户姓名 | varchar(20) |
gender | 性别 | varchar(10) |
birthday | 生日 | date |
cellphone | 手机 | varchar(20) |
电子邮件 | varchar(40) | |
preference | 客户爱好 | varchar(100) |
type | 客户类型 | varchar(40) |
description | 备注 | varchar(255) |
创建表
create table customer(
id varchar(40) primary key,
name varchar(20),
gender varchar(10),
birthday date,
cellphone varchar(20),
email varchar(40),
preference varchar(100),
type varchar(40),
description varchar(255)
);
环境搭建
- JavaEE 三层结构
- Servlet +JSP + JavaBean +jstl+DBUtils+DAO+MySQL
- 导入jar包:JSTL,BeanUtils,DBUtils,C3P0,mysql驱动
- 创建包结构
- cn.xd.customer.web 表现层
- cn,xd.customer.service 业务层
- cn.xd.customer.dao 持久层
- cn.xd.customer.utils工具包
- cn.xd.customer.domain实体类 (JavaBean)
- 应用的jar包
- MySQL驱动包
- c3p0包
- dbutils包
- BeanUtil包
- JSTL包
- c3p0的配置文件
- 公共程序 domain utils
- Customer 类 实体类
- DataSourceUtils 工具类
编写代码
创建Customer的JavaBean
private String id;
private String name;
private String gender;
private Date birthday;
private String email;
private String preference;
private String type;
private String description;
为了测试方便,向customer表中插入数据
insert into customer values("a11","tom","男","2010-10-10","1372389034","tom@163.com","吃喝玩","vip","good man");
insert into customer values("a12","fox","男","2010-10-10","1372389034","fox@163.com","吃喝玩","vip","good man");
insert into customer values("a13","james","男","2010-10-10","1372389034","james@163.com","吃喝玩","vip","good man");
实现查询所有客户信息操作
- 在success.jsp页面添加连接
<a href="${pageContext.request.ContextPath}/findAll">查看客户信息</a>
- 在CustomerFindAllServlet中调用service,在service中调用dao,最后得到一个
List<Customer>
- 在showCustomer.jsp页面展示客户信息
<c:forEach items="${cs}" var="c">
<tr>
<td><input type="checkbox"></td>
<td>${c.id}</td>
<td>${c.name}</td>
<td>${c.gender}</td>
<td>${c.birthday}</td>
<td>${c.cellphone}</td>
<td>${c.email}</td>
<td>${c.preference}</td>
<td>${c.type}</td>
<td>${c.description}</td>
<td>
<a>编辑</a> <a>删除</a>
</td>
</tr>
</c:forEach>
删除操作
- 在showCustomer.jsp页面的删除连接上添加参数 客户的id
<a>编辑</a> <a href="${pageContext.request.contextPath}/delById?id=${c.id}">删除</a>
- 创建一个CustomerDelByIdServlet,完成获取请求参数,调用service中删除方法
- 问题:如果删除完成后,怎么处理?
- 跳转到 CustomerFindAllServlet中,再重新查询数据
编辑
- 查询,做回显示
<a href="${pageContext.req.contextPath}/findById?id=${c.id}">编辑</a>
- 创建CustomerFindByIdServlet,得到要查询的id,调用service,得到Customer对象
- 将customer对象存储到request域,请求转发到customerInfo.jsp页面。
- 在customerInfo,jsp中展示客户信息
- 注意:客户的id不能修改,所以使用
<input type="hedden">
- 修改
- 注意使用BeanUtils时的类型转换问题
- 注意编码问题
- post:request.setCharacterEncoding(“utf-8”);
- get:手动转换 new String(request.getParameter(name).getBytes(“iso8859-1”),”utf-8”)
- 进行修改操作
添加
- 在showCustomer.jsp页面上添加一个连接,可以直接访问到添加页面 add.jsp
- 创建add.jsp
- 关于生日的日历组件
- 导入js
- 在input type = text组件上添加 calss,onclick
- 关于id问题
- 使用UUID获取
- 创建CustomerAddServlet完添加操作
- 得到所有请求参数封装到Customer对象
- 编码问题
- 使用BeanUtils,注意Date类型转换问题,
- 手动封装id
- 调用service完成添加操作
<td>
<a href="${pageContext.request.contextPath}/add.jsp">添加</a>
</td>
//add.jsp
<head>
<script language="javascript" type="text/javascript" src="${pageContext.request.contextPath}/My97DatePicker/WdatePicker.js"></script>
</head>
<body>
${requestScope["add.message"]}<br>
<form action="${pageContext.request.contextPath}/add" method="post">
客户姓名:<input type="text" name="name"><br>
客户性别:<input type="radio" name="gender" value="男">男<input type="radio" name="gender" value="女">女
客户生日:<input type="text" name="birthday" class="Wdate" onclick="WdatePicker()"><br>
客户电话:<input type="text" name="cellphone" ><br>
客户邮箱:<input type="text" name="email" ><br>
客户爱好:<input type="text" name="preference" ><br>
客户类型:<input type="text" name="type" ><br>
客户备注:<input type="text" name="description" ><br>
<input type="submit" value="添加">
</form>
</body>
//CustomerAddServlet.java
req.setCharacterEncoding("utf-8");
DateConverter dc = new DateConverter();
dc.setPattern("yyyy-MM-dd");
try{
ConverUtils.register(dc,java.util.Date.class);
BeanUtils.populate(c,req.getParameterMap());
}catch(IllegalAccessException e){
e.printStackTrace();
}catch(InvocationTargetException e){
e.printStackTrace();
}
//手动将id封装到Customer对象中
c.setId(IDUtils.getUUID());
//调用service完成添加操作
CustomerService service = new CustomerService();
try{
service.add(c);
//添加成功
resp.sendRedirect(req.getContextPath()+"/fondAll");
}catch (SQLException e){
e.printStackTrace();
req.setAttribute("add.message","添加客户信息失败");
req.getRequestDispatcher("/add.jsp").forward(req,resp);
return;
}
//UUID示例
public class IDUtils{
public static String getUUID(){
return UUID.randomUUID().toString();
}
public static void main(String[] args){
System.out.println(getUUID());
}
}
//CustomerService.java
//添加客户信息
public void add(Customer c) throws SQLException{
dao.add(c);
}
//dao.java
public void add(Customer c) throws SQLException{
String sql="insert into customer values(?,?,?,?,?,?,?,?,?)";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
runner.update(sql,c.getId(),c.getName(),c.getGender(),c.getBirthday(),c.getCellphone(),c.getEmail(),c.getPreference(),c.getType(),c.getDescription());
}
批量删除
- 完成页面上全选与全不选操作
- 完成批量删除
- 页面上怎样将数据提交到服务器端
- 可以创建一个表单,,将表单数据提交
- 直接使用js操作,需要手动拼接出url路径
- 在服务器端怎样批量删除
- 得到所用要删除的id值
//showCustomer.jsp
<head>
<script>
function change(){
//得到id为main的checkbox
documnet.getElementById("main");
var flag = main.checked;
//得到所有name=ck 的checkbox
var cks = document.getElementsByName("ck");
//将cks中所有的checkbox的checked值设置为flag
for(var i=0;i<cks.length;i++){
cks[i].checked=flag;
}
}
</script>
</head>
<table>
<tr>
<td>
<input type="checkbox" id="main" onclick="change()">
</td>
</tr>
<c:forEach items="${cs}" var="c">
<tr>
<td>
<input type="checkbox" name="ck">
</td>
</tr>
</c:forEach>
</table>
//showCustomer.jsp
<script>
//作用:让表单提交
function sendDel(){
document.getElementById("f").submit;//表单提交
var cks = document.getElementsByName("ck");
/* var url="${pageContext.request.contextPath}/delSelect?"
for(var i=0;i<cks.length;i++){
if(cks[i].checked){
var id=cks[i].value;
url+="id="+id+"&";
}*/
}
};
</script>
<c:if test ="${not empty cs}">
<form action = "${pageContext.request.contextPath}/delSelect" method="post" id="f">
<table>
<c:forEach items="${cs}" var = "c">
<tr>
<td>
<input type="checkbox" value="${c.id}" name="ck">
</td>
</tr>
</c:forEach>
</table>
</form>
</c:if>
<tr>
<td colspan="10"><a href="javascript:void(0)" onclick="sendDel();">删除选中</a></td>
</tr>
//CustomerDelSelectServlet
//得到所有要删除的客户的id
String[] id = req.getParameterCalues("ck");
//调用service,完成批量删除
CustomerService service = new CustomerService();
service.delSelect(id);
//CustomerService.java
//批量删除
public void delSelect(String[] id){
dao.delSelect(id);
}
//customerDao.java
public void delSelect(Stinf[] id){
String sql="delete from customer where id=?";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
for(int i=0;i<id.length;i++){
ids[i][0]=id[i];
}
runner.batch(sql,ids);
}
条件查询
- 页面完成
- 创建CustomerSimpleSelectServlet完成条件查询
//showCustomer.jsp
<c:if test="${not empty cs}">
<div align ="center">
<form action="${pageContext.request.contextPath}/simpleSelect" method="post">
<select name="sel">
<option>请选择条件</option>
<option value="name">按姓名查询</option>
<option value="cellphone">按手机号查询</option>
<option value="gender">按性别查询</option>
</select>
<input type="text" name="msg">
<input type=“submit” value="查询">
</form>
</div>
</c:if>
- 问题:select的名称叫什么?每一个option的值是什么?
- select可以任意起名
- option的value名称需要与Customer表中的字段名称对应
- 创建CustomerSimpleSelectServlet完成条件查询
- 注意SQL语句问题:
- String sql = “select * from customer where “+sel+” like?”;
//CustomerSimpleSelectServlet.java
String sel = request.getParameter("sel");//字段名称
String msg = request.getParameter("msg");//字段值
//调用service完成查询操作
CustomerService service = new CustomerService();
try{
List<Customer> cs = service.simpleSelect(sel,msg);
}catch(SQLException e){
e.printStackTrace();
resp.getWriter().write("条件查询失败");
return;
}
//CustomerService
public List<Customer> simpleSelect(String sel,String msg){
return dao.simpleSelect(sel,msg);
}
//CustomerDao
//sel 字段名称
//msg 字段值
public List<Customer> simpleSelect(String sel,String msg){
//SQL语句中,?号会默认加单引号
//select * from customer where 'name' like '%'小'%'
//String sql = "select * from customer where ? like '%?%'"
String sql = "select * from customer where "+sel+" like ?"
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return runner.query(sql,new BeanListHandler<Customer>(Customer.class),"%"+msg+"%");
}