11第十二天DBUtils
一、前言:元数据介绍
准备工作:数据库day12(account)、mysql-connector-java-5.1.40-bin.jar和c3p0-0.9.1.2.jar,以及c3p0-config.xml:
<?xml version="1.0" encoding="utf-8"?><c3p0-config><default-config name="aaa"><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///day12</property><property name="user">root</property><property name="password">666666</property></default-config></c3p0-config>
select * from account;+----+------+-------+| id | name | money |+----+------+-------+| 1 | a | 1000 || 2 | b | 1000 || 3 | c | 1000 |+----+------+-------+
(一)、元数据
1、DataBaseMetaData
(1)、元数据:数据库、表、列的定义信息。
(2)、 Connection.getMetaData()
(3)、DataBaseMetaData对象
String getURL():返回一个String类对象,代表数据库的URL。String getUserName():返回连接当前数据库管理系统的用户名。String getDriverName():返回驱动驱动程序的名称。ResultSet getPrimaryKeys(String catalog, String schema, String table):返回指定表主键的结果集catalog- 类别名称;它必须与存储在数据库中的类别名称匹配;该参数为 "" 表示获取没有类别的那些描述;为 null 则表示该类别名称不应该用于缩小搜索范围。schema- 模式名称;它必须与存储在数据库中的模式名称匹配;该参数为 "" 表示获取没有模式的那些描述;为 null 则表示该模式名称不应该用于缩小搜索范围。table- 表名称;它必须与存储在数据库中的表名称匹配。
每个主键列描述都有以下列:TABLE_CAT String => 表类别(可为 null)TABLE_SCHEM String => 表模式(可为 null)TABLE_NAME String => 表名称COLUMN_NAME String => 列名称KEY_SEQ short => 主键中的序列号(值 1 表示主键中的第一列,值 2 表示主键中的第二列)。PK_NAME String => 主键的名称(可为 null)```* `getTables(String catalog, String schemaPattern,String tableNamePattern,String[] types)` - 获取可在给定类别中使用的表的描述。仅返回与类别、模式、表名称和类型标准匹配的表描述。它们根据 TABLE_TYPE、TABLE_CAT、TABLE_SCHEM 和 TABLE_NAME 进行排序。```sql每个表描述都有以下列:TABLE_CAT String => 表类别(可为 null)TABLE_SCHEM String => 表模式(可为 null)TABLE_NAME String => 表名称TABLE_TYPE String => 表类型。典型的类型是 "TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。REMARKS String => 表的解释性注释TYPE_CAT String => 类型的类别(可为 null)TYPE_SCHEM String => 类型模式(可为 null)TYPE_NAME String => 类型名称(可为 null)SELF_REFERENCING_COL_NAME String => 有类型表的指定 "identifier" 列的名称(可为 null)REF_GENERATION String => 指定在 SELF_REFERENCING_COL_NAME 中创建值的方式。这些值为 "SYSTEM"、"USER" 和 "DERIVED"。(可能为 null)注: 有些数据库可能不返回用于所有表的信息。
- 方法练习:
package com.lmd.metadata;import java.sql.Connection/DatabaseMetaData;import java.sql.PreparedStatement;import java.sql.ResultSet/SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class DataBaseMetaDataDemo {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();try {conn = source.getConnection();//--获取当前数据库的元数据DatabaseMetaData metaData = conn.getMetaData();//--获取数据库连接时使用的URL 框架设计者使用String url = metaData.getURL();System.out.println(url);//输出:jdbc:mysql:///day12//--获取数据库的用户名 框架设计者使用String name = metaData.getUserName();System.out.println(name);//输出:root@localhost//--返回驱动驱动程序的名称。 框架设计者使用String driver = metaData.getDriverName();System.out.println(driver);//输出:MySQL Connector Java//--返回指定表主键的结果集 框架设计者使用rs = metaData.getPrimaryKeys(null, null, "account");while (rs.next()) {//获取主键的序列号和名称short cseq = rs.getShort("KEY_SEQ");String cname = rs.getString("PK_NAME");System.out.println(cseq+":"+cname);//1:PRIMARY}//-获取表, "acc%":以acc开头的表;"%":所有 表rs = metaData.getTables(null, null, "%", new String[]{"TABLE"});while (rs.next()) {//获取表名称String tname = rs.getString("TABLE_NAME");System.out.println(tname);//输出:account}} catch (Exception e) {e.printStackTrace();} finally {//rs、ps和conn释放}}}
2、ParameterMetaData
(1)、PreparedStatement . getParameterMetaData()
- 获得代表PreparedStatement元数据的ParameterMetaData对象。
- select * from user where name=? And password=?
(2)、ParameterMetaData对象
getParameterCount()获得指定参数的个数getParameterTypeName(int param)获得指定参数的sql类型
(3)、getParameterType异常处理
- Parameter metadata not available for the given statement
(4)、url后面拼接参数
- ?generateSimpleParameterMetadata=true
- 方法练习:
package com.lmd.metadata;import java.sql.Connection;import java.sql.DatabaseMetaData/ParameterMetaData;import java.sql.PreparedStatement/ResultSet;import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class PMMetaDataDemo {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();try {conn = source.getConnection();ps = conn.prepareStatement("select * from account where name=? and money=?");//---获取参数元数据ParameterMetaData metaData = ps.getParameterMetaData();//--获取参数个数int count = metaData.getParameterCount();System.out.println(count);//2//--获取数据的类型// 要修改c3p0-config.xml:<property name="jdbcUrl">jdbc:mysql:///day12// ?generateSimpleParameterMetadata=true</property>String type = metaData.getParameterTypeName(1);//mysql支持不好System.out.println(type);//VARCHARString type2 = metaData.getParameterTypeName(2);System.out.println(type2);//VARCHAR} catch (Exception e) {e.printStackTrace();} finally {//rs、ps和conn释放}}}
3、ResultSetMetaData
(1)、ResultSet. getMetaData()
- 获得代表ResultSet对象元数据的ResultSetMetaData对象。
(2)、ResultSetMetaData对象
getColumnCount()返回resultset对象的列数getColumnName(int column)获得指定列的名称getColumnTypeName(int column)获得指定列的类型- 方法练习:
package com.lmd.metadata;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class PMMetaDataDemo {public static void main(String[] args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();try {conn = source.getConnection();ps = conn.prepareStatement("select * from account");rs = ps.executeQuery();//框架设计者使用//--获取结果集元数据ResultSetMetaData metaData = rs.getMetaData();//--获取结果集中列的个数int ccount = metaData.getColumnCount();System.out.println(ccount);//3//--获取结果集中指定列的名称String cname = metaData.getColumnName(2);System.out.println(cname);//name//--获取结果集中指定列的类型的名称String tname = metaData.getColumnTypeName(3);System.out.println(tname);//DOUBLE} catch (Exception e) {e.printStackTrace();} finally {//rs、ps和conn释放}}}
- 总练习:
Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();try {conn = source.getConnection();ps = conn.prepareStatement("select * from account");rs = ps.executeQuery();//框架设计者使用//--获取结果集元数据ResultSetMetaData metaData = rs.getMetaData();//--获取结果集中列的个数int ccount = metaData.getColumnCount();//System.out.println(ccount);//3//--获取结果集中指定列的名称//String cname = metaData.getColumnName(2);//System.out.println(cname);//name//--获取结果集中指定列的类型的名称//String tname = metaData.getColumnTypeName(3);//System.out.println(tname);//DOUBLESystem.out.println("----------------------------------------------------");for (int i = 1; i <= ccount; i++) {String cname = metaData.getColumnName(i);String ctype = metaData.getColumnTypeName(i);System.out.print(cname+":"+ctype+"\t\t");}System.out.println();System.out.println("----------------------------------------------------");while (rs.next()) {for (int i = 1; i <= ccount; i++) {Object obj = rs.getObject(i);System.out.print(obj+"\t\t ");}System.out.println();}System.out.println("----------------------------------------------------");} catch (Exception e) {e.printStackTrace();} finally {//rs、ps和conn释放}<img src="029ca96e-e579-4d7d-b5d7-4eb88b1d88e1_files/084b64e4-5ad6-4e3f-ab13-8ab1ddeb1403.png" border="0" class="" style="font-size: 1rem;">
二、Apache—DBUtils框架
(一)、简介 commons-dbutils-1.4.jar 其方法都是静态的
1、commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习
成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很
多不喜欢hibernate的公司的首选。
2、API介绍:
- org.apache.commons.dbutils.QueryRunner — 核心
- org.apache.commons.dbutils.ResultSetHandler
- 工具类
- org.apache.commons.dbutils.DbUtils、。
(二)、DbUtils类
1、提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
- public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。
- public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLException。
- public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。
- public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
(三)、QueryRunner类 – 两行代码搞定增删改查
1、该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够
大大减少编码量。
2、QueryRunner类提供了两个构造方法:
- 默认的构造方法。
- 需要一个 javax.sql.DataSource 来作参数的构造方法。
3、QueryRunner() –需要控制事务时,使用这组方法
其中方法:Connection .setAutoCommit .commit .rollback
Connection conn = source.getConnection();
con.setAutoCommit(false);下面执行多条SQL语句,是基于一个连接,即一个事务
(1)、更新操作
- public int update(Connection conn, String sql)
- 执行 INSERT,UPDATE或DELETE SQL语句,不使用替换参数。
- public int update(Connection conn, String sql, Object… params)
- 执行 INSERT,UPDATE或DELETE SQL语句。
- public int update(Connection conn, String sql, Object param)
- 使用单个替换参数执行给定的INSERT,UPDATE或DELETE SQL语句。
(2)、查询操作
- public
T query(Connection conn, String sql, ResultSetHandler rsh, Object… params) - 执行 SELECT SQL语句,不使用替换参数。
- public
T query(Connection conn, String sql, ResultSetHandler rsh, Object… params) - 执行具有替换参数的SELECT SQL 语句。
- 执行具有替换参数的SELECT SQL 语句。
2、QueryRunner(DataSource ds) –不需要控制事务用这组方法
(1)、更新操作
- public int update(String sql)
- 执行给定的INSERT,UPDATE或DELETE SQL语句,不带任何替换参数。
- public int update(String sql, Object… params)
- 执行给定的INSERT,UPDATE或DELETE SQL语句。
- public int update(String sql, Object param)
- 使用单个替换参数执行给定的INSERT,UPDATE或DELETE SQL语句。
(2)、查询操作
- public
T query(String sql, ResultSetHandler rsh) - 执行给定的SELECT SQL语句,不带任何替换参数。
- public
T query(String sql, ResultSetHandler rsh, Object… params) - 执行给定的SELECT SQL查询语句并返回结果对象。
(四)、ResultSetHandler 实现类
该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。
ResultSetHandler 接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)。
1、ResultSetHandler 接口的实现类
- ArrayHandler:把结果集中的第一行数据转成对象数组。
- ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。
- !!!!
BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。 - !!!!
BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。 - MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
- MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List
- ColumnListHandler:将结果集中某一列的数据存放到List中。
- KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List
- !!!!!
ScalarHandler:获取结果集中第一行数据指定列的值,常用来进行单值查询
2、练习:
package com.lmd.metadata;import java.sql.SQLException;import java.util.List;import java.util.Map;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.ArrayHandler;import org.apache.commons.dbutils.handlers.ArrayListHandler;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.apache.commons.dbutils.handlers.ColumnListHandler;import org.apache.commons.dbutils.handlers.KeyedHandler;import org.apache.commons.dbutils.handlers.MapHandler;import org.apache.commons.dbutils.handlers.MapListHandler;import org.apache.commons.dbutils.handlers.ScalarHandler;import org.junit.Test;import com.lmd.domain.Account;import com.mchange.v2.c3p0.ComboPooledDataSource;public class RSHandlerDemo {//ArrayHandler:把结果集中的第一行数据转成对象数组public void testArrayHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());Object[] obj = runner.query("select * from account where money>?", new ArrayHandler(), 800);for (int i = 0; i < obj.length; i++) {System.out.print(i == obj.length-1 ? obj[i] : obj[i]+"--");}}//输出:1--a--999.0//ArrayListHandler:把结果集中的每一行数据都转成一个对象数组,再存放到List中。public void testArrayListHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());List<Object[]> list = runner.query("select * from account where money>?", new ArrayListHandler(), 800);for (int i = 0; i < list.size(); i++) {Object[] obj = list.get(i);for (int j = 0; j < obj.length; j++) {System.out.print(j == obj.length-1 ? obj[j] : obj[j]+"--");}System.out.println();}}//输出:1--a--999.0 换行 2--b--888.0//BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。public void testBeanHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());Account acc = runner.query("select * from account where money>?", new BeanHandler<Account>(Account.class), 800);System.out.println(acc.getId()+"--"+acc.getName()+"--"+acc.getMoney());}//输出:1--a--999.0//BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。public void testBeanListHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());List<Account> list = runner.query("select * from account where money>?", new BeanListHandler<Account>(Account.class), 800);for (int i = 0; i < list.size(); i++) {Account acc = list.get(i);System.out.println(acc.getId()+"--"+acc.getName()+"--"+acc.getMoney());}}//输出:1--a--999.0 换行 2--b--888.0//MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。public void testMapHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());Map<String, Object> map = runner.query("select * from account where money>?", new MapHandler(), 800);System.out.println(map );}//输出:{money=999.0, name=a, id=1}//MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到Listpublic void testMapListHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());List<Map<String, Object>> list = runner.query("select * from account where money>?", new MapListHandler(), 800);for (Map<String, Object> map : list) {System.out.println(map);}}//输出:{money=999.0, name=a, id=1}换行{money=888.0, name=b, id=2//ColumnListHandler:将结果集中某一列的数据存放到List中。public void testColumnListHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());List<Object> list = runner.query("select * from account where money>?", new ColumnListHandler(2), 800);for (Object obj : list) {System.out.print(obj +" ");}}//输出:a b//KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里(List<Map>),//再把这些map再存到一个map里,其key为指定的列。public void testKeyedHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());Map<Object, Map<String, Object>> map = runner.query("select * from account where money>?", new KeyedHandler("id"), 800);System.out.println(map);//输出:{1={money=999.0, name=a, id=1}, 2={money=888.0, name=b, id=2}}System.out.println(map.get(2).get("name"));}//输出: b//ScalarHandler:获取结果集中第一行数据指定列的值,常用来进行单值查询//默认第一行第一列@Testpublic void testScalarHandler() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());Long count = (Long) runner.query("select count(*) from account", new ScalarHandler());System.out.println(count);}//输出: 3}
(五)、QueryRunner类更新和查询操作练习:
1、更新操作
//自己设计DbUtils框架package com.lmd.dbutils;import java.sql.Connection/ParameterMetaData;import java.sql.PreparedStatement/SQLException;import javax.sql.DataSource;import org.apache.commons.dbutils.DbUtils;public class MyQueryRunner {private DataSource source = null;public MyQueryRunner(){ }public MyQueryRunner(DataSource source){this.source = source;}public int update(String sql, Object... params)throws SQLException {Connection conn = source.getConnection();PreparedStatement ps = conn.prepareStatement(sql);//--获取参数元数据ParameterMetaData metaData = ps.getParameterMetaData();int count = metaData.getParameterCount();//--循环设置参数值for (int i = 1; i <= count; i++) {ps.setObject(i, params[i-1]);}//--执行update操作int num = ps.executeUpdate();DbUtils.closeQuietly(conn, ps, null);return num;}}
- 实现更新操作:
package com.lmd.dbutils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import org.apache.commons.dbutils.DbUtils;import org.apache.commons.dbutils.QueryRunner;import org.junit.Test;import com.mchange.v2.c3p0.ComboPooledDataSource;public class DbUtilsUpdate {public void delete() throws SQLException {MyQueryRunner runner = new MyQueryRunner(new ComboPooledDataSource());runner.update("delete from account where id=?", 7);}public void add() throws SQLException {MyQueryRunner runner = new MyQueryRunner(new ComboPooledDataSource());runner.update("insert into account values(null,?,?)", "d", 1000);}/*** MyDbUtils实现增删改功能* @throws SQLException*//@Testpublic void update1() throws SQLException {MyQueryRunner runner = new MyQueryRunner(new ComboPooledDataSource());runner.update("update account set money=? where name=?", 777, "c");}/*** DbUtils实现增删改功能* @throws SQLException*/public void update2() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());runner.update("update account set money=? where name=?", 888, "b");}/*** 古老方法实现增删改功能* --在进行增删改操作时,每次不一样的时sql语句和其中的参数*/public void update3() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();try {conn = source.getConnection();ps = conn.prepareStatement("update account set money=? where name=?");ps.setDouble(1, 999);ps.setString(2, "a");ps.executeUpdate();} catch (Exception e) {e.printStackTrace();} finally {DbUtils.closeQuietly(conn, ps, rs);}}}
2、查询操作
- 新增一个接口:
MyResultSetHandler
package com.lmd.dbutils;import java.sql.ResultSet;import java.sql.SQLException;public interface MyResultSetHandler<T> {T handle(ResultSet rs) throws SQLException;}
- 在自己设计DbUtils框架MyQueryRunner.java中新增:
//利用接口实现传进去public <T> T query(String sql, MyResultSetHandler<T> rsh, Object... params) throws SQLException{Connection conn = source.getConnection();PreparedStatement ps = conn.prepareStatement(sql);//--获取参数元数据ParameterMetaData metaData = ps.getParameterMetaData();int count = metaData.getParameterCount();//--循环设置参数值for (int i = 1; i <= count; i++) {ps.setObject(i, params[i-1]);}//--执行query操作获取结果集ResultSet rs = ps.executeQuery();//--`回调`处理结果集的逻辑T t = rsh.handle(rs);DbUtils.closeQuietly(conn, ps, rs);return t;}
- 查询操作:
package com.lmd.dbutils;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import org.apache.commons.dbutils.DbUtils;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.ResultSetHandler;import org.junit.Test;import com.lmd.domain.Account;import com.mchange.v2.c3p0.ComboPooledDataSource;import com.mysql.fabric.xmlrpc.base.Array;public class DbUtilsQuery {/*** MyDbUtils实现查询功能* @throws SQLException** 回调函数:当方法a调用方法b时,而方法b在执行的过程中,* 其中一些逻辑需要由方法a告知,此时需要方法a在调用* 方法b时将逻辑传入,而java中是不允许传递java源代码的,* 此时可以使用回调机制。所谓回调,就是方法a和方法b约定* 一个接口,在这个接口中定义一个方法,这个方法通常叫handler方法,* a调用b时,传入此接口实现,其中利用handler方法,将逻辑传入,* 方法b在执行过程中需要执行a传入的逻辑时,调用接口实现的handler方法* 即可,此时a调用b时,b回来调用的a传入的逻辑,所以此过程叫回调*/@Testpublic void select1() throws SQLException {MyQueryRunner runner = new MyQueryRunner(new ComboPooledDataSource());List<Account> list = runner.query("select * from account where money>?", new MyResultSetHandler<List<Account>>(){@Overridepublic List<Account> handle(ResultSet rs) throws SQLException {List<Account> list = new ArrayList<Account>();while (rs.next()) {Account account = new Account();account.setId(rs.getInt("id"));account.setName(rs.getString("name"));account.setMoney(rs.getDouble("money"));list.add(account);}return list;}}, 800);for (int i = 0; i < list.size(); i++) {Account acc = list.get(i);System.out.println(acc.getId()+"--"+acc.getName()+"--"+acc.getMoney());}}/*** DbUtils实现查询功能* @throws SQLException*/public void select2() throws SQLException {QueryRunner runner = new QueryRunner(new ComboPooledDataSource());List<Account> list = runner.query("select * from account where money>?", new ResultSetHandler<List<Account>>(){@Overridepublic List<Account> handle(ResultSet rs) throws SQLException {List<Account> list = new ArrayList<Account>();while (rs.next()) {Account account = new Account();account.setId(rs.getInt("id"));account.setName(rs.getString("name"));account.setMoney(rs.getDouble("money"));list.add(account);}return list;}}, 800);for (int i = 0; i < list.size(); i++) {Account acc = list.get(i);System.out.println(acc.getId()+"--"+acc.getName()+"--"+acc.getMoney());}}/*** 古老方法实现查询功能* --在进行查询操作时,每次不一样的是sql语句、sql中的参数、结果集的处理*/public void select3() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;ComboPooledDataSource source = new ComboPooledDataSource();List<Account> list = new ArrayList<Account>();try {conn = source.getConnection();ps = conn.prepareStatement("select * from account where money>?");ps.setDouble(1, 800);rs = ps.executeQuery();while (rs.next()) {Account account = new Account();account.setId(rs.getInt("id"));account.setName(rs.getString("name"));account.setMoney(rs.getDouble("money"));list.add(account);}for (int i = 0; i < list.size(); i++) {Account acc = list.get(i);System.out.println(acc.getId()+"--"+acc.getName()+"--"+acc.getMoney());}//1--a--999.0//2--b--888.0} catch (Exception e) {e.printStackTrace();} finally {DbUtils.closeQuietly(conn, ps, rs);}}}
(六)、其他知识点:
1、回调函数
- 所谓回调,就是客户程序C调用服务程序S中的某个函数A,然后S又在某个时候反过来调用C中的某个函数B,对于C来说,这个B便叫做回调函数。例如Win32下的窗口过程函数就是一个典型的回调函数。一般说来,C不会自己调用B,C提供B的目的就是让S来调用它,而且是C不得不提供。由于S并不知道C提供的B姓甚名谁,所以S会约定B的接口规范(函数原型),然后由C提前通过S的一个函数R告诉S自己将要使用B函数,这个过程称为回调函数的注册,R称为注册函数。Web Service以及Java的RMI都用到回调机制,可以访问远程服务器程序。
下面举个通俗的例子:
某天,我打电话向你请教问题,当然是个难题,^_^,你一时想不出解决方法,我又不能拿着电话在那里傻等,于是我们约定:等你想出办法后打手机通知我,这样,我就挂掉电话办其它事情去了。过了XX分钟,我的手机响了,你兴高采烈的说问题已经搞定,应该如此这般处理。故事到此结束。这个例子说明了“异步+回调”的编程模式。其中,你后来打手机告诉我结果便是一个“回调”过程;我的手机号码必须在以前告诉你,这便是注册回调函数;我的手机号码应该有效并且手机能够接收到你的呼叫,这是回调函数必须符合接口规范。通过上面个人感觉到回调更多的应用就是结合异步。比如:Ajax中js通过组件和服务器的异步通信。
2、例子:
- 程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。目的达到。在C/C++中,要用回调函数,被掉函数需要告诉调用者自己的指针地址,但在JAVA中没有指针,怎么办?我们可以通过接口(interface)和类来实现回调函数的功能。
- 假设我是程序员A,以下是我的程序a:
public class Caller {public MyCallInterface mc;public void setCallfuc(MyCallInterface mc) {this.mc= mc;}public void call(){this.mc.method();}}
* 我还需要定义一个接口,以便程序员B根据我的定义编写程序实现接口。
public interface MyCallInterface {public void method();}
* 于是,程序员B只需要实现这个接口就能达到回调的目的了:
public class B implements MyCallInterface {public void method() {System.out.println("回调");}public static void main(String args[]) {Caller call = new Caller();call.setCallfuc(new B());call.call();}}
3、例子:

package com.lmd.test;//接口中定义比较大小的方法interface IntCompare{public int compare(int a, int b) ;}class AscendOrder implements IntCompare{@Overridepublic int compare(int a, int b) {return a>b ? 1 : (a<b ? -1 : 0);}}class DescendOrder implements IntCompare{@Overridepublic int compare(int a, int b) {return a>b ? -1 : (a<b ? 1 : 0);}}public class CallbackFunction {public static void insertSort(int[] arr, IntCompare cmp) {if (arr != null) {for (int i = 1; i < arr.length; i++) {int temp = arr[i], j=i;if (cmp.compare(arr[j-1], temp) == 1) {while (j >= 1 && cmp.compare(arr[j-1], temp)==1) {arr[j] = arr[j-1];j--;}}arr[j] = temp;}}}public static String printSort(int[] arr) {String s = "";for (int i = 0; i < arr.length; i++) {s += arr[i] + " ";}return s;}public static void main(String[] args) {int[] arr1 = {12, 3, -2, 33, 24};insertSort(arr1, new AscendOrder());System.out.println("升序:" + printSort(arr1));int[] arr2 = {12, 3, -2, 33, 24};insertSort(arr2, new DescendOrder());System.out.println("降序:" + printSort(arr2));}}
分页技术
- 物理分页
- 在sql查询时,从数据库只检索分页需要的数据
- 通常不同的数据库有着不同的物理分页语句
- mysql物理分页,采用limit关键字
- 例如:检索11-20条 select * from user limit 10,10 ;
- 在sql查询时,先从数据库检索出所有数据的结果集
- 在程序内,通过逻辑语句获得分页需要的的数据
- 例如: 检索11-20条 userList.subList(10,20);
(七)、分页技术概述
1、物理分页 – 常用,其优缺点与逻辑分页反之
- 在sql查询时,从数据库只检索分页需要的数据
- 通常不同的数据库有着不同的物理分页语句
- mysql物理分页,采用limit关键字
- 例如:检索11-20条 select * from user limit 10,10 ;
2、逻辑分页 – 数据少且很少变化的数据库,已不常用。例如:国家、省、县
- 在sql查询时,先从数据库检索出所有数据的结果集
- 在程序内,通过逻辑语句获得分页需要的的数据
- 例如: 检索11-20条 userList.subList(10,20);
- 优点:存在list中,仅查询一次数据库
- 缺点:数据过大时,存在内存中耗内存;数据库发生变化,内存中反映不出来
三、案例——客户管理系统:体验基于数据库javaweb的增删改查
(一)客户管理系统
- 1、实现功能:添加客户、查询客户列表、修改客户信息、删除客户、条件查询客户信息、分页查询客户
- 2、javaee的经典三层架构–工厂类实现解耦
- 3、使用技术:jsp+servlet+service+dao+jdbc+mysql+c3p0+dbutils
- 4、使用包:
- com.lmd.web
- com.lmd .service
- com.lmd.dao
- com.lmd.domain
- com.lmd.util
- com.lmd.exception
- com.lmd.factory
- 5、使用第三方包: JSTL、* mysql驱动、beanutils、c3p0包、dbutils包
- 6、配置文件:
- confing.properties src下
- c3p0-config.xml src下
- 7、设计数据库:
create table customer (id int primary key auto_increment,name varchar(20),gender varchar(10),birthday date,cellphone varchar(20),email varchar(40),preference varchar(100),type varchar(40),description varchar(255));
| 字段名 | 说明 | 类型 |
|---|---|---|
| id | 编号 | int |
| name | 客户姓名 | varchar(20) |
| gender | 性别 | varchar(10) |
| birthday | 生日 | date |
| cellphone | 手机 | varchar(20) |
| 电子邮件 | varchar(40) | |
| preference | 客户爱好 | varchar(100) |
| type | 客户类型 | varchar(40) |
| description | 备注 | varchar(255) |
- 8、工厂类实现解耦:
- 要有接口(CustDao、CustService)、要有配置文件(confing.properties )、要有工厂类。
- CustDaoImp和CustServiceImp两个实现类 设置了一个通用的工厂类。
CustDaoImp=com.lmd.dao.CustDaoImp //service层和Dao层的解耦CustService=com.lmd.service.CustServiceImp //web层(servlet)和service层的解耦
按照需求从前向后开发
新建一个JavaBean类-Cust.java,设计一个工厂类BasicFactory.java
9、添加客户功能实现:
- –>addCust.jsp–>AddCustServlet.java(内含需要service层处理的方法void addCust(Cust cust);)
- –>CustService.java(接口,业务逻辑层,内含需要Dao层具体处理的方法:Cust findUserByName(String name);和void addCust(Cust cust);)
- –>CustServiceImp.java(接口实现类)
- –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类,其中设计一个工具类DaoUtils.java,获取数据源和连接池)
index.jsp 主页 提供<添加客户>超链接
- –>addCust.jsp 添加客户的页面,提供表单允许输入客户信息
- –>AddCustServlet 1.封装数据/校验数据 2.调用Service层添加客户的方法 3.重定向回到主页 –>Service 提供添加客户的方法,检查客户名是否已经存在,如果存在提示,如果不存在则调用dao增加客户方法
- –> Dao 根据用户名查找用户 添加客户
- 10、查询客户列表功能实现:
- –>AddCustServlet.java(内含需要service层处理的方法List
getAllCust();) - –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法:List
getAllCust();) - –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
- –> listCust.jsp
- –>AddCustServlet.java(内含需要service层处理的方法List
index.jsp 页面中 提供<查询客户列表>超链接
- –>ListCustServlet 调用Service中查询所有客户的方法 查到数据后,将查到的数据存入request域中,请求转发listCust.jsp页面展示
- –>Service 调用dao中查询所有客户
- –>dao中查询所有客户
- –>listCust.jsp 页面,遍历list展示所有客户
11、修改客户信息 (查询/修改)功能实现:
- –>listCust.jsp(增加<修改>超链接,访问CustInfoServlet.java)
- –>UpdateCustServlet.java(内含需要service层处理的方法void updateCust(Cust cust);)
- –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法void updateCust(Cust cust);)
- –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
- –> updateCust.jsp
在客户信息列表页面,每一条记录后面都有一个<修改>超链接
- –>CustInfoServlet 调用Service中的方法 找到当前客户信息 存入request域后带到updateCust.jsp页面显示
- –>updateCust.jsp 显示客户信息,并允许修改
- –>UpdateCustServlet 封装数据/调用Service中修改数据的方法
- –>Service 修改客户信息的方法,调用dao中的方法进行修改
- –>Dao 提供修改客户信息的方法
12、删除客户功能实现:
- –>listCust.jsp(增加<删除>超链接,访问DelCustServlet.java)
- –>DelCustServlet.java(内含需要service层处理的方法void delCustById(String id);)
- –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法void delCustById(String id);)
- –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
在客户信息列表页面,每一条记录后面都有一个<删除>超链接
- –>DelCustServlet 获取要删除的客户id,调用Service中删除客户的方法,请求转发到客户列表页面
- –>Service 删除客户的方法 调用dao中对应方法
- –>Dao中根据id删除客户的方法
13、批量删除客户功能实现:
- –>listCust.jsp(增加“checkbox”复选框,访问BatchDelCustServlet.java)
- –>BatchDelCustServlet.java(内含需要service层处理的方法void batchDel(String[] ids);)
- –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法void delCustByIdWithTrans(Connection conn, String id) throws SQLException;)
- –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
listCust.jsp 在客户信息列表页面的每一条记录之前都有一个复选框,选中后,可以删除
- –>BatchDelCustServlet 获取所有要删除的客户的id,调用Service中批量删除客户的方法做删除操作
- –>Service中提供批量删除客户的方法,事务的管理
- –>dao中删除客户的方法
14、条件查询客户信息功能实现:
- –>listCust.jsp(设置条件查询表单,访问FindCustByCondServlet.java)
- –>FindCustByCondServlet.java(内含需要service层处理的方法List
findCustByCond(Cust cust);) - –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法List
findCustByCond(Cust cust);) - –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
listCust.jsp 在客户信息列表页面之前,提供一个条件查询的表单,允许通过用户名、性别、客户类型进项条件查询
- –>FindCustByCondServlet 将条件封装在bean中调用service中条件查询客户的方法,将查询到的所有客户信息存在request域带到listCust.jsp界面显示
- –>Service中提供根据条件查询客户的方法
- –>dao中条件查询客户的方法
15、分页查询客户信息功能实现:
- –>index.jsp(增加<分页查询客户信息>超链接,访问PageCustServlet.java)添加一个bean类Page.java
- –>PageCustServlet.java(内含需要service层处理的方法Page pageCust(int thispage, int rowperpaper);)
- –>CustService.java(接口,业务逻辑层)
- –>CustServiceImp.java(接口实现类,内含需要Dao层具体处理的方法int getCountRow();和List
getCustByPage(int from, int count);) - –>CustDao.java(接口,数据访问层)–>CustDaoImp.java(接口实现类)
- index.jsp上 listCust.jsp上程序过多,重新设计一个页面界面上设计:共xxx条记录 共xx页 首页 上一页 1 2 3 4 5 下一页 尾页
- –>listCust.jsp(增加<分页查询客户信息>超链接,访问PageCustServlet.java)
- –>PageCustServlet.java(获取要访问的页码以及每页显示多少条记录,调用serviece中分页查询客户的方法查询客户,存入request域带到pageList.jsp页面进行展示)
- –>Service中提供根据分页查询客户的方法(Page pageCust(int thispage, int rowperpaper);)
- –>dao中分页查询客户的方法(int getCountRow();和List
getCustByPage(int from, int count);) - if(总页码<=5){
- 显示所有页码;
- } else{
- if(当前页码<=3){
- 显示1到5;
- } else if(当前页码>=总页码-2){
- 显示总页码-4到总页码;
- } else {
- 显示当前页码-2到当前页码+2;
- }
- }
- 16、代码程序:
- c3p0-config.xml
<?xml version="1.0" encoding="utf-8"?><c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql:///day12?serverTimezone=UTC</property>(时区异常问题)<property name="user">root</property><property name="password">666666</property></default-config></c3p0-config>
* `index.jsp`开始界面
<%@ page language="java" contentType="text/html; charset=UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>客户管理系统</title></head><body><h1>客户管理系统_主页</h1><a href="${pageContext.request.contextPath}/addCust.jsp">添加客户</a><a href="${pageContext.request.contextPath}/ListCustServlet">查询客户列表</a><a href="${pageContext.request.contextPath}/ListCustServlet">修改客户信息</a><a href="${pageContext.request.contextPath}/ListCustServlet">删除客户</a><a href="${pageContext.request.contextPath}/PageCustServlet?thispage=1">分页查询客户</a></body></html>

* `web.xml` 配置错误提示界面
<error-page><error-code>500</error-code><location>/error/500.jsp</location></error-page><error-page><error-code>404</error-code><location>/error/404.jsp</location></error-page>
* `500/404.xml` 错误提示界面
<body>服务器出错了~~~~~~出错原因:${pageContext.exception.message }</body><body>资源被搬走了~~~~~~出错原因:${pageContext.exception.message }</body>
* `Cust.java` Dao类,这一般是指java中MVC架构中的model的概念,主要是访问数据库的一些方法。domain包下
package com.lmd.domain;import java.io.Serializable;import java.sql.Date;public class Cust implements Serializable {private int id;private String name;private String gender;private Date birthday;private String cellphone;private String email;private String preference;private String type;private String description;//getter和setter}
* `Page.java` Dao类分页查询使用 domain包下
package com.lmd.domain;import java.util.List;public class Page {private int thispage;private int rowperpage;private int countrow;private int countpage;private int firstpage;private int lastpage;private int prevpage;private int nextpage;private List<Cust> custList;//getter和setter}
BasicFactory.java工厂类解耦,需要接口和实现类、配置文件(confing.properties )
package com.lmd.factory;import java.io.FileReader;import java.util.Properties;import com.lmd.dao.CustDao;public class BasicFactory {private static BasicFactory factory = new BasicFactory();private static Properties prop = null;private BasicFactory(){}public static BasicFactory getFactory() {return factory;}static{try {prop = new Properties();prop.load(new FileReader(BasicFactory.class.getClassLoader().getResource("config.properties").getPath()));} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}public <T> T getInstance(Class<T> clazz) {//CustDao.class:com.lmd.dao.CustDaoImptry {String cName = clazz.getSimpleName();//"CustDao" 接口找实现String cImplName = prop.getProperty(cName);//com.lmd.dao.CustDaoImpreturn (T) Class.forName(cImplName).newInstance();} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}}
* `CustService.java` service包下 接口 业务逻辑层
package com.lmd.service;import java.util.List;import com.lmd.domain.Cust;import com.lmd.domain.Page;public interface CustService {/*** 添加客户* @param cust 封装了用户信息的bean*/void addCust(Cust cust);/*** 查询所有客户信息* @return*/List<Cust> getAllCust();/*** 根据id查找客户信息* @param id 客户id* @return 查找到的客户信息,如果找不到返回null;*/Cust findCustById(String id);/*** 修改客户信息的方法* @param cust 封装了最新客户信息的方法*/void updateCust(Cust cust);/*** 根据id删除客户信息* @param id 删除客户的id*/void delCustById(String id);/*** 批量删除客户* @param ids 所有客户id组成的字符串数组*/void batchDel(String[] ids);/*** 根据条件查询客户信息* @param cust 封装了查询条件的bean,有客户名/客户性别/客户类型* @return 符合条件的客户集合*/List<Cust> findCustByCond(Cust cust);/*** 分页查询客户信息* @param thispage 查询的页码* @param rowperpage 每页的记录数* @return 当前页的所有信息*/Page pageCust(int thispage, int rowperpaper);}
* `CustServiceImp.java` service包下 实现类 内含需要Dao层具体实现的方法
package com.lmd.service;import java.sql.Connection;import java.sql.SQLException;import java.util.List;import org.apache.commons.dbutils.DbUtils;import com.lmd.dao.CustDao;import com.lmd.domain.Cust;import com.lmd.domain.Page;import com.lmd.factory.BasicFactory;import com.lmd.util.DaoUtils;public class CustServiceImp implements CustService {//CustDao dao = (CustDao) BasicFactory.getFactory().getInstance("CustDao");CustDao dao = BasicFactory.getFactory().getInstance(CustDao.class);//CustService service = BasicFactory.getFactory().getInstance(CustService.class);@Overridepublic void addCust(Cust cust) {//1.检查客户名是否已经存在if (dao.findUserByName(cust.getName()) != null) {throw new RuntimeException("用户名已经存在!!!");}//2.调用Dao中的方法增加用户,如果存在提示,如果不存在则调用dao增加客户方法dao.addCust(cust);}@Overridepublic List<Cust> getAllCust() {return dao.getAllCust();}@Overridepublic Cust findCustById(String id) {return dao.findCustById(id);}@Overridepublic void updateCust(Cust cust) {dao.updateCust(cust);}@Overridepublic void delCustById(String id) {dao.delCustById(id);}@Overridepublic void batchDel(String[] ids) {//为了实现事务,使用了Connection,其是Dao层的东西//产生耦合,不好,后面会改进Connection conn = DaoUtils.getConn();try {conn.setAutoCommit(false);for (String id : ids) {dao.delCustByIdWithTrans(conn,id);}//int i = 1/0;//回滚测试DbUtils.commitAndCloseQuietly(conn);} catch (Exception e) {DbUtils.rollbackAndCloseQuietly(conn);e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic List<Cust> findCustByCond(Cust cust) {return dao.findCustByCond(cust);}@Overridepublic Page pageCust(int thispage, int rowperpage) {Page page = new Page();//--当前页page.setThispage(thispage);//--每页记录数page.setRowperpage(rowperpage);//--总记录数int countrow = dao.getCountRow();page.setCountrow(countrow);//--总页数int countpage = countrow/rowperpage+(countrow%rowperpage==0?0:1);page.setCountpage(countpage);//--首页page.setFirstpage(1);//--尾页page.setLastpage(countpage);//--上一页page.setPrevpage(thispage==1?1:thispage-1);//--下一页page.setNextpage(thispage==countpage?countpage:thispage+1);//--当前页数据List<Cust> list = dao.getCustByPage((thispage-1)*rowperpage,rowperpage);page.setCustList(list);return page;}}
* `DaoUtils.java` utils包下 访问数据源
package com.lmd.util;import java.sql.Connection;import javax.sql.DataSource;import com.mchange.v2.c3p0.ComboPooledDataSource;public class DaoUtils {private static DataSource source = new ComboPooledDataSource();private DaoUtils(){}public static DataSource getSource(){return source;}public static Connection getConn(){try {return source.getConnection();} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}}
* `CustDao.java` dao包下 接口 数据访问层(访问数据库)
package com.lmd.dao;import java.sql.Connection;import java.sql.SQLException;import java.util.List;import com.lmd.domain.Cust;import com.lmd.domain.Page;public interface CustDao {/*** 检查客户名是否已经存在* @param name 客户名* @return 找不到,返回null*/Cust findUserByName(String name);/*** 添加客户* @param cust*/void addCust(Cust cust);/*** 查询所有客户信息组成的集合* @return 封装了所有客户信息的集合,若没有返回null*/List<Cust> getAllCust();/*** 根据客户id查找客户信息* @param id 客户id* @return 最新客户信息bean*/Cust findCustById(String id);/*** 修改客户信息* @param cust* @return 最新客户信息bean*/void updateCust(Cust cust);/*** 根据id删除客户信息* @param id 删除客户的id*/void delCustById(String id);/*** 根据id删除客户信息,并管理事务* @param conn* @param id 删除客户的id* @throws SQLException*/void delCustByIdWithTrans(Connection conn, String id) throws SQLException;/*** 根据条件查询客户信息* @param cust 封装了查询条件的bean,有客户名/客户性别/客户类型* @return 符合条件的客户集合*/List<Cust> findCustByCond(Cust cust);/*** 查询数据库有多少条记录* @return 记录数*/int getCountRow();/*** 查询指定记录后多少条记录* @param from 从哪条记录后取* @param count 取的记录数* @return*/List<Cust> getCustByPage(int from, int count);}
* `CustDaoImp.java` Dao层的接口实现类 (省写验证输入项是否正确或是否为空的方法)
package com.lmd.dao;import java.sql.Connection;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import org.apache.commons.dbutils.QueryRunner;import org.apache.commons.dbutils.handlers.BeanHandler;import org.apache.commons.dbutils.handlers.BeanListHandler;import org.apache.commons.dbutils.handlers.ScalarHandler;import com.lmd.domain.Cust;import com.lmd.util.DaoUtils;public class CustDaoImp implements CustDao{@Overridepublic Cust findUserByName(String name) {try {String sql = "select * from customer where name=?";QueryRunner runner = new QueryRunner(DaoUtils.getSource());return runner.query(sql, new BeanHandler<Cust>(Cust.class), name);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic void addCust(Cust cust) {String sql = "insert into customer values (null,?,?,?,?,?,?,?,?)";try {QueryRunner runner = new QueryRunner(DaoUtils.getSource());runner.update(sql, cust.getName(), cust.getGender(), cust.getBirthday(),cust.getCellphone(), cust.getEmail(), cust.getPreference(),cust.getType(), cust.getDescription());} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic List<Cust> getAllCust() {String sql = "select * from customer";try{QueryRunner runner = new QueryRunner(DaoUtils.getSource());return runner.query(sql, new BeanListHandler<Cust>(Cust.class));} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic Cust findCustById(String id) {try {String sql = "select * from customer where id=?";QueryRunner runner = new QueryRunner(DaoUtils.getSource());return runner.query(sql, new BeanHandler<Cust>(Cust.class), id);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic void updateCust(Cust cust) {try {String sql = "update customer set name=?,gender=?,birthday=?,cellphone=?"+ ",email=?,preference=?,type=?,description=? where id=?";QueryRunner runner = new QueryRunner(DaoUtils.getSource());runner.update(sql, cust.getName(), cust.getGender(), cust.getBirthday(),cust.getCellphone(), cust.getEmail(), cust.getPreference(),cust.getType(), cust.getDescription(),cust.getId());} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic void delCustById(String id) {try {String sql = "delete from customer where id=?";QueryRunner runner = new QueryRunner(DaoUtils.getSource());runner.update(sql,id);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic void delCustByIdWithTrans(Connection conn, String id) throws SQLException {String sql = "delete from customer where id=?";QueryRunner runner = new QueryRunner();runner.update(conn,sql,id);}@Overridepublic List<Cust> findCustByCond(Cust cust) {String sql = "select * from customer where 1=1";List<Object> list = new ArrayList<Object>();if (cust.getName()!=null && !"".equals(cust.getName())) {sql += " and name like ?";list.add("%"+cust.getName()+"%");}if (cust.getGender()!=null && !"".equals(cust.getGender())) {sql += " and gender=?";list.add(cust.getGender());}if (cust.getType()!=null && !"".equals(cust.getType())) {sql += " and type=?";list.add(cust.getType());}try {QueryRunner runner = new QueryRunner(DaoUtils.getSource());if (list.size()<=0) {return runner.query(sql, new BeanListHandler<Cust>(Cust.class));}return runner.query(sql, new BeanListHandler<Cust>(Cust.class), list.toArray());} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic int getCountRow() {String sql = "select count(*) from customer";try {QueryRunner runner = new QueryRunner(DaoUtils.getSource());return ((Long) runner.query(sql, new ScalarHandler())).intValue();} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}@Overridepublic List<Cust> getCustByPage(int from, int count) {String sql = "select * from customer limit ?,?";try {QueryRunner runner = new QueryRunner(DaoUtils.getSource());return runner.query(sql, new BeanListHandler<Cust>(Cust.class), from, count);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException(e);}}}
(1)、添加用户
* `addCust.jsp` 添加用户界面
<body style="text-align: center;"><h1>客户管理系统_添加客户</h1><form action="${pageContext.request.contextPath }/AddCustServlet" method="post"><table align="center" border="1"><tr><td>客户姓名</td><td><input type="text" name="name" /></td></tr><tr><td>客户性别</td><td><input type="radio" name="gender" value="男" checked="checked" />男<input type="radio" name="gender" value="女" />女</td></tr><tr><td>客户生日</td><td><input type="text" name="birthday" /></td></tr><tr><td>手机号码</td><td><input type="text" name="cellphone" /></td></tr><tr><td>电子邮件</td><td><input type="text" name="email" /></td></tr><tr><td>客户爱好</td><td><input type="checkbox" name="preference" value="篮球" />篮球(钢琴、舞蹈)</td></tr><tr><td>客户类型</td><td><select name="type"><option value="钻石用户">钻石用户</option>(白金、白银、青铜等等)</select></td></tr><tr><td>备注信息</td><td><textarea rows="6" cols="30" name = "description"></textarea></td></tr><tr><td colspan="2"><input type="submit" value="添加用户" /></td></tr></table></form></body>
* `AddCustServlet.java 添加用户实现
package com.lmd.web;import java.io.IOException;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 org.apache.commons.beanutils.BeanUtils;import com.lmd.domain.Cust;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class AddCustServlet*/@WebServlet("/AddCustServlet")public class AddCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {request.setCharacterEncoding("UTF-8");response.setContentType("text/html; charset=UTF-8");CustService service = BasicFactory.getFactory().getInstance(CustService.class);// 1.封装数据,省写校验数据Cust cust = new Cust();try {BeanUtils.populate(cust, request.getParameterMap());//单独处理爱好String[] prfs = request.getParameterValues("preference");StringBuffer buffer = new StringBuffer();for (String pref : prfs) {buffer.append(pref+",");}String pref = buffer.substring(0, buffer.length()-1);cust.setPreference(pref);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}// 2.调用Service层添加客户的方法service.addCust(cust);//Ctrl+1添加方法//3.重定向回到主页response.sendRedirect(request.getContextPath()+"/index.jsp");}}
(2)、查询用户列表、修改、删除及条件查询
* `listCust.jsp` 显示所有用户信息、修改客户信息、条件查询客户信息、删除客户 界面
<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><script type="text/javascript">function checkAll(allC){var otherChs = document.getElementsByName("delId");for(var i=0; i<otherChs.length; i++){otherChs[i].checked = allC.checked;}}</script></head><body style="text-align: center;"><h1>客户管理系统_客户列表页面</h1><form action="${pageContext.request.contextPath }/FindCustByCondServlet" method="post"">客户姓名:<input type="text" name="name" value="${param.name }"/>客户性别:<input type="radio" name="gender" value="男"<c:if test="${param.gender=='男'}">checked='checked'</c:if>/>男<input type="radio" name="gender" value="女"<c:if test="${param.gender=='女'}">checked='checked'</c:if>/>女<input type="radio" name="gender" value="" />无客户类型:<select name="type"><option value=""></option><option value="钻石用户"<c:if test="${param.type=='钻石用户' }">selected='selected'</c:if>>钻石用户</option><option value="白金用户"<c:if test="${param.type=='白金用户' }">selected='selected'</c:if>>白金用户</option><option value="黄金用户"<c:if test="${param.type=='黄金用户' }">selected='selected'</c:if>>黄金用户</option><option value="白银用户"<c:if test="${param.type=='白银用户' }">selected='selected'</c:if>>白银用户</option><option value="青铜用户"<c:if test="${param.type=='青铜用户' }">selected='selected'</c:if>>青铜用户</option><option value="普通用户"<c:if test="${cust.type=='普通用户' }">selected='selected'</c:if>>普通用户</option></select><input type="submit" value="条件查询用户" /></form><form action="${pageContext.request.contextPath }/BatchDelCustServlet" method="post"><table border="1" width="100%" align="center"><tr><th><input type="checkbox" onchange="checkAll(this)" />全选</th><th>客户姓名</th><th>客户性别</th><th>出生日期</th><th>手机号码</th><th>电子邮件</th><th>客户爱好</th><th>客户类型</th><th>描述信息</th><th>修改</th><th>删除</th></tr><c:forEach items="${requestScope.list }" var="cust"><tr><!-- 使用标签解决引导入侵,不让字符转义 --><td><input type="checkbox" name="delId" value="${cust.id }" /></td><td><c:out value="${cust.name }"/></td><td><c:out value="${cust.gender }"/></td><td><c:out value="${cust.birthday }"/></td><td><c:out value="${cust.cellphone }"/></td><td><c:out value="${cust.email }"/></td><td><c:out value="${cust.preference }"/></td><td><c:out value="${cust.type }"/></td><td><c:out value="${cust.description }"/></td><td><a href="${pageContext.request.contextPath }/CustInfoServlet?id=${cust.id}">修改</a></td><td><a href="${pageContext.request.contextPath }/DelCustServlet?id=${cust.id}">删除</a></td></tr></c:forEach></table><input type="submit" value="批量删除" /></form></body></html>
* ListCustServlet.java 显示所有用户信息实现
package com.lmd.web;import java.io.IOException;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.lmd.domain.Cust;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class ListCustServlet*/@WebServlet("/ListCustServlet")public class ListCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {CustService service = BasicFactory.getFactory().getInstance(CustService.class);//1、调用service中查询所有客户的方法List<Cust> list = service.getAllCust();//2、将查找的信息存在request域,请求转发到listCust.jsp页面进行展示request.setAttribute("list", list);request.getRequestDispatcher("/listCust.jsp").forward(request, response);}}
1)、修改客户信息
* `updateCust.jsp` 修改客户信息界面
<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head></head><body style="text-align: center;"><h1>客户管理系统_修改客户</h1><form action="${pageContext.request.contextPath }/UpdateCustServlet" method="post"><input type="hidden" name="id" value="${cust.id }" /><table align="center" border="1"><tr><td>客户姓名</td><td><input type="text" name="name" value="${cust.name }" readonly="readonly" style="background: silver;"/></td></tr><tr><td>客户性别</td><td><input type="radio" name="gender" value="男"<c:if test="${cust.gender=='男'}">checked='checked'</c:if>/>男<input type="radio" name="gender" value="女"<c:if test="${cust.gender=='女'}">checked='checked'</c:if>/>女</td></tr><tr><td>客户生日</td><td><input type="text" name="birthday" value="${cust.birthday }" /></td></tr><tr><td>手机号码</td><td><input type="text" name="cellphone" value="${cust.cellphone }" /></td></tr><tr><td>电子邮件</td><td><input type="text" name="email" value="${cust.email }" /></td></tr><tr><td>客户爱好</td><td><input type="checkbox" name="preference" value="篮球"<c:forTokens items="${cust.preference }" delims="," var="pref"><c:if test="${pref=='篮球'}">checked='checked'</c:if></c:forTokens>/>篮球<input type="checkbox" name="preference" value="钢琴"<c:if test="${fn:contains(cust.preference, '钢琴') }">checked='checked'</c:if>/>钢琴<input type="checkbox" name="preference" value="舞蹈"<c:if test="${fn:contains(cust.preference, '舞蹈') }">checked='checked'</c:if>/>舞蹈<input type="checkbox" name="preference" value="跑步"<c:if test="${fn:contains(cust.preference, '跑步') }">checked='checked'</c:if>/>跑步</td></tr><tr><td>客户类型</td><td><select name="type"><option value="钻石用户"<c:if test="${cust.type=='钻石用户' }">selected='selected'</c:if>>钻石用户</option><option value="白金用户"<c:if test="${cust.type=='白金用户' }">selected='selected'</c:if>>白金用户</option><option value="黄金用户"<c:if test="${cust.type=='黄金用户' }">selected='selected'</c:if>>黄金用户</option><option value="白银用户"<c:if test="${cust.type=='白银用户' }">selected='selected'</c:if>>白银用户</option><option value="青铜用户"<c:if test="${cust.type=='青铜用户' }">selected='selected'</c:if>>青铜用户</option><option value="普通用户"<c:if test="${cust.type=='普通用户' }">selected='selected'</c:if>>普通用户</option></select></td></tr><!-- 造成引导入侵,例如输入javascript代码,会弹出结果 --><tr><td>备注信息</td><td><textarea rows="6" cols="30" name="description">${cust.description }</textarea></td></tr><tr><td colspan="2"><a href="${pageContext.request.contextPath}/updateCust.jsp"><input type="submit" value="添加用户"/></a></td></tr></table></form></body></html>
* `UpdateCustServlet.java` 修改客户信息实现
package com.lmd.web;import java.io.IOException;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 org.apache.commons.beanutils.BeanUtils;import com.lmd.domain.Cust;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class UpdateCustServlet*/@WebServlet("/UpdateCustServlet")public class UpdateCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {CustService service = BasicFactory.getFactory().getInstance(CustService.class);// 1.封装数据,省写校验数据Cust cust = new Cust();try {BeanUtils.populate(cust, request.getParameterMap());//单独处理爱好String[] prfs = request.getParameterValues("preference");StringBuffer buffer = new StringBuffer();for (String pref : prfs) {buffer.append(pref+",");}String pref = buffer.substring(0, buffer.length()-1);cust.setPreference(pref);} catch (Exception e) {e.printStackTrace();throw new RuntimeException(e);}// 2.调用Service层修改客户的方法service.updateCust(cust);//Ctrl+1添加方法//3.重定向回到客户列表页面request.getRequestDispatcher("/ListCustServlet").forward(request, response);}}
2)、单个删除客户
* `ListCustServlet.java` 单个删除客户实现
package com.lmd.web;import java.io.IOException;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 org.apache.commons.beanutils.BeanUtils;import com.lmd.domain.Cust;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class DelCustServlet*/@WebServlet("/DelCustServlet")public class DelCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {CustService service = BasicFactory.getFactory().getInstance(CustService.class);// 1.获取要删除的客户idString id = request.getParameter("id");// 2.调用Service层id删除客户的方法service.delCustById(id);//Ctrl+1添加方法//3.转发到客户列表页面request.getRequestDispatcher("/ListCustServlet").forward(request, response);}public void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
3)、批量删除客户
* `ListCustServlet.java` 显示所有用户信息实现
package com.lmd.web;import java.io.IOException;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 org.apache.commons.beanutils.BeanUtils;import com.lmd.domain.Cust;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class BatchDelCustServlet*/@WebServlet("/BatchDelCustServlet")public class BatchDelCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {CustService service = BasicFactory.getFactory().getInstance(CustService.class);// 1.获取所有删除的客户idString[] ids = request.getParameterValues("delId");// 2.调用Service层批量删除客户的方法service.batchDel(ids);//Ctrl+1添加方法//3.转发到客户列表页面request.getRequestDispatcher("/ListCustServlet").forward(request, response);}}
(3)、分页查询用户列表
* `pageCust.jsp` 分页显示用户信息界面
<%@ page language="java" contentType="text/html; charset=UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><script type="text/javascript">function changePage(obj){if(isNaN(obj.value)){alert("必须是数字!!!");obj.value = ${page.thispage};} else{if(obj.value<=0 || obj.value>${page.countpage}){alert("必须是有效范围内的页码!!!");obj.value = ${page.thispage};return;} else {window.location.href = "${pageContext.request.contextPath }/PageCustServlet?thispage="+obj.value;}}}</script></head><body style="text-align: center;"><h1>客户管理系统_客户列表页面</h1><table border="1" width="100%" align="center"><tr><th>客户姓名</th><th>客户性别</th><th>出生日期</th><th>手机号码</th><th>电子邮件</th><th>客户爱好</th><th>客户类型</th><th>描述信息</th><th>修改</th><th>删除</th></tr><c:forEach items="${requestScope.page.custList }" var="cust"><tr><!-- 使用标签解决引导入侵,不让字符转义 --><td><c:out value="${cust.name }"/></td><td><c:out value="${cust.gender }"/></td><td><c:out value="${cust.birthday }"/></td><td><c:out value="${cust.cellphone }"/></td><td><c:out value="${cust.email }"/></td><td><c:out value="${cust.preference }"/></td><td><c:out value="${cust.type }"/></td><td><c:out value="${cust.description }"/></td><td><a href="${pageContext.request.contextPath }/CustInfoServlet?id=${cust.id}">修改</a></td><td><a href="${pageContext.request.contextPath }/DelCustServlet?id=${cust.id}">删除</a></td></tr></c:forEach></table><div style="text-align: center;">共${page.countrow }条记录 共${page.countpage }页 <a href="${pageContext.request.contextPath }/PageCustServlet?thispage=${page.firstpage}">首页</a><a href="${pageContext.request.contextPath }/PageCustServlet?thispage=${page.prevpage}">上一页</a><!-- 分页逻辑开始 --><c:if test="${page.countpage<=5 }"><c:set var="begin" value="1" scope="page"></c:set><c:set var="end" value="${page.countpage }" scope="page"></c:set></c:if><c:if test="${page.countpage>5 }"><c:choose><c:when test="${page.thispage<=3 }"><c:set var="begin" value="1" scope="page"></c:set><c:set var="end" value="5" scope="page"></c:set></c:when><c:when test="${page.thispage>=page.countpage-2 }"><c:set var="begin" value="${page.countpage-4 }" scope="page"></c:set><c:set var="end" value="${page.countpage}" scope="page"></c:set></c:when><c:otherwise><c:set var="begin" value="${page.thispage-2 }" scope="page"></c:set><c:set var="end" value="${page.thispage+2}" scope="page"></c:set></c:otherwise></c:choose></c:if><c:forEach begin="${begin }" end="${end }" var="i"><c:if test="${i==page.thispage }">${i }</c:if><c:if test="${i!=page.thispage }"><a href="${pageContext.request.contextPath }/PageCustServlet?thispage=${i}">${i }</a></c:if></c:forEach><!-- 分页逻辑结束 --><a href="${pageContext.request.contextPath }/PageCustServlet?thispage=${page.nextpage}">下一页</a><a href="${pageContext.request.contextPath }/PageCustServlet?thispage=${page.lastpage}">尾页</a>跳转到<input type="text" value="${page.thispage }" size="1" onchange="changePage(this)"/>页</div></body></html>
* PageCustServle.java 显示所有用户信息实现
package com.lmd.web;import java.io.IOException;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.lmd.domain.Cust;import com.lmd.domain.Page;import com.lmd.factory.BasicFactory;import com.lmd.service.CustService;/*** Servlet implementation class PageCustServlet*/@WebServlet("/PageCustServlet")public class PageCustServlet extends HttpServlet {public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {CustService service = BasicFactory.getFactory().getInstance(CustService.class);//1、获取当前要显示的页和每页记录数int thispage = Integer.parseInt(request.getParameter("thispage"));int rowperpage = 5;//2、调用service中分页查询客户的方法,查找出客户信息Page page = service.pageCust(thispage,rowperpage);//2、存入request域,请求转发到pageCust.jsp页面进行展示request.setAttribute("page", page);request.getRequestDispatcher("/pageCust.jsp").forward(request, response);}}



浙公网安备 33010602011771号