01-1项目所需小工具
小工具
工欲善其事,必先利其器。下面我们来介绍一下在项目中要使用的小工具(itcast-tools-1.4.jar)。这个小工具底层使用了:
小工具jar包的使用
l c3p0数据库连接池;
l common-beanutils;
l common-dbutils;
l javaMail;
1 CommonUtils 之CommonUtils(1生成uuid,2Map转换成JavaBean)
字面意思 common 共有的 普通的 工具包
问题如何普通 普通在哪里?
第一个工具类的使用?该类的作用是什么? 该类使用需要导入jar包吗?
1.1导入jar包使用之前 需要导入 原始的jar包
和该包依赖的两个jar 包
通过项目的buidpath导入项目需要的jar包
Itcast-tools-1.4.jar包
2.工具包中方法的使用
CommonUtils类就两个方法:
两个方法都是静态方法 将包导入后 直接类点 方法
l String uuid():生成长度32的随机字符,通常用来做实体类的ID。底层使用了UUID类完成; 该方法 返回值 32位的随机字符 该方法的作用 数据库表中的主键
n 该方法还能做什么? 作为 激活码使用 他永远不会重复
l T toBean(Map, Class<T>):
主要了解该方法怎么用?
把Map转换成指定类型的Bean对象。通常用来获取表单数据(request.getParameterMap())封装到JavaBean中,底层使用了common-beanutils。注意,本方法要求map中键的名称要与Bean的属性名称相同才能完成映射,否则不能完成映射。
/** * 随机生成32位长的字符串,通常用来做实体类的ID */ @Test 测试类 不用main方法直接运行 public void testUuid() { String s = CommonUtils.uuid();//生成随机32位长的字符串 System.out.println(s); }
/**该方法的作用是: * 把Map类型 数据 映射成Bean类型。 javabean中 * 要求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); } |
一个map映射对象可以吗? 一个map包含了两个javabean的数据,用这个map分别生成这两个javabean
2 JdbcUtils 4.项目所需小工具之JdbcUtils(1获取Connection,2事务管理)
2.1 jadbUtils是用的用途? 需要jar 包吗? jar包中有哪里类 和类中的方法使用?
简化对jdbc链接数据库驱动的操作 JdbcUtils用来获取Connection
导入三个jar包
底层使用了c3p0连接池!两个
* * 还需要mysql驱动 一个
2.2 工具包中的主要方法
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();//提交事务 } } |
/**
* 1.JdbcUtils用来获取Connection
* * 底层使用了c3p0连接池!
* * 还需要mysql驱动
* @author qdmmy6
*
*/
public class JdbcUtilsTest {
/**
* 底层使用了c3p0连接池,说明我们还要提供c3p0配置文件
* @throws SQLException
*/
@Test
public void testGetConnection() throws SQLException {
Connection con = JdbcUtils.getConnection();
System.out.println(con);;
JdbcUtils.releaseConnection(con);
System.out.println(con.isClosed());
}
/**
*2. JdbcUtilst还提供了与事务相关的功能
*
*/
@Test
public void testTransaction() {
try { //事物 需要 try catch
JdbcUtils.beginTransaction();//开启事务
// 多次操作
JdbcUtils.commitTransaction();//提交事务
} catch(Exception e) {
try {//出了异常回滚事务
JdbcUtils.rollbackTransaction();//回滚事务
} catch (SQLException e1) {
}
}
}
3 TxQueryRunner 5.项目所需小工具之TxQueryRunner(把JdbcUtils和dbUtils整合在一起)
导入包
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); } } |
讲课源码
/**
* TxQueryRunner它是QueryRunner的子类!(commons-dbutils.jar) 方法都封装好了 直接用就行 原理 做完项目的时候在学
* 可用起来与QueryRunner相似的!
* 我们的类支持事务!它底层使用了JdbcUtils来获取连接!
*
* 简化jdbc的操作
* QueryRunner的三个方法:
* * update() --> insert、update、delete
* * query() --> select
* * batch() --> 批处理
* @author qdmmy6
*
*/
public class TxQueryRunnerTest {
/** * 测试update()方法,用来执行insert、update、delete语句
* @throws SQLException
*/
@Test update()执行数据的插入操作
public void testUpdate() throws SQLException {
String sql = "insert into t_person(pid,pname,age,sex) values(?,?,?,?)";
Object[] params = {"1", "p1", 1, "男"};//给sql中对应的参数
QueryRunner qr = new TxQueryRunner();//我们没有给对象提供连接池
qr.update(sql, params);//执行sql,也不提供连接,它内部会使用JdbcUtils来获取连接
}
成功插入
/**
* 使用事务 连续插入两条数据 第一条插入成功第二天没成功 回滚
保证数据一定插入成功 否则报错
* @throws SQLException
*/
@Test
public void testUpdate2() throws Exception {
try {
JdbcUtils.beginTransaction();//开启事务
String sql = "insert into t_person(pid,pname,age,sex) values(?,?,?,?)";
QueryRunner qr = new TxQueryRunner();
Object[] params = {"2", "p2", 2, "女"};
qr.update(sql, params);//执行
if(false) {
throw new Exception();
}
params = new Object[]{"3", "p3", 3, "女"};
qr.update(sql, params);//执行
JdbcUtils.commitTransaction();//提交事务
} catch(Exception e) {
try {
JdbcUtils.rollbackTransaction();//回滚事务
} catch (SQLException e1) {
}
throw e;
}
}
/**
* 测试查询方法
* 我们知道JDBC查询的结果的是ResultSet
* 而QueryRunner查询的结果是通过ResultSet映射后的数据。
* * QueryRunner第一步是执行select,得到ResultSet
* * 把ResultSet转换成其他类型的!
* 通过转换结果:
* * javaBean:把结果集封装到javaBean中
* * Map:把结果集封装到Map中
* * 把结果集封装到Object中(结果集是单行单列)
* @throws SQLException
*
*
*/
/*
* 单行结果集映射到javaBean中
*/
@Test
public void testQuery1() throws SQLException {
String sql = "select * from t_person where pid=?";
QueryRunner qr = new TxQueryRunner();
/*
* 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。
*
* BeanHandler --> 它是ResultSetHandler的实现类,它的作用是把结果集封装到Person对象中
*/
Person p = qr.query(sql, new BeanHandler<Person>(Person.class), "1");
System.out.println(p);
}
/**
* 使用BeanListHandler
* 把多行结果集映射到List<Bean>,即多个JavaBean对象。
* 一行结果集记录对应一个javaBean对象,多行就对应List<Bean> list集合
* @throws SQLException
*/
@Test
public void testQuery2() throws SQLException {
String sql = "select * from t_person";
QueryRunner qr = new TxQueryRunner();
/*
* 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。
*
* BeanListHandler --> 它是ResultSetHandler的实现类,
* 它的作用是把结果集封装到List<Person>对象中
*/
List<Person> list = qr.query(sql, new BeanListHandler<Person>(Person.class));
System.out.println(list);
}
/**
* 使用MapHandler,把单行结果集封装到Map对象中
* @throws SQLException
*/
@Test
public void testQuery3() throws SQLException {
String sql = "select * from t_person where pid=?";
QueryRunner qr = new TxQueryRunner();
/*
* 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。
*
* BeanListHandler --> 它是ResultSetHandler的实现类,
* 它的作用是把结果集封装到List<Person>对象中
*/
Map<String, Object> map = qr.query(sql, new MapHandler(), "1");
System.out.println(map);
}
/**
* 使用MapListHandler,把多行结果集封装到List<Map>中,即多个Map
* 一行对应一个Map,多行对应List<Map>
* @throws SQLException
*/
@Test
public void testQuery4() throws SQLException {
String sql = "select * from t_person";
QueryRunner qr = new TxQueryRunner();
/*
* 第二个参数类型为ResultSetHandler,它是一个接口,表示映射的结果类型。
*
* BeanListHandler --> 它是ResultSetHandler的实现类,
* 它的作用是把结果集封装到List<Person>对象中
*/
List<Map<String, Object>> mapList = qr.query(sql, new MapListHandler());
System.out.println(mapList);
}
/**
* 使用ScalarHandler,把单行单列的结果集封装到Object中
* @throws SQLException
*/
@Test
public void testQuery5() throws SQLException {
String sql = "select count(*) from t _person";//结果集是单行单列的
QueryRunner qr = new TxQueryRunner();
Object obj = qr.query(sql, new ScalarHandler());
/*
* 我们知道select count(1),结果一定是个整数!
* > Integer
* > Long
* > BigInteger
*
* 不同的驱动,结果不同!
* 无论是哪种类型,它都是Number类型!强转成Number一定不出错
*/
Number number = (Number)obj;
long cnt = number.longValue();
System.out.println(cnt); //输出结果是个数字
}
/**
* 一行结果集中包含了两张表的列
两张表从属关系 , person是从表 address是主表
一行结果集 对应两个对象
1.构建一个AddressBean对象 和person 对象
当写表和实体类之间映射的时候,一旦出现外键的时候不能写外键,通过外键找到类型写出来
* 使用MapHandler来处理
处理的过程:
* 1. 把结果集封装到map中
* 2. 使用map生成Person对象
* 3. 使用map生成address对象
* 4. 把两个实体对象建立关系
* @throws SQLException
*/
@Test
public void testQuery6() throws SQLException {
String sql = "SELECT * FROM t_person p, t_address a WHERE p.aid=a.aid AND p.pid=?";
QueryRunner qr = new TxQueryRunner();
/*
* 1. 得到Map
*/
Map map = qr.query(sql, new MapHandler(), "aaa");
/*
* 2. 把Map中部分数据封装到Person中
*/
Person p = CommonUtils.toBean(map, Person.class);
/*
* 3. 把Map中部分数据封装到Address中
*/
Address addr = CommonUtils.toBean(map, Address.class);
/*
* 4. 建立两个实体的关系
*/
p.setAddress(addr);
System.out.println(p);
}
person类
public class Person {
private String pid;
private String pname;
private int age;
private String sex;
private Address address;
address类
public class Address {
private String aid;//主键
private String province;//省
private String city;//市
private String district;//区
private String street;//街道
源码部分
/**
* 一行结果集中包含了两张表的列
* 使用MapHandler来处理
* 1. 把结果集封装到map中
* 2. 使用map生成Person对象
* 3. 使用map生成address对象
* 4. 把两个实体对象建立关系
* @throws SQLException
*/
@Test
public void testQuery6() throws SQLException {
String sql = "SELECT * FROM t_person p, t_address a WHERE p.aid=a.aid AND p.pid=?";
QueryRunner qr = new TxQueryRunner();
/*
* 1. 得到Map
*/
Map map = qr.query(sql, new MapHandler(), "aaa");
/*
* 2. 把Map中部分数据封装到Person中
*/
Person p = CommonUtils.toBean(map, Person.class);
/*
* 3. 把Map中部分数据封装到Address中
*/
Address addr = CommonUtils.toBean(map, Address.class);
/*
* 4. 建立两个实体的关系
*/
p.setAddress(addr);
System.out.println(p);
}
4 MailUtils
MailUtils是用来发邮件的小工具,底层使用JavaMail完成,所以它这件事mail.jar和activaion.jar。 导入两个包
源码 主要用来激活 用户注册的时候 给邮箱发送一个激活邮件
/**
* 测试MailUtils,作用是发邮件,不收邮件
* 底层依赖的是javamail:mail.jar、activation.jar
* @author qdmmy6
*
*/
public class MailUtilsTest {
/**
* 发邮件
* @throws IOException
* @throws MessagingException
*/
@Test
public void send() throws MessagingException, IOException {
/*
发送邮件的步骤
* 1. 登录邮件服务器
* MailUtils.createSession(服务器地址, 登录名, 密码); 返回一个session对象
* 2. 创建邮件对象
* 发件人
* 收件人
* 主题
* 正文
* 3. 发
* 需要第一步得到的session、和第二步的邮件对象
*/
javaxmail下的session
smtp.163.com smtp指的是邮件协议
Session session = MailUtils.createSession(".163.com", "itcast_cxf", "itcastitcast");
后期吧信息放在配置文件中 放在代码中 是不安全的
点击这里完成激活
不建议使用带有邮箱验证的邮箱发送 ruqq
Mail mail = new Mail("itcast_cxf@163.com", "itcast_cxf@126.com", "测试邮件一封", "<a href='http://www.baidu.com'>百度</a>");
MailUtils.send(session, mail);
}
}
MailUtilsTest.java
/** * 测试发送普通邮件 * @throws IOException * @throws MessagingException */ @Test public void fun() throws MessagingException, IOException { Session session = MailUtils.createSession("smtp.163.com", "itcast_cxf", "itcastitcast"); Mail mail = new Mail("itcast_cxf@163.com", "itcast_cxf@126.com", "测试MailUtils", "这是正文!"); MailUtils.send(session, mail); } |
log4j的配置 只提示警告以上的信息 和只打印给控制台
f1信息隐去
5 BaseServlet
导入包了已经 copy以上所有的jar包
BaseServlet是用来作为其它Servlet父类的,它有如下两个优点:
一个Servlet多个处理方法
BaseServlet的作用是用来简化Servlet。通过我们需要为每个功能编写一个Servlet,例如用户注册写一个RegistServlet,用户登录写一个LoginServlet。如果使用BaseServlet,那么我们可以只写一个UserServlet,然后让UserServlet去继承BaseServlet,然后在UserServlet给出两个请求处理方法,一个方法叫regist(),一个叫login()。
BaseServlet来简化了Servlet中请求转发和重定向的代码。
自己写的包
源码
package cn.itcast.test.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.itcast.servlet.BaseServlet;
/**
* 一般Servlet都是只有一个请求处理方法
* 登录:一个LoginServlet
* 注册:一个RegistServlet
* 修改密码:...
*
* 我们需要一个Servlet有多个请求处理方法
* login()
* regist()
* updatePassword()
*
* 让你的Servlet去继承BaseServlet
*
* -----------
*
* BaseServlet:
* 1. 可以有多个请求处理方法
* 2. 简化了转发和重定向的代码
*
* 请求处理方法格式:
* pubilc String regist(HttpServletRequest request, HttpServletResponse response)
* throws ServletException, IOException {
* }
*
* 请求BaseServlet中的某个方法:
* http://localhost:8080/tools/AServlet?method=regist 原来地址的基础上加上一个method=方法名
* http://localhost:8080/tools/AServlet?method=login
* @author qdmmy6
*
*/
public class AServlet extends BaseServlet {
public String regist(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//2. 简化了转发和重定向的代码 重定向到本网站的页面
System.out.println("regist()..."); return 返回值i
return "/index.jsp";//表示转发到index.jsp
// return "f:/index.jsp";//f前缀表示forward,即转发
// return "r:/index.jsp";//r前缀表示redirect,即重定向
// return null;//不转发,也不重定向
// return "";//不转发,也不重定向
// 想重定向到百度,return null,自己去重定向!百度不是项目中的页面
}
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("login()...");
return "r:/index.jsp";
}
}
简化了请求转发和重定向的代码
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(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet regist()..."); return "f:/index.jsp"; }
/** * 在请求本方法时需要给出method=login参数! */ public String login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("AServlet login()..."); return "r:/index.jsp"; } } |
5.5项目设置自动的热加载 修改完servlet后不用重启tomcat
tomcat conf---context.xml修改配置 reloadable="ture" 等一会 如果有缓存还是要重启的
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&name=张三'/>">点击这里发出GET请求</a><br/> <form action="<c:url value='/EncodingServlet'/>" method="post"> <input type="hidden" name="method" value="test"/> <input type="text" name="name" value="李四"/> <input type="submit" value="请求这里发出POST请求"/> </form> |
EncodingServlet
/** * 测试EncodingFilter * @author qdmmy6 * */ public class EncodingServlet 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; } } |
源码 在web.xml中进行filter的配置
<!-- 处理全站请求编码,无论是GET还是POST,默认是UTF-8 -->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.itcast.filter.EncodingFilter</filter-class> //包地址
<init-param> //初始化参数 设置 字符集可以是gbk
<param-name>charset</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern> //全过滤
</filter-mapping>
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'/>" 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> <script type="text/javascript"> function change() { $("#img").attr("src", "<c:url value='/VerifyCodeServlet?'/>" + new Date().getTime()); } </script> … <form action="<c:url value='/UserServlet'/>" method="post"> <input type="hidden" name="method" value="regist"/> 验证码:<input type="text" name="verifyCode"/> <img id="img" src="<c:url value='/VerifyCodeServlet'/>" border="1"/> <a href="javascript:change();">换一张</a> <br/> <input type="submit" value="注册"/> </form> |
当用户在表单中填写了验证码,而且提交了表单,到达UserServlet的regist()方法,在regist() 方法中需要比较用户在表单中输入的验证码,与验证码图片上的文本是否相同。
l 获取用户输入的验证码:request.getParameter(“verifyCode”);
l 获取图片上的验证码:session.getAttribute(“vCode”);
1.写一个页面 普通的注册页面 用户名 密码和验证框
测试页面
想办法弄出验证码
2.让图片显示出来
web中配置已经写好的Servlet 先配置文件中配置 使用的工具包中的VerifyCodeServlet
<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>
通过javascript实现张图片的点击换一张
<script type="text/javascript">
function _hyz() {
/*
1. 获取<img>元素
2. 给它的src指向为/tools/VerifyCodeServlet
*/
var img = document.getElementById("imgVerifyCode");
// 需要给出一个参数,这个参数每次都不同,这样才能干掉浏览器缓存!
img.src = "${pageContext.requet.contextPath} /VerifyCodeServlet?a=" + new Date().getTime();
}
</script>
</head>
<body>
<%--
1. 写表单,其中包含图片(验证码)
2. 让图片显示出来:
把<img>的src指向VerifyCodeServlet,你需要在web.xml中部署VerfiyCodeServlet
3. 换一张
--%>
<form action="/tools/LoginServlet" method="post">
<%-- 添加一个参数:method=login --%>
<input type="hidden" name="method" value="login">
用户名:<input type="text" name="name"/><br/>
密 码:<input type="password" name="pwd"/><br/>
验证码:<input type="text" name="verifyCode"/><br/>
<img src="/tools/VerifyCodeServlet" id="imgVerifyCode"/>
<a href="javascript:_hyz()">换一张</a>
<br/>
<input type="submit" value="提交"/>
</form>
Ie缓存的原因 同一个路径 第二次访问 不直接从缓存中取值 没有从服务器中取值
表单的验证
表单传参数 访问自定义的Servlet
${pageContext.request.contextPath} 获取项目名,通过el标签
*/
public class AServlet extends BaseServlet {
public String regist(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("regist()...");
return "/index.jsp";//表示转发到index.jsp
// return "f:/index.jsp";//f前缀表示forward,即转发
// return "r:/index.jsp";//r前缀表示redirect,即重定向
// return null;//不转发,也不重定向
// return "";//不转发,也不重定向
// 想重定向到百度,return null,自己去重定向!
}
public String login(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("login()...");
return "r:/index.jsp";
}
总结这个BaseServlet 很鸡助 可以不使用
}
将AServlet注册 到web中 在高版本中通过注解来使用Servlet
<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>文件加.类名</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>