网上图书商城项目学习笔记-001工具类测试
工具类测试
工具类分析图
1.BeanHandler
2.MapHandler
3.多表查询映射
1.CommonUtilsTest.java
1 package cn.itcast.test; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import org.junit.Test; 7 8 import cn.itcast.commons.CommonUtils; 9 10 /** 11 * 测试CommonUtils类 12 // * CommonUtils类依赖的jar:commons-beanutils.jar、commons-logging.jar 13 * @author qdmmy6 14 * 15 */ 16 public class CommonUtilsTest { 17 /** 18 * 测试uuid() 19 * 返回一个随机的32长的字符串 20 * 用途: 21 * 1. 用来做id,数据库表中的主键是不能重复的,它就是不重复的! 22 * 2. 激活码也是不能重复的!也可以用它 23 * 24 */ 25 @Test 26 public void testUuid() { 27 String s = CommonUtils.uuid(); 28 System.out.println(s); 29 } 30 31 /** 32 * 作用:把一个map中的数据封装到javabean中 33 * 要求: 34 * 1. 要求map中的key名称与javabean中的属性名称相同 35 */ 36 @Test 37 public void testToBean() { 38 /* 39 * 1. 创建Map 40 */ 41 Map<String,Object> map = new HashMap<String,Object>(); 42 map.put("pid", "123"); 43 map.put("pname", "张三"); 44 map.put("age", "23"); 45 map.put("xxx", "XXX"); 46 47 // 通过map的数据来创建Person类型的JavaBean对象 48 Person p = CommonUtils.toBean(map, Person.class); 49 System.out.println(p); 50 } 51 }
源码:CommonUtils.java
1 package cn.itcast.commons; 2 3 import java.util.Map; 4 import java.util.UUID; 5 6 import org.apache.commons.beanutils.BeanUtils; 7 import org.apache.commons.beanutils.ConvertUtils; 8 9 /** 10 * 小小工具 11 * @author qdmmy6 12 * 13 */ 14 public class CommonUtils { 15 /** 16 * 返回一个不重复的字符串 17 * @return 18 */ 19 public static String uuid() { 20 return UUID.randomUUID().toString().replace("-", "").toUpperCase(); 21 } 22 23 /** 24 * 把map转换成对象 25 * @param map 26 * @param clazz 27 * @return 28 * 29 * 把Map转换成指定类型 30 */ 31 @SuppressWarnings("rawtypes") 32 public static <T> T toBean(Map map, Class<T> clazz) { 33 try { 34 /* 35 * 1. 通过参数clazz创建实例 36 * 2. 使用BeanUtils.populate把map的数据封闭到bean中 37 */ 38 T bean = clazz.newInstance(); 39 ConvertUtils.register(new DateConverter(), java.util.Date.class); 40 BeanUtils.populate(bean, map); 41 return bean; 42 } catch(Exception e) { 43 throw new RuntimeException(e); 44 } 45 } 46 }
2.JdbcUtilsTest.java
1 package cn.itcast.test; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 6 import org.junit.Test; 7 8 import cn.itcast.jdbc.JdbcUtils; 9 10 /** 11 * JdbcUtils用来获取Connection 12 * * 底层使用了c3p0连接池! 13 * * 还需要mysql驱动 14 * @author qdmmy6 15 * 16 */ 17 public class JdbcUtilsTest { 18 /** 19 * 底层使用了c3p0连接池,说明我们还要提供c3p0配置文件 20 * @throws SQLException 21 */ 22 @Test 23 public void testGetConnection() throws SQLException { 24 Connection con = JdbcUtils.getConnection(); 25 System.out.println(con);; 26 JdbcUtils.releaseConnection(con); 27 System.out.println(con.isClosed()); 28 } 29 30 /** 31 * JdbcUtilst还提供了与事务相关的功能 32 * 33 */ 34 @Test 35 public void testTransaction() { 36 try { 37 JdbcUtils.beginTransaction();//开启事务 38 39 // 多次操作 40 41 JdbcUtils.commitTransaction();//提交事务 42 } catch(Exception e) { 43 try { 44 JdbcUtils.rollbackTransaction();//回滚事务 45 } catch (SQLException e1) { 46 } 47 } 48 } 49 }
源码:JdbcUtils.java
1 package cn.itcast.jdbc; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 6 import javax.sql.DataSource; 7 8 import com.mchange.v2.c3p0.ComboPooledDataSource; 9 10 /** 11 * 使用本类的方法,必须提供c3p0-copnfig.xml文件 12 * @author qdmmy6 13 */ 14 public class JdbcUtils { 15 // 饿汉式 16 private static DataSource ds = new ComboPooledDataSource(); 17 18 /** 19 * 它为null表示没有事务 20 * 它不为null表示有事务 21 * 当开启事务时,需要给它赋值 22 * 当结束事务时,需要给它赋值为null 23 * 并且在开启事务时,让dao的多个方法共享这个Connection 24 */ 25 private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); 26 27 public static DataSource getDataSource() { 28 return ds; 29 } 30 31 /** 32 * dao使用本方法来获取连接 33 * @return 34 * @throws SQLException 35 */ 36 public static Connection getConnection() throws SQLException { 37 /* 38 * 如果有事务,返回当前事务的con 39 * 如果没有事务,通过连接池返回新的con 40 */ 41 Connection con = tl.get();//获取当前线程的事务连接 42 if(con != null) return con; 43 return ds.getConnection(); 44 } 45 46 /** 47 * 开启事务 48 * @throws SQLException 49 */ 50 public static void beginTransaction() throws SQLException { 51 Connection con = tl.get();//获取当前线程的事务连接 52 if(con != null) throw new SQLException("已经开启了事务,不能重复开启!"); 53 con = ds.getConnection();//给con赋值,表示开启了事务 54 con.setAutoCommit(false);//设置为手动提交 55 tl.set(con);//把当前事务连接放到tl中 56 } 57 58 /** 59 * 提交事务 60 * @throws SQLException 61 */ 62 public static void commitTransaction() throws SQLException { 63 Connection con = tl.get();//获取当前线程的事务连接 64 if(con == null) throw new SQLException("没有事务不能提交!"); 65 con.commit();//提交事务 66 con.close();//关闭连接 67 con = null;//表示事务结束! 68 tl.remove(); 69 } 70 71 /** 72 * 回滚事务 73 * @throws SQLException 74 */ 75 public static void rollbackTransaction() throws SQLException { 76 Connection con = tl.get();//获取当前线程的事务连接 77 if(con == null) throw new SQLException("没有事务不能回滚!"); 78 con.rollback(); 79 con.close(); 80 con = null; 81 tl.remove(); 82 } 83 84 /** 85 * 释放Connection 86 * @param con 87 * @throws SQLException 88 */ 89 public static void releaseConnection(Connection connection) throws SQLException { 90 Connection con = tl.get();//获取当前线程的事务连接 91 if(connection != con) {//如果参数连接,与当前事务连接不同,说明这个连接不是当前事务,可以关闭! 92 if(connection != null &&!connection.isClosed()) {//如果参数连接没有关闭,关闭之! 93 connection.close(); 94 } 95 } 96 } 97 }
3.TxQueryRunnerTest.java
1 package cn.itcast.test; 2 3 import java.sql.SQLException; 4 import java.util.List; 5 import java.util.Map; 6 7 import org.apache.commons.dbutils.QueryRunner; 8 import org.apache.commons.dbutils.handlers.BeanHandler; 9 import org.apache.commons.dbutils.handlers.BeanListHandler; 10 import org.apache.commons.dbutils.handlers.MapHandler; 11 import org.apache.commons.dbutils.handlers.MapListHandler; 12 import org.apache.commons.dbutils.handlers.ScalarHandler; 13 import org.junit.Test; 14 15 import cn.itcast.commons.CommonUtils; 16 import cn.itcast.jdbc.JdbcUtils; 17 import cn.itcast.jdbc.TxQueryRunner; 18 19 /** 20 * TxQueryRunner它是QueryRunner的子类!(commons-dbutils.jar) 21 * 可用起来与QueryRunner相似的! 22 * 我们的类支持事务!它底层使用了JdbcUtils来获取连接! 23 * 24 * 简化jdbc的操作 25 * QueryRunner的三个方法: 26 * * update() --> insert、update、delete 27 * * query() --> select 28 * * batch() --> 批处理 29 * @author qdmmy6 30 * 31 */ 32 public class TxQueryRunnerTest { 33 /** 34 * 测试update()方法,用来执行insert、update、delete语句 35 * @throws SQLException 36 */ 37 @Test 38 public void testUpdate() throws SQLException { 39 String sql = "insert into t_person(pid,pname,age,sex) values(?,?,?,?)"; 40 Object[] params = {"1", "p1", 1, "男"};//给sql中对应的参数 41 42 QueryRunner qr = new TxQueryRunner();//我们没有给对象提供连接池 43 qr.update(sql, params);//执行sql,也不提供连接,它内部会使用JdbcUtils来获取连接 44 } 45 46 /** 47 * 使用事务 48 * @throws SQLException 49 */ 50 @Test 51 public void testUpdate2() throws Exception { 52 try { 53 JdbcUtils.beginTransaction();//开启事务 54 55 String sql = "insert into t_person(pid,pname,age,sex) values(?,?,?,?)"; 56 QueryRunner qr = new TxQueryRunner(); 57 Object[] params = {"2", "p2", 2, "女"}; 58 qr.update(sql, params);//执行 59 60 if(false) { 61 throw new Exception(); 62 } 63 64 params = new Object[]{"3", "p3", 3, "女"}; 65 qr.update(sql, params);//执行 66 67 JdbcUtils.commitTransaction();//提交事务 68 } catch(Exception e) { 69 try { 70 JdbcUtils.rollbackTransaction();//回滚事务 71 } catch (SQLException e1) { 72 } 73 throw e; 74 } 75 } 76 77 /** 78 * 测试查询方法 79 * 我们知道JDBC查询的结果的是ResultSet 80 * 而QueryRunner查询的结果是通过ResultSet映射后的数据。 81 * * QueryRunner第一步是执行select,得到ResultSet 82 * * 把ResultSet转换成其他类型的! 83 * 通过转换结果: 84 * * javaBean:把结果集封装到javaBean中 85 * * Map:把结果集封装到Map中 86 * * 把结果集封装到Object中(结果集是单行单列) 87 * @throws SQLException 88 * 89 * 90 */ 91 /* 92 * 单行结果集映射到javaBean中 93 */ 94 @Test 95 public void testQuery1() throws SQLException { 96 String sql = "select * from t_person where pid=?"; 97 QueryRunner qr = new TxQueryRunner(); 98 /* 99 * 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。 100 * 101 * BeanHandler --> 它是ResultSetHandler的实现类,它的作用是把结果集封装到Person对象中 102 */ 103 Person p = qr.query(sql, new BeanHandler<Person>(Person.class), "1"); 104 System.out.println(p); 105 } 106 107 /** 108 * 使用BeanListHandler 109 * 把多行结果集映射到List<Bean>,即多个JavaBean对象。 110 * 一行结果集记录对应一个javaBean对象,多行就对应List<Bean> 111 * @throws SQLException 112 */ 113 @Test 114 public void testQuery2() throws SQLException { 115 String sql = "select * from t_person"; 116 QueryRunner qr = new TxQueryRunner(); 117 /* 118 * 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。 119 * 120 * BeanListHandler --> 它是ResultSetHandler的实现类, 121 * 它的作用是把结果集封装到List<Person>对象中 122 */ 123 List<Person> list = qr.query(sql, new BeanListHandler<Person>(Person.class)); 124 System.out.println(list); 125 } 126 127 /** 128 * 使用MapHandler,把单行结果集封装到Map对象中 129 * @throws SQLException 130 */ 131 @Test 132 public void testQuery3() throws SQLException { 133 String sql = "select * from t_person where pid=?"; 134 QueryRunner qr = new TxQueryRunner(); 135 /* 136 * 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。 137 * 138 * BeanListHandler --> 它是ResultSetHandler的实现类, 139 * 它的作用是把结果集封装到List<Person>对象中 140 */ 141 Map<String, Object> map = qr.query(sql, new MapHandler(), "1"); 142 System.out.println(map); 143 } 144 145 /** 146 * 使用MapListHandler,把多行结果集封装到List<Map>中,即多个Map 147 * 一行对应一个Map,多行对应List<Map> 148 * @throws SQLException 149 */ 150 @Test 151 public void testQuery4() throws SQLException { 152 String sql = "select * from t_person"; 153 QueryRunner qr = new TxQueryRunner(); 154 /* 155 * 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。 156 * 157 * BeanListHandler --> 它是ResultSetHandler的实现类, 158 * 它的作用是把结果集封装到List<Person>对象中 159 */ 160 List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler()); 161 System.out.println(mapList); 162 } 163 164 /** 165 * 使用ScalarHandler,把单行单列的结果集封装到Object中 166 * @throws SQLException 167 */ 168 @Test 169 public void testQuery5() throws SQLException { 170 String sql = "select count(*) from t_person";//结果集是单行单列的 171 QueryRunner qr = new TxQueryRunner(); 172 173 Object obj = qr.query(sql, new ScalarHandler()); 174 /* 175 * 我们知道select count(1),结果一定是个整数! 176 * > Integer 177 * > Long 178 * > BigInteger 179 * 180 * 不同的驱动,结果不同! 181 * 无论是哪种类型,它都是Number类型!强转成Number一定不出错 182 */ 183 Number number = (Number)obj; 184 long cnt = number.longValue(); 185 System.out.println(cnt); 186 } 187 188 /** 189 * 一行结果集中包含了两张表的列 190 * 使用MapHandler来处理 191 * 1. 把结果集封装到map中 192 * 2. 使用map生成Person对象 193 * 3. 使用map生成address对象 194 * 4. 把两个实体对象建立关系 195 * @throws SQLException 196 */ 197 @Test 198 public void testQuery6() throws SQLException { 199 String sql = "SELECT * FROM t_person p, t_address a WHERE p.aid=a.aid AND p.pid=?"; 200 QueryRunner qr = new TxQueryRunner(); 201 /* 202 * 1. 得到Map 203 */ 204 Map map = qr.query(sql, new MapHandler(), "aaa"); 205 /* 206 * 2. 把Map中部分数据封装到Person中 207 */ 208 Person p = CommonUtils.toBean(map, Person.class); 209 /* 210 * 3. 把Map中部分数据封装到Address中 211 */ 212 Address addr = CommonUtils.toBean(map, Address.class); 213 /* 214 * 4. 建立两个实体的关系 215 */ 216 p.setAddress(addr); 217 218 System.out.println(p); 219 } 220 }
源码:TxQueryRunner.java
1 package cn.itcast.jdbc; 2 3 import java.sql.Connection; 4 import java.sql.SQLException; 5 6 import org.apache.commons.dbutils.QueryRunner; 7 import org.apache.commons.dbutils.ResultSetHandler; 8 9 public class TxQueryRunner extends QueryRunner { 10 11 @Override 12 public int[] batch(String sql, Object[][] params) throws SQLException { 13 Connection con = JdbcUtils.getConnection(); 14 int[] result = super.batch(con, sql, params); 15 JdbcUtils.releaseConnection(con); 16 return result; 17 } 18 19 @Override 20 public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) 21 throws SQLException { 22 Connection con = JdbcUtils.getConnection(); 23 T result = super.query(con, sql, rsh, params); 24 JdbcUtils.releaseConnection(con); 25 return result; 26 } 27 28 @Override 29 public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException { 30 Connection con = JdbcUtils.getConnection(); 31 T result = super.query(con, sql, rsh); 32 JdbcUtils.releaseConnection(con); 33 return result; 34 } 35 36 @Override 37 public int update(String sql) throws SQLException { 38 Connection con = JdbcUtils.getConnection(); 39 int result = super.update(con, sql); 40 JdbcUtils.releaseConnection(con); 41 return result; 42 } 43 44 @Override 45 public int update(String sql, Object param) throws SQLException { 46 Connection con = JdbcUtils.getConnection(); 47 int result = super.update(con, sql, param); 48 JdbcUtils.releaseConnection(con); 49 return result; 50 } 51 52 @Override 53 public int update(String sql, Object... params) throws SQLException { 54 Connection con = JdbcUtils.getConnection(); 55 int result = super.update(con, sql, params); 56 JdbcUtils.releaseConnection(con); 57 return result; 58 } 59 }
源码链接:
http://pan.baidu.com/s/1pKnA7NH
小工具
工欲善其事,必先利其器。下面我们来介绍一下在项目中要使用的小工具(itcast-tools-1.4.jar)。这个小工具底层使用了:
l c3p0数据库连接池;
l common-beanutils;
l common-dbutils;
l javaMail;
1 CommonUtils
CommonUtils类就两个方法:
l String uuid():生成长度32的随机字符,通常用来做实体类的ID。底层使用了UUID类完成;
l T toBean(Map, Class<T>):把Map转换成指定类型的Bean对象。通常用来获取表单数据(request.getParameterMap())封装到JavaBean中,底层使用了common-beanutils。注意,本方法要求map中键的名称要与Bean的属性名称相同才能完成映射,否则不能完成映射。
/** * 随机生成32位长的字符串,通常用来做实体类的ID */ @Test public void testUuid() { String s = CommonUtils.uuid();//生成随机32位长的字符串 System.out.println(s); }
/** * 把Map类型映射成Bean类型。 * 要求map中键的名称与Person类的属性名称相同。 * 即map的key分别为:pid、name、age、birthday,person的属性名称也是pid、name、age、birthday */ @Test public void testToBean() { Map<String,String> map = new HashMap<String,String>(); /* * map的key:pid、age、birthday、myname * person的属性:pid、age、birthday、name * map中没有名为name的键值,而多出一个名为myname的键值,所以映射后的person对象的name属性值为null。 * map中的age和birthday都是字符串类型,而person的age是int类型、birthday是Date类型,但toBean()方法会自动对Map中值进行类型转换。 */ map.put("pid", CommonUtils.uuid()); map.put("age", "23"); map.put("birthday", "2014-01-30"); map.put("myname", "张三");
Person p = CommonUtils.toBean(map, Person.class); System.out.println(p); } |
2 JdbcUtils
JdbcUtils用来获取Connection对象,以及开启和关闭事务。
l Connection getConnection():从c3p0连接池获取Connection对象,所以需要提供c3p0-config.xml配置文件;
l beginTransaction():为当前线程开启事务;
l commitTransaction():提交当前线程的事务;
l rollbackTransaction():回滚当前线程的事务;
l releaseConnection(Connection):如果参数连接对象不是当前事务的连接对象,那么关闭它,否则什么都不做;
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8" ?> <c3p0-config> <default-config> <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="user">root</property> <property name="password">123</property>
<property name="acquireIncrement">3</property> <property name="initialPoolSize">10</property> <property name="minPoolSize">2</property> <property name="maxPoolSize">10</property> </default-config> </c3p0-config> |
JdbcUtilsTest.java
/** * 测试JdbcUtils类 * @author qdmmy6 * */ public class JdbcUtilsTest { /** * 通过C3P0连接池获取连接对象 * @throws SQLException */ @Test public void testGetConnection() throws SQLException { Connection con = JdbcUtils.getConnection();//获取连接 System.out.println(con); JdbcUtils.releaseConnection(con);//如果参数con不是当前线程的连接对象,那么关闭之 }
/** * 当开始事务后,调用getConnection()会为当前线程创建Connection,而且多次调用getConnection()返回的是同一个对象 * @throws SQLException */ @Test public void testTansaction() throws SQLException { JdbcUtils.beginTransaction();//开启事务 Connection c1 = JdbcUtils.getConnection();//第一次获取当前线程的事务连接对象 Connection c2 = JdbcUtils.getConnection();//第二次获取当前线程的事务连接对象 Assert.assertEquals(true, c1 == c2);//比较两次是否相同 JdbcUtils.commitTransaction();//提交事务 } } |
3 TxQueryRunner
TxQueryRunner类是common-dbutils下QueryRunner类的子类,用来简化JDBC操作。TxQueryRunner类内部使用了JdbcUtils.getConnection()类来获取连接对象,以及使用JdbcUtils.releaseConnection()关闭连接。
l int[] batch(String sql, Object[][] params):执行批处理,参数sql是SQL语句模板,params为参数;
l T query(String sql, ResultSetHandler<T> rh):执行查询,执行查询,参数sql为要执行的查询语句模板,rh是结果集处理,用来把结果集映射成你想要的结果;
l T query(String sql, ResultSetHandler<T> rh, Object… params):执行查询,参数sql为要执行的查询语句模板,rh是结果集处理,用来把结果集映射成你想要的结果,params是sql语句的参数;
l int update(String sql):执行增、删、改语句,参数sql是要执行的SQL语句;
l int update(Stringsql, Object param):执行增、删、改语句,参数sql是要执行的SQL语句,参数param是参数(一个参数);
l int update(String sql, Object… params):执行增、删、改语句,参数sql是要执行的SQL语句,参数params是参数(多个参数);
为了测试TxQueryRunner,我们在mydb1数据库下创建t_person表,然后再创建Person实体类,以及PersonDao类,最后测试PersonDao类中的方法。
t_person
字段 |
说明 |
pid |
主键 |
name |
姓名 |
age |
年龄 |
birthday |
生日 |
Person.java
public class Person { private String pid; private String name; private int age; private Date birthday; … } |
PersonDao.java
/** * 测试TxQueryRunner * @author qdmmy6 * */ public class PersonDao { private QueryRunner qr = new TxQueryRunner();
public void add(Person person) throws SQLException { String sql = "insert into t_person values(?,?,?,?)"; Object[] params = {person.getPid(), person.getName(), person.getAge(), new java.sql.Date(person.getBirthday().getTime())}; qr.update(sql, params); }
public void edit(Person person) throws SQLException { String sql = "update t_person set name=?,age=?,birthday=? where pid=?"; Object[] params = { person.getName(), person.getAge(), new java.sql.Date(person.getBirthday().getTime()), person.getPid()}; qr.update(sql, params); }
public void delete(String pid) throws SQLException { String sql = "delete from t_person where pid=?"; qr.update(sql, pid); }
public Person load(String pid) throws SQLException { String sql = "select * from t_person where pid=?"; return qr.query(sql, new BeanHandler<Person>(Person.class), pid); }
public List<Person> findAll() throws SQLException { String sql = "select * from t_person"; return qr.query(sql, new BeanListHandler<Person>(Person.class)); } } |
PersonDaoTest.java
public class PersonDaoTest { @Test public void testAdd() throws SQLException { Person p1 = new Person(CommonUtils.uuid(), "张三", 18, new Date()); Person p2 = new Person(CommonUtils.uuid(), "李四", 81, new Date()); Person p3 = new Person(CommonUtils.uuid(), "王五", 66, new Date());
PersonDao dao = new PersonDao(); dao.add(p1); dao.add(p2); dao.add(p3); }
@Test public void testEdit() throws SQLException { PersonDao dao = new PersonDao(); Person person = dao.load("2F371BE415984DE89781CCCA7B8734CB"); person.setAge(88); dao.edit(person); }
@Test public void testDelete() throws SQLException { PersonDao dao = new PersonDao(); dao.delete("2F371BE415984DE89781CCCA7B8734CB"); }
@Test public void testFindAll() throws SQLException { PersonDao dao = new PersonDao(); List<Person> list = dao.findAll(); System.out.println(list); } } |
4 MailUtils
MailUtils是用来发邮件的小工具,底层使用JavaMail完成,所以它这件事mail.jar和activaion.jar。
MailUtilsTest.java
/** * 测试发送普通邮件 * @throws IOException * @throws MessagingException */ @Test public void fun() throws MessagingException, IOException { Session session = MailUtils.createSession("smtp.163.com", "itcast_cxf", "itcastitcast");[q1] Mail mail = new Mail("itcast_cxf@163.com", "itcast_cxf@126.com", "测试MailUtils", "这是正文!");[q2] MailUtils.send(session, mail);[q3] } |
5 BaseServlet
BaseServlet是用来作为其它Servlet父类的,它有如下两个优点:
一个Servlet多个处理方法
BaseServlet的作用是用来简化Servlet。通过我们需要为每个功能编写一个Servlet,例如用户注册写一个RegistServlet,用户登录写一个LoginServlet。如果使用BaseServlet,那么我们可以只写一个UserServlet,然后让UserServlet去继承BaseServlet,然后在UserServlet给出两个请求处理方法,一个方法叫regist(),一个叫login()。
BaseServlet来简化了Servlet中请求转发和重定向的代码。
简化了请求转发和重定向的代码
BaseServlet中的请求处理方法有一个String类型的返回值,返回值表示转发或重定向的目标页面。例如:
l f:/index.jsp:其中f:表示转发,即forward的意思,/index.jsp表示转发到/index.jsp页面;
l r:/index.jsp:其中r:表示重定向,即redirect的意思,/index.jsp表示重定向到/index.jsp页面。
l null:表示不转发也不重定向;
因为BaseServlet中可以有多个请求处理方法,所以在访问BaseServlet时一定要给出名为method的参数来指定要请求的方法名称。
AServlet.java
public class AServlet extends BaseServlet { /** * 请求处理方法的参数都与doGet()和doPost()相同,即request和response * 但请求处理方法有String类型的返回值,而doGet()和doPost()没有返回值。 * 在请求本方法时需要给出method=regist参数! */ public String regist[q4] (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet regist()..."); return "f:/index.jsp";[q5] }
/** * 在请求本方法时需要给出method=login参数! */ public String login[q6] (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet login()..."); return "r:/index.jsp"[q7] ; } } |
6 EncodingFilter
EncodingFilter用来处理请求编码问题。
我们知道,如果是POST请求,我们需要调用request.setCharacterEncoding(“utf-8”)方法来设计编码;如果是GET请求,我们需要自己手动来处理编码问题。如果我们使用了EncodingFilter,那么就处理了POST和GET请求的编码问题。
web.xml
<filter> <filter-name>EncdoingFilter</filter-name> <filter-class>cn.itcast.filter.EncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>EncdoingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
index.jsp
<a href="<c:url value='/EncodingServlet?method=test[q8] &name=张三'/>">点击这里发出GET请求</a><br/> <form action="<c:url value='/EncodingServlet'/>" method="post"> <input type="hidden" name="method" value="test"/>[q9] <input type="text" name="name" value="李四"/> <input type="submit" value="请求这里发出POST请求"/> </form> |
EncodingServlet
/** * 测试EncodingFilter * @author qdmmy6 * */ public class EncodingServlet [q10] extends BaseServlet { /** * 可以使用POST和GET两种方式请求test()方法!查看输出是否为乱码! */ public String test(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String name = request.getParameter("name"); System.out.println(name); return null; } } |
7 VerifyCodeServlet(一次性验证码)
通过在表单中总是需要使用一次性验证码,这一问题可以使用VerifyCodeServlet来处理。让<img>元素的src指向VerifyCodeServlet即可在页面中生成一次性验证码。而且VerifyCodeServlet还会把验证码保存到session中,名称为:vCode,也就是说,你可以通过session来获取验证码文本:session.getAttribute(“vCode”)。
web.xml
<servlet> <servlet-name>VerifyCodeServlet</servlet-name> <servlet-class>cn.itcast.vcode.servlet.VerifyCodeServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>VerifyCodeServlet</servlet-name> <url-pattern>/VerifyCodeServlet</url-pattern> </servlet-mapping> |
MyJsp.jsp
<form action="<c:url value='/UserServlet'/>" method="post"> <input type="hidden" name="method" value="regist"/> 验证码:<input type="text" name="verifyCode"/> <img src="<c:url value='/VerifyCodeServlet'/>"[q11] border="1"/><br/> <input type="submit" value="注册"/> </form> |
因为用户可能看不清楚图片上的文本,所以我们需要给用户提供一个“换一张”超链接。其实实现这一步很简单,只需要使用javascript让<img>元素src指向VerifyCodeServlet即可。但因为浏览器可能会缓存上一次生成的图片,所以我们还需要使用时间为参数“强迫”浏览器访问服务器,而不是使用缓存。
MyJsp.jsp
<script type="text/javascript" src="<c:url value='/js/jquery-1.5.1.js'/>"></script>[q12] <script type="text/javascript"> function change[q13] () { $("#img").attr("src", "<c:url value='/VerifyCodeServlet?'/>" + new Date().getTime());[q14] } </script> … <form action="<c:url value='/UserServlet'/>" method="post"> <input type="hidden" name="method" value="regist"/> 验证码:<input type="text" name="verifyCode"/> <img id="img"[q15] src="<c:url value='/VerifyCodeServlet'/>" border="1"/> <a href="javascript:change();">换一张</a>[q16] <br/> <input type="submit" value="注册"/> </form> |
当用户在表单中填写了验证码,而且提交了表单,到达UserServlet的regist()方法,在regist() 方法中需要比较用户在表单中输入的验证码,与验证码图片上的文本是否相同。
l 获取用户输入的验证码:request.getParameter(“verifyCode”);
l 获取图片上的验证码:session.getAttribute(“vCode”);
[q1]创建session
[q2]创建邮箱对象,参数分别为:发件人、收件人、主题、正文
[q3]发送邮件
[q4]访问本方法的URL为http://localhost:8080/day01/AServlet?method=regist
[q5]转发到/index.jsp页面
[q6]访问本方法的URL为http://localhost:8080/day01/AServlet?method=login
[q7]重定向到/index.jsp
[q8]请求EncdoingServlet的test方法
[q9]请求EncodingServlet的test方法
[q10]因为添加了EncodingFilter过滤器,那么所有的Servlet都不用再去处理请求编码的问题了。
[q11]让<img>的src指向VerifyCodeServlet即可生成一次性验证码
[q12]导入jquery
[q13]在点击“换一张”时会调用本方法
[q14]指定<img>元素的src属性值为VerifyCodeServlet,并且追加参数为当前时间毫秒,它是不会重复的值,所以浏览器不会使用缓存,而是访问服务器。
[q15]指定id为img,方法使用jquery来查找该元素。
[q16]点击该超链接会调用change()方法