MainServlet.findCost()
,我们在这个类当中加一个findCost方法,专门处理查询类的请求,可以吧,就这么干啊,那么它在处理请求时,数据来源于这个表,我们得访问这个表,对吧,得查询,那你要查询的话,你看我们是怎么查,写点什么,你是不是得写个dao,是不是啊,写个dao,一般什么表我们习惯就叫什么dao,是吧,我们就叫CostDao。findAll()
,查询全部的,可以吧,CostDao.findAll()
,这个方法,那这个方法,它需要能够访问cost这个表,从表中能够得到数据,然后呢,Servlet可以调这个CostDao,dao可以给Servlet返回这个findAll()查询到的数据,是这意思吧。那么返回的数据叫什么名字比较好,这个返回的数据,咱们是不是得取个名字啥的,一般就是返回的是这个,返回的是我们用实体类封装一下,实体类可以叫Cost,是这样吧,那么它有几个,返回几条数据呢,一个,还是多个呢,多个,怎么体现多个呢,集合可以吧,返回一个集合啊,List
,封装多条数据,这样。这还不够啊,我们调dao,dao这回咱们真的要访问数据库,不像以前模拟了,明白吧,这回真的是要动真格的了啊,要玩真的了,要玩真的话,你要访问数据库,还得写个啥呢,你是不是还得写个啥,之前咱还说了,写一个DBUtil,用来建立连接对吧,得有这工具,要不然不方便啊。db.properties
,这个我也把它画一下吧,我们还需要呢,调用一个文件,叫db.properties
,这是参数,配置文件啊,连接参数,还有连接池参数。那dao可以调用DBUtil得到连接对吧,DBUtil要读取db.properties
,是这样吧,就这样干。然后再看,那最终呢,我们在这里得到了数据以后,要给浏览器返回,怎么返回,怎么办呢,你是不是得写一个jsp,是这样吧,得写个jsp啊。那因为呢,我们是开发一个正式的项目,我们一定是遵守MVC模式是吧,那MVC模式呢,一定是Servlet处理请求,然后呢,它将结果给jsp展现对吧,相互配合,那么jsp啊,以前我们是把它直接放到了webapp之下,对吧,但其实呢,我们正式项目里,不是放到呢webapp之下,正式项目里通常是放到,这个神秘的目录之下/WEB-INF
,放这里来啊,这个东西很神秘,我没解释呢,那为什么要放这里来,它有哪些神秘之处,我们后面再讲,等这个功能做完以后再讲,明白吧,别着急,反正先放进去啊。/WEB-INF
这里来,最好是一个模块建个目录是吧,分开,是这样吧,你看美工做的静态网页不是分开了么,对吧,分开,别放到一块去,太乱啊,那对于这个资费模块,我们建一个目录叫cost,查询页面,我叫find.jsp
,行吧,即/WEB-INF/cost/find.jsp
,可以吧,能看出这个文件的,属于某个模块,什么意思对吧,很直观了,就这样,然后呢,Servlet把得到的数据,转发给它find.jsp,由find.jsp向浏览器做出响应,那我们这个项目,这个功能啊,它的完整的,这个过程就是这样,它只有一个请求,过程就是这样。那就是一开始呢,就是我们可能是,没有讲这么全,我们的脑海里呢,出现的一些离散的,发散的,一些个东西,比如说有的人想到了实体类,有的人想到了dao,有的人想到了DBUtil,对吧,都想到了某一部分,没有想全,但是呢,我们通过了这个图形的串接,能够把它们呢,都串接起来,因为我们需要这些内容,串接好以后,这些内容摆这,我们还要最好呢,给出一个合理的开发的顺序,那你想,我们先开发谁后开发谁比较,合适啊。2.List
,3.CostDao.findAll()
,4.MainServlet.findCost()
,5./WEB-INF/cost/find.jsp
,这样的步骤明白么,因为这些内容,我们工作时要常写,我就需要把它们练熟啊。db.properties
,有这个工具类DBUtil.java
,对吧,咱们一个一个copy啊,别着急,我们先把这个db.properties
,copy到我们这个项目中来,放到也是这个目录下,src/main/resources/
,一定不要放错位置,copy过来啊,看一下。然后呢,还要copy那个工具类,那copy工具类之前呢,我们最好把那个,没关系,我们把这个包先建好吧,要不然没有包对吧,我们在netctoss/src/main/java
下,先建几个包,有util包,有实体类entity的包,有这个dao,还有web,先准备好,看一下建几个包。那包都建好了,建好以后,我们从jdbc的项目中,把那个DBUtil类,copy到这个util包下,copy过来看看,就是复制粘贴,但是你注意,你放的位置一定要放对了,因为这个部署的时候,有的代码会被丢弃,你要放错位置的话,不小心整没了,麻烦了啊,一定要严谨,这个程序员呢,最重要的一个品质就是要严谨,但我看很多人这个不够严谨,你还得练啊,还得注意啊。try-catch
,那么写完以后呢,大家把这个main方法执行一下,看一下输出结果,我执行一下,没报错,没问题,就这样了。那下面呢,我们按部就班的去开发啊,第2步,写这个实体类,那实体类用来存数据对吧,然后呢,它是一个典型的javaBean,我们要满足javaBean规范,那表里呢,10字段,实体类呢,要与之对应,有10个属性。那下面呢,在这个项目之内,在entity包之下,创建一个实体类,这个类呢,和表同名,就叫Cost,要实现呢,序列化接口,那表里有10个字段,类中有10属性,我先把这10个属性写出来,然后呢,每个属性是什么意思,我再补充注释,再加以解释,咱们先把属性写出来,
private Integer costId;
private String name;
private Integer baseDuration;
private Double baseCost;
private Double unitCost;
private String status;
private String descr;
private Timestamp creatime;
private Timestamp startime;
private String costType;
一共呢,10个属性,那现在我把每一个属性的意思解释一下啊,这个第一个costId,是这个表的组件,没什么好说的,组件,第二个呢,name是,这是资费表,name呢,是资费名,比如说60元套餐,是这个名字,80元套餐是名字,比如说计时是名字,总之啊,这是资费的名称,然后呢,下面这3个字段,baseDuration,baseCost和unitCost,属性,是这个资费相关的数据,那么,这个叫baseDuration,是基本时长,如果呢,用户选择资费是,这个套餐的话,那这个套餐,它默认有多少小时可用,比如说我们这手机号,你选择套餐,默认你能打多少分钟电话,就这个意思,或者说,默认你带多少流量,基本时长,写一下啊,基本时长。
然后呢,baseCost,这个是基本费用,这个基本费用指的是什么呢,比如说,我选了一个套餐,这个套餐呢,默认多少钱,比如说我这个手机号,我选了个,比如说,168的套餐,那基本的费用就是168,就这个意思啊,那这个基本的费用,是金额,是小数,基本时长一般都是整数,多少分钟,多少小时明白吧,没有谁还卖半分钟的,没有那样的,是整数;然后呢,这个是unitCost,这是单位费用,那什么叫单位费用,那你选了个套餐的话,你这个套餐有可能会用超,对吧,是吧,套餐超了以后,那每一分钟多少钱,那是这个意思,单位费用,也是小数,因为是金额,那么我们呢,所用的这个数据的类型啊,你会发现,都是封装类型,之前我说过,我们为什么都用封装类型呢,为什么呢,因为啊,封装类型,它可以为none,是这样吧,是吧,如果是基本类型,它不允许为none,是吧,是这样的,那这个数据有没有可能为none呢,有可能,如果我选的是包月,有这个单位费用么,没有,包月没有超出的可能,没有单位费用,对吧,也没有基本时长,不限时长,是这意思吧,所以呢,这些数据是可能为空的,数据库里也允许为空,所以这块呢,我们用这个封装类型,是比较合理的啊 。
再看啊,下一个呢,是status,这个单词是状态的意思,这个我们选的这个资费,它有状态,比如说呢,今年,我们新推出了一个套餐,非常划算,比如校园套餐,很优惠,那可能明年没有了,禁用了对吧,后年又开启,又可用了,所以这个资费,它有状态,可以切换,这个状态呢,只有两种,那么像着这种这种状态,这种字段,我们在存的时候,一般啊,不是存这个中文,不是说存这个启用,禁用,存汉字,不是,我们存的是什么呢,0,1,2,3,4,或者是呢,这个字母,比如说,M啊,F啊,这样的。那为什么这样呢,就是说,如果说我们数据库啊,存的是几个选项,如果存的是选项的话,这个叫枚举项,一般我们习惯叫枚举,就是可列举,这写一下啊,像这种呢,可以列举的字段,我们叫枚举,枚举类型通常存的是整数,或者是char,习惯于这样。那我们表里呢,这个字段存的是char,那存了什么呢,0和1啊,0代表启用,然后呢,1代表禁用,项目页面的状态叫开通暂停啊,其实和启用禁用差不多,我就稍微修一下啊,这个最终显示的是,0-开通
,1-暂停
啊。
然后呢,咱们数据库字段呢,是char,那我用的java类型呢,是String,当然我可以用char,那我为啥用String呢,我怕将来呢,万一有一天呢,这个状态太多了,这个char存不下了,明白吧,就用字符串了,那我这个String的话,你给我个char也可以对吧,它比较兼容啊,所以呢,咱们这个,写实体类的时候啊,一般都要考虑兼容性,你像之前,这个封装类型,能兼容none啊,字符串也可以兼容char,所以说,主要是从这个角度来考虑,最好是我们写过这个类以后啊,将来呢,一旦是字段发生变化,我这类不用动,因为类一动的话,咱们调它的代码,就也得动啊,最好别动。然后呢,下一个是descr,是description那个描述单词的缩写,就是对这个资费的说明,或者说描述吧,资费说明吧。
然后呢,是creatime,创建时间啊,那我们要在jdbc当中使用时间的话,时间以前说过( JDBC对日期时间的处理 ),咱们用什么类型了,用的是哪个包下的类型啊,java.sql对吧,所以我用的是java.sql.Timestamp
,时间戳,这个包名别引错了,引错会有问题,然后呢,字段名,它就叫creatime,它把create和time拼在一起,并缩写掉了一个t,只有一个t啊,这主意,creatime去掉了一个t,这是,这一个数据呢,创建的时间啊,然后呢,后面是,开通时间啊,就是说,咱们这个数据啊,有这个状态,状态呢,是开通暂停,那我们在这个页面上,可以通过启用,禁用这样的按钮,去调整这个状态,可以修改这个状态啊,那么当你修改状态时,你把数据开通了,你要给出开通时间,是资费这条数据被开通的那个时间,做一条记录,这个叫startime,也是把t拼掉了一个,这要注意,也是java.sql包下的这个日期啊。
最后呢,还有一个字段叫costType,那你注意,这个建表这个人啊,他的规则不统一啊,你像这样的单词,creatime和startime,俩t缩掉一个对吧,costType,他没缩掉,它就直接两个单词拼到一起了,所以说这个有点不太统一,不过,他既然这么写,我们就跟着,就这样写吧,那这什么意思呢,就是cost是费用的意思,是资费的意思,type是类型,这是资费类型,也是一种枚举的数据。那么因为呢,它是枚举类型,咱们数据库里存的呢,还是char啊,那它存了什么呢,存了也是数字啊,1,2,3 啊,那代表什么意思呢,1代表包月,2代表套餐,3代表计时,3个选项。那么10个字段,咱们分别呢,进行了一个解释,大家了解一下,然后呢,写完这个解释以后吧,我们需要生产get/set啊,大家生成get/set方法。
那这个实体类呢,咱们就写完了,就这样,这个没啥难度啊 ,反正你就注意,我们写实体类的几个原则啊,第一个,它要满足javaBean规范,这是第一个;第二个,实体类当中的类型,我们尽量采用封装类型,因为封装类型支持none,基本类型不支持none,而很多数据是允许为none的,那么我们不用去想,这个字段允不允许none,我是基本类型还是,封装类型呢,干脆都封装类型,咱们就无脑模式,这个意思啊。然后呢,我们咱实体类当中啊,所写的时间,要采用java.sql
这个包下的时间,然后,如果你是想记录完整的时间,用这个类型Timestamp,如果只想要日期,就用Date,如果只想要时间,就用time,我们这里要记录完整的,所以用Timestamp这个。那么实体类写完了,再看下一步,下一步呢,我们是可以写dao了,对吧,那在dao当中呢,我们要写查询,我们通过DBUtil创建连接,通过连接执行sql,对吧,再将sql返回的结果封装为实体类以及集合,返回就可以,就这么一个过程,那么这个过程呢,我们在jdbc的时候呢,说过的,所以到目前为止,我们所讲的内容,依然是在复习,它并不是什么新的内容。
public List findAll(){ return null; }
,这个方法呢,我们声明完了,声明完以后呢,加以实现。首先呢,第一步,创建连接,那么这个连接,最终是要关闭,对吧,无论是否报异常,我们都要尝试关闭它,然后呢,如果捕获到异常的时候,我们要对异常呢,进行处理,所以,创建连接啊,不是一句话,是一个套路,是一段话啊,写一下。public List findAll(){
Connection conn = null;
try {
conn = DBUtil.getConnection();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询资费失败",e);
}finally {
DBUtil.close(conn);
}
return null;
}
conn = DBUtil.getConnection();
,这句话,我们需要catch,如果捕获到异常,对于异常,我们处理不了,对吧,一般都处理不了,处理不了怎么办呢,抛出去,交给调用者处理,那调用者也处理不了怎么办呢,抛出去,交给上层调用者处理,如果谁都处理不了怎么办呢,最终,交给tomcat处理,那么tomcat有能力啊,处理所有异常,到时候呢,我们会演示,后面会演示,先别着急啊。然后呢,finally啊,最终无论如何,无论是否发生异常,一定要尝试关闭连接啊。那这个结构啊,无论是增删改查都一样,我们之前jdbc的时候呢,这段话写过无数遍对吧,现在又回顾了一下。String sql = "select * from cost "+"order by cost_id";
,我从表里呢,查出所有数据,然后呢,为了保证,这个数据呢,有序,我按照id呢,排下序,大家注意啊,你写sql时,用点心,别照我抄,因为表名,咱们不一样对吧,你写你自己的表名啊,如果抄错的话,一执行报错了,别赖我啊,我现在不怕你了啊,为啥呢,我那个数据库,连的是我本地的数据,你随便写啊,但是你访问不到你就别赖我了。那sql写完以后啊,要执行这个sql,那你看,我执行这个sql, 我是用Statement还是用preparedStatement,为什么呢,为啥用Statement呢,因为没有条件。ResultSet rs = smt.executeQuery(sql);
,那我们得到了结果集,结果集当中呢,封装了所有的数据,那对于结果集我们需要遍历对吧。List list = new ArrayList();
,循环之前呢,创建一个集合,整个循环完成以后,我们返回这个集合,return list;
,那你看啊,咱们在上面创建集合,在下面返回集合,那我们最后那句话,return null;
,还有用吗,没有了,把它删掉啊。public List findAll(){
Connection conn = null;
try {
conn = DBUtil.getConnection();
String sql = "select * from cost "+"order by cost_id";
Statement smt = conn.createStatement();
ResultSet rs = smt.executeQuery(sql);
List list = new ArrayList();
while(rs.next()) {
}
return list;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询资费失败",e);
}finally {
DBUtil.close(conn);
}
return null;//删掉
}
Cost c = new Cost();
,名字简单点,就叫c吧,然后呢,每次循环结束的那一刻,我要把这个c呢,加到集合里,我提前写好,省的一会忘了,这个容易忘啊,list.add(c);
,写到这呢,有人可能会想啊,说你看啊,我们循环,每次循环都创建一个对象,那这样的话,我们创建这么多对象,这个是不是效率会偏低呢,我能不能把这个对象,挪到前面去,我每次都加这个c,这不也没有问题么,它也不报错么,这样行不行呢,这样可不可以呢,行不行。public List findAll(){
Connection conn = null;
try {
conn = DBUtil.getConnection();
String sql = "select * from cost "+"order by cost_id";
Statement smt = conn.createStatement();
ResultSet rs = smt.executeQuery(sql);
List list = new ArrayList();
//Cost c = new Cost();//放到此处会覆盖集合中的所有元素
while(rs.next()) {
Cost c = new Cost();
list.add(c);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询资费失败",e);
}finally {
DBUtil.close(conn);
}
}
list.add(c)
,也是add多次啊,你循环100遍,也add100个对吧,有问题么,行不行,不行在哪,哎,有人说到点子上了,你不用说那么多,就说一句话,一个词,覆盖,就到点子上了,为啥呢,咱们一共就new了一个对像,第一次循环,往里存了个数据,唐僧对吧,第二次存了个猪八戒,最后,存了个悟空,那你说最后集合里装的是啥呢,全都是悟空,是这样吧,是吧,因为你即便是add 100次,add100个同一个对象对吧,是这意思吧,所以这是不行的啊,不能这么搞啊。所以呢,一个对像封装一条数据,你就得new这么多对象,没有办法啊。public List findAll(){
Connection conn = null;
try {
conn = DBUtil.getConnection();
//String sql = "select * form cost_lhh "+"order by cost_id";//测试错误页面error.jsp
String sql = "select * from cost_lhh "+"order by cost_id";
Statement smt = conn.createStatement();
ResultSet rs = smt.executeQuery(sql);
List list = new ArrayList();
while(rs.next()) {
Cost c = new Cost();
c.setCostId(rs.getInt("cost_id"));
c.setName(rs.getString("name"));
c.setBaseDuration(rs.getInt("base_duration"));
c.setBaseCost(rs.getDouble("base_cost"));
c.setUnitCost(rs.getDouble("unit_cost"));
c.setStatus(rs.getString("status"));
c.setDescr(rs.getString("descr"));
c.setCreatime(rs.getTimestamp("creatime"));
c.setStartime(rs.getTimestamp("startime"));
c.setCostType(rs.getString("cost_type"));
list.add(c);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询资费失败",e);
}finally {
DBUtil.close(conn);
}
}
Cost c = new Cost();
c.setCostId(rs.getInt("cost_id"));
c.setName(rs.getString("name"));
c.setBaseDuration(rs.getInt("base_duration"));
c.setBaseCost(rs.getDouble("base_cost"));
c.setUnitCost(rs.getDouble("unit_cost"));
c.setStatus(rs.getString("status"));
c.setDescr(rs.getString("descr"));
c.setCreatime(rs.getTimestamp("creatime"));
c.setStartime(rs.getTimestamp("startime"));
c.setCostType(rs.getString("cost_type"));
list.add(c);
public static void main(String[] args) {
CostDao dao = new CostDao();
List list = dao.findAll();
for(Cost c : list){
System.out.println(c.getCostId()+","+c.getName());
}
}
.do
,这是一种习惯,点do。我有时这样讲,我们项目中所有的普通的请求,咱们都叫点do,以.do
为后缀,那将来呢,如果有很特殊的请求,我们再加别的后缀,这样比较灵活;那么,我们工作时呢,很多项目都是这么干的。那下面我们来写这个Servlet啊。那么打开开发工具,然后啊,我们在这个web这个包下,创建这个类,就叫MainServlet,继承于HttpSerlvet:/findCost.do
,行吧,这样,我们一会配的时候,是按照这种后缀的方式进行处理,进行配置,那下面我们就要处理这个路径,那你看,这个/findCost.do
是Servlet的访问路径,是吧,所以要想去判断它的话,我们得取到谁呢,ServletPath,那下面呢,我们就获取访问路径,String path = req.getServletPath();
,那得到了访问路径以后,要判断啊,根据规范对路径加以处理,那写一下,就是根据规范处理路径,规范在哪里,我把它标在了图上,那就判断吧,咱们的规范里只有一个图,只有一个路径对吧,就判断它自己,如果说呢,这个路径就是,/findCost.do
的话,if("/findCost.do".equals(path));
。/findCost.do
,我们要执行呢,查询资费,这件事啊,再写一下,要查询资费,那么你要查询资费的话,我们要再单独调个方法,别在这直接写,在这直接写的话,将来判断多了,代码太罗嗦,对吧,调个方法,这个方法,我就叫findCost(req,res);
,然后呢,给它传入request和response,那么这个方法呢,咱们一会再写啊,先不着急,然后啊,否则,如果不是这个路径,那就是错的对吧,就这一个是对的,错的怎么办呢,抛异常,异常抛出去以后,最终由tomcat统一处理, 将来会处理好,抛出去,throw new RuntimeException("没有这个页面");
。@Override
,这东西呢,表示说我们是继承对吧,咱们在copy以后要改名,不是继承,所以你把这个方法的声明复制一下,复制完以后呢,我们在service之后粘贴一下,那粘贴以后啊,我就有了一个service方法,重名报错了,我把它改个名,改成就叫做findCost,然后呢,写上注释啊,说明白是什么作用,查询资费。//查询资费
protected void findCost(
HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
//查询所有的资费
CostDao dao = new CostDao();
List list = dao.findAll();
}
那这一步比较容易,就是实例化dao,调一下,得到数据就可以了,那么,得到的数据,我们需要呢,把它转发给jsp,所以进行下一步,就是将请求转发到jsp。那么如果呢,你要把请求转发到jsp,我们首先呢,得把数据绑定到request之上对吧,然后呢,转发时,把request给jsp,jsp呢,通过request,才能得到这个数据,所以呢,咱们下一步,是绑定数据,这也算是转发的一部吧,request点setAttribute,数据的值呢,就是集合,名字,取个名字,我叫costs,即req.setAttribute("costs", list);
。
数据绑定以后,可以实现转发了,那转发呢,就一句话,我们先获取到转发器对吧,并且呢,获取转发器的时候啊,要声明转发的路径,然后呢,调forward方法,传入request和response就行了,那写一下,req.getRequestDispatcher("").forward(req, res);
,那么在调用getRequestDispatcher转发器的时候,我们需要呢,传入转发的路径,相对路径,那么要想写相对路径,我们还得分析一下,这个相对路径怎写,是谁和谁的相对,是从哪到哪,你把这个起点和终点,这个两个路径呢,列举一下,然后呢,经过观察,很容易就知道了,所以呢,写相对路径的关键之处呢,是你要知道,我们是从哪跳到哪,那看图啊,有了图啊,很多问题都很直观的能够解释清楚。
那咱们是从Servlet到jsp对吧,从MainServlet.findCost()
这,到/WEB-INF/cost/find.jsp
这,那么Servlet,它的访问路径不就是/findCost.do
么,是吧,那么jsp,它的访问路径和静态资源一样,是它存放的目录对吧,是吧,以前是这么干的啊,那么之前的 Servlet4/访问路径 中,有说过,这个项目部署完以后,我们所谓的路径指的是部署后的,项目访问路径,而对于部署后的内容,那么访问时,有两种情况,一种是静态的内容对吧,像html,图片啊,等等,静态的,是它存放的位置,另外呢,是动态的,是Servlet对吧,是网名,那么jsp也是位置,它存放的位置。那么,我们把这者路径呢,列举一下。我们是当前,正在访问的是Servlet,那么它的路径是/netctoss/findCost.do
;目标jsp的是,/netctoss/WEB-INF/cost/find.jsp
:
//当前:/netctoss/findCost.do
//目标:/netctoss/WEB-INF/cost/find.jsp
那从Servlet到jsp啊,那么它们的路径,分别是上面的两个,所以你一看,相对路径咱们怎写,写哪一部分呢,那从哪开始写,WEB-INF
,因为findCost.do
和WEB-INF
平级对吧,就我们从WEB-INF
到最后find.jsp
是吧,/WEB-INF/cost/find.jsp
,就行了。即req.getRequestDispatcher("WEB-INF/cost/find.jsp").forward(req, res);
,总而言之啊,咱们在开发的时候,遇到问题,不要呢,永远都不要只停留在想的层面,很多事啊,光想,越想越乱,最好呢,是动动手,列举一下,写一写,甚至呢,试一试,很多时候,你一试,什么都知道,什么都清楚了。那这个Servlet,我们写完了,写完以后呢,对于这个类是不是得加以配置,所以下面呢,我们来配置这个类,配置的时候你要注意,它能够处理的请求,是以点do为后缀是吧,所以呢,访问路径你要写点do,那我们打开这个配置文件啊,对这个类加以配置,打开web.xml
:
main
web.MainServlet
main
*.do
*.do
,当我们以后缀的方式加以配置时,那么这个不能写斜线,是吧,不要写斜线,这要注意,那多说一句啊,这个有的时候,有同学面试,说面试官问这样一个话题,说,那你做这个项目为啥,所有请求都是点do呢,这样有什么好处呢,这样好么,就是他的问题是,一个组件处理所有请求,有啥好处呢,你可能连这句话的意思都没听明白,有人说你在说啥呢,是吧,这不挺好的么。其实,我们站的角度不一样,我们的角度是我们去学习,对吧,我们是,之前是一个请求一个servlet,那个不好是吧,我们改进了,一个类处理所有请求,这就好了。WEB-INF
下,创建一级目录叫cost,目录下创建一个页面叫find.jsp
,那我们创建这个内容,那么在WEB-INF
下,创建一个目录叫cost,cost之下创建一个jsp,叫find.jsp
,创建好以后,那这个jsp,首先要写的是指令对吧,我们先写一个page指令,<%@page pageEncoding="utf-8" %>
,那么在这个page指令之上,我们需不需要写出其他的属性呢,比如说contentType,比如说import,用不用写啊, 不用,因为contentType有默认值对吧,import我们用el表达式取值,不用了,对吧,不需要写,那我需不需要写出别的指令呢,比如说,include呀,taglib呀,需不需要写别指令呢,用不用,那想不到,先不写也没关系,这个page指令,<%@page pageEncoding="utf-8" %>
,必须要写对吧,那个include呀,taglib,我们需要时,再加也没关系对吧,先不写了,遇到时再说吧。NETCTOSS_V02
之下,这个资费查询页面,它在fee的下面,对吧,叫fee_list.html
,有人说,哎,这怎么叫fee呢,这个fee,这个单词也是费用的意思,它和那个cost类似,同义词对吧,那为啥叫俩不同的名字,不统一呢,咱们这个设计数据库啊,是张三,写网页呢,是李四,是俩人明白吧,这俩人对费用的理解产生了分歧,所以就不一致,那我们用哪一个呢,我们一般还是跟数据库这哥们站一边啊,因为我们差不多是一个意思啊,所以我们一般还是习惯于叫cost,我们就叫cost,因为我们那个实体类就叫Cost是吧,咱们就叫cost算了,就是我们取名叫cost,你看刚才我取名叫cost,它这个文件,它原来叫fee,我们把这个文件的代码copy过来。fee_list.html
打开,打开它,打开以后呢,得全选吧,全选会吧,ctrl+A ,复制会吧,ctrl+C,然后呢,打开你的eclipse,粘贴ctrl+V啊,粘贴到find.jsp的page指令下面,就行了。 那查询的功能到这,咱们把这个实体类dao,还有Servlet都完成了,然后呢,jsp已经创建了,jsp当中呢,这个静态的代码已经粘贴过去了,这还没完,这个jsp,我们copy过来的静态网页,它是依赖于这个样式文件和图片的,所以呢,我们还得把这个它所依赖的样式文件和图片呢,也copy到项目中来。WEB-INF
里,那么,我们所引用的图片和样式,如果有js,js也是,都要放到webapp里,这是一般项目的一些规则,那为什么要这样放呢,后面会讲,我们先把它写完会讲,这个先别着急。那放进来以后,咱们这个jsp在这里也有了,它所依赖的样式和图片,也有了,当然了,目前的话,这个jsp中,只有静态代码对吧,还没有动态的逻辑,那我们先不着急,我们先把这个项目呢,部署一下,我们尝试呢,去访问一下这个页面,看一看,能不能得到结果。把这个项目呢部署一下,部署以后,启动tomcat,那启动完以后,我们要访问这个资费查询的功能,怎么访问呢,应该访问谁呢,应该访问的是/findCost.do
,我们现在呢,是采用MVC模式去开发项目,那么在MVC模式当中呢,我们永远都不要试图,直接访问jsp,我们通常呢,访问的都是Servlet,由它处理请求转发给jsp,所以我们访问的是/findCost.do
,那么,如果项目做完整,我们应该点这个图标,但目前还没有图标,我们直接敲路径访问,测试。http://localhost:8080/netctoss/findCost.do
,然后回车,回车以后你看,你看啊,有点问题,但是呢,先别管这个问题,我们先呢,显示出这样的内容,到目前为止就算是ok了,试一下:/findCost.do
,它转发到了jsp,jsp呢,向浏览器输出了这样一个内容,内容是有,但是少点,差点东西对吧,这是差什么了呢,样式和图片不对,是吧,那样式和图片显示的不对,说明什么问题呢,应该是路径不对,对吧,所以,我们打开那个find.jsp
,我们检查一下,那个网页里面的图片,样式的路径,如果有问题的话,我们改一下,因为之前,我们看的是静态网页,现在呢,我们做的是动态网页对吧,这个结构有所变化,这个项目的访问的方式有所变化,所以说呢,路径可能是需要调整。那我们再回到开发工具当中。那我打开呢这个find.jsp
,然后呢,我们从第一行,往下看,然后你看第7行,第8行有link:`
`
find.jsp
在这,webapp/WEB-INF/cost/find.jsp
,我们要访问的,比如说images
,或者是styles
,对吧,在webapp目录下,中间差几级呢,一级,两级,是吧,差两级,所以两个点点杠,那你写上试试看,行不行,行么,不行,为什么不行呢,那有人提到了说,我们不应该看webapp这个地方,我们看的这个eclipse,这是源代码,我们访问的是源代码么,不是,你看这个就是错误的对吧,不应该看这。D/tts9/apache-tomcat-7.0.67/wtpwebapps/netctoss
,netctoss之下有styles和images,对吧,那那个find.jsp在哪呢,netctossWEB-INF/cost
之下,哎,我看了一下,部署以后还是差两级啊,那为啥不行呢。
... ...
`
`
... ...
... ...
forEach
,所以我们在jsp上呢,想要处理这个数据,我们得得到这个数据用el,处理数据用jstl对吧,我们得引入jstl标签吧,对不对。c.tld
文件,重新呢,copy一下那个名字,熟悉一下,省的你忘了,那咱们当前的电信计费项目,这里面有Libaries库,展开以后,有Maven Dependencies
,是吧,然后展开以后,里面有我们所导入的jar包,我们要看的是jstl对吧,展开, 展开以后呢,看的是META-INF
,对不对,META-INF
之下,我们要看的是c.tld
,那么打开c.tld
,打开以后,那么这个文件的名字是在多少行呢,12行uri,那我们呢,把这个uri,这个名字复制一下,复制时呢,你这个严谨一点,仔细一点。那复制以后,我们可以呢,回到刚才的find.jsp
,然后呢,用taglib指令,把它引入进去,那么在find.jsp
,这个,就是第2行,这个位置,我们在这插入一句话 ,一个指令,在这把这个指令写好,<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
,那指令的名字呢,叫taglib,属性uri当中呢,写的是我们,就copy的那句话,后面的prefix,写的是前缀,前缀是c。
,那么这个循环啊,它的结束应该是写到哪去呢,不应该在这对吧,应该是在它下面这个tr之后结束对吧,那我把这个结束符呢,剪切一下,把它放到tr的后面,那这样的话呢,我们每次循环,循环内部输出一行对吧,就这样一个结构,那么另外呢,forEach标签上呢,还有一些属性,有一个属性叫items,其次呢,还有一个属性叫var,
,那items当中啊,我们应该写上呢,我们要遍历的那个数据对吧,这个数据是由Servlet转发过来,转发的时候,那个数据的名字叫什么,当时我叫的是costs,对吧,复数,那我就写了,我要获取它,在这写了,写items="costs"
,对吧,行不行啊,行什么啊,合适么,不行,你要取数,得写什么啊,el表达式,但是我们很容易,在这个地方容易忘,所以说,演示一下,这样是不行的,你要取数,必须得写el,别忘了,items="${costs }"
。var="c"
,这个c的内容,用什么来输出呢,还是el,因为el可以取数,也可以输出对吧,它有两个功能,那我输出呢,是c.costId
,即${c.costId }
,那么这个c.costId
,costId是什么呢,这叫什么啊,这叫bean属性,我们写的是costId ,但它底层在调用时,调的是getCostId方法对吧,就是这样。${c.name }
,我这个程序啊,它一写完之后呢,就跳一下啊,这个可能跟开发工具有关系啊,c.name
,同理,第3列,第3列是基本时长,${c.baseDuration }
,然后呢,下一列是基本费用,${c.baseCost }
,再往后呢,是单位费用,${unitCost }
,然后再往后下一列,下一列是这个创建时间,${c.creatime }
,然后呢,再下一列,这个是开通时间,${c.startime }
,最后一列呢,是状态,那么状态呢,咱们表里存的数据,字段叫status对吧,存的是什么呢,是那个char,存的是0和1,对吧,0代表开通,1代表暂停,我们得到是0和1,但是呢,不能给用户看到0和1对吧,它不知道啥意思,我们需要翻译一下,那怎么翻译呢,你得用判断对吧,和我们翻译那个M,F,性别一样( 学生性别判断功能之JSTL标签if )。
,if标签之上有test属性,这里面写条件,当这个条件成立时候,我们输出某值,那我们要判断什么呢,那个status是否等于0或者1,对吧,判断取值,那就直接写了啊,
,要写el表达式,就总之啊,我们在书写这个数据啊,条件的时候,特别容易呢,把这个el给忘了,所以你要注意啊。那你看,咱们el表达式,这里呢是,既取了值,又做了运算对吧,是吧,又做了运算,判断是否相等,那么如果等于0,我们显示的是什么呢,开通,否则,那再写个if,暂停
,到这,咱们这个jsp,它里面的逻辑就完成了,这个数据呢,由原来的静态的,改为了动态的。
资费ID
资费名称
基本时长
基本费用
单位费用
创建时间
开通时间
状态
${c.costId }
${c.name }
${c.baseDuration }
${c.baseCost }
${c.unitCost }
${c.creatime }
${c.startime }
开通
暂停
,然后呢,可以写format等于格式,是这样吧,只不过呢,这个标签呢,它格式化的是一个当前时间对吧,如果说,我们给这个标签,再进一步,再加一个属性,比如加个value,我们把这个时间传给它进去,比如说,我能通过value,把时间呢,传给这个标签,他能不能把这个时间给我格式化了呢,也可以,是吧,
,可以这么去想,但其实呢,没有必要,这个标签啊,不用我们写,这个sysdate标签呢,本来就有啊,这个告诉你啊,就是说,我们可以 看那个jstl当中呢,有一个文件,有一个tld文件,叫fmt.tld
,先不用急着看,这个fmt呢,是format缩写,是格式化的意思,那这个文件之内所包含的标签,都是用来格式化的,其中有一个标签呢,专门格式化时间的,它叫做formatDate,那我们可以利用这个已有的标签,只要你把这个tld文件导入到jsp上,就用这个已有的标签就可以格式化这个时间啊。<%@page pageEncoding="utf-8" %>
,然后呢,我在写这个网页head里,它也有这句话utf-8,对吧,但这句话,跟以前我们写的不一样,以前我们写的是,
,但在这个find.jsp里,它整的这么复杂,
,你看,这能想出来么,它为什么这么麻烦呢,为啥这个写法,跟我们以前不一样呢,能想到么,就这个meta,怎么跟我们以前写的不一样,是这样的,你看find.jsp中的这个地方,
,这个地方跟我们以前写的一样么,不一样,以前我们直接写
,到html结束了是吧,表示这是用的是html5,那它还没结束,它写了很长是吧,这用的是什么呢,用的时X1,即XHTML 1.0
,用的是另外的一个旧的版本,明白吧,那这个旧的版本,想声明meta,就必须这样写明白吧,所以,这是旧的版本,所以是这样写,是这样的,如果是H5,就不用了。charset="utf-8"
,那你看,上面也有编码,这也有编码,那这两个编码,有冲突么,可以省略其中一个么,对吧,有什么关系呢,或者说,哪个编码,对什么地方产生影响呢,这个也需要探讨一下。总之啊,我们平时呢,开发小案例,模拟案例,这没什么大问题,但是呢,一开发一个项目以后,我们发现代码多了对吧,内容一多了,这个问题就多了,所以,你的项目呢,越复杂,你在这个项目中呢,所遇到的问题就会越多,困难也会越多,那你能够学到的东西也会越多,所以,我们呢,做这个项目的目的,也是希望让大家见到一下,一些问题,我们去解决问题,能成长。这是第3个话题啊,第3个问题,就是说,jsp上,怎么说呢,编码问题,具体来说呢是,为什么jsp上,就是有两处声明了编码,这两处有什么联系么,这是第3个问题。localhost:8080/netctoss/findCost.do
,点F12,打开这个控制台,打开这个network,打开以后啊,我们刷新一下这个查询功能,刷新一下, 刷新以后,你看network里有多个请求么,有,很多个,对吧,然后,大概看一下啊,最先是什么呢,findCost.do,然后是什么呢,css,然后是什么呢,图片,它是有一定的规律的,就是不用去细看,就是说大概,大概了解一下。findCost.do
引起的,明白吧,你看后面的请求,都是由findCost.do
引起的,就是我们主动访问的是findCost.do
,但其他的,关于样式,关于图片的请求,是在这个请求之内,和它相关的请求,自动的。那大概了解了这一点以后啊,下面呢,我们就解释一下,它为什么会这样,它这个工作原理到底是什么,我们更进一步去理解web项目,那这边呢,我画的是浏览器啊,然后呢,右边再画一个服务器,那当前呢,我们访问的是服务器端的Servlet,那具体来说,我们访问的是这个MainServlet当中的findCost()方法,MainServlet.findCost()
,我们访问的是它,然后呢,它处理请求的时候,它会呢,进行转发,它是把请求呢,转发给了,jsp,那这个jsp呢,它叫find.jsp
啊,当然,这个jsp呢,放到了WEB-INF
之下,这样的,然后呢,最终由jsp,向浏览器做出响应,关于dao,我就不写了,我就写个大概啊,这样。findCost.do
,就是我们当前,把我们所知道的信息呢,把它串起来,从中呢,寻找一些答案。那么最终啊,这个find.jsp
,它给浏览器返回的,返回的是什么呢,这东西给浏览器返回的是什么呢,浏览器从它这里得到了什么呢,返回的是啥啊,返回的仅仅是一个静态网页,HTML,那么Servlet也好,jsp也罢,这两者,都是服务器端的组件,那么他们的使命是用来处理HTTP协议,那么往通俗来讲,它是用来拼动态资源的,对吧,那么,我们利用的jsp拼的是什么呢,拼的是HTML,为什么这么讲呢,因为我们在写jsp的时候,我那个page指令上,没有写 contentType,是吧,那没有写,它有默认值,之前说过,默认值是什么呢,就是text/html
,是这样么,对吧,所以呢,这个jsp向浏览器输出的是html,它向浏览器输出了图片么,它向浏览器输出了样式么,输出了么,有么,并没有啊,它只是向浏览器输出了html而已,所以呢,在这个请求,就在我们访问findCost.do
,这个请求结束时,响应时,浏览器得到了,仅仅是html。那么,在这一刻,浏览器并没有得到样式和图片。MainServlet.findCost
,得到了一个静态网页,静态网页是被jsp组件生成的,仅仅是网页而已,然后呢,浏览器会加载网页,加载过程中,才显示出具体的内容,那么浏览器加载网页呢,会由上向下,按顺序加载,由上往下,按顺序加载,那么首先呢,它会加载网页中的head,这一部分,加载head,然后呢,再加载body,它会这个按顺序加载啊,先后。那总之啊,这个过程啊,这个环节,我们称之为加载。然后呢,它是先加载head,然后再加载body,有先后顺序。那你注意,那浏览器啊,在加载head的时候,它会看到,这个head里有一个子标签,这个子标签叫什么呢,叫link,有吧,有的,叫link,那浏览器一看啊,link标签,link标签表示说要引入一个样式文件。findCost.do
,对吧,第2个,样式文件对吧,它是有先有后的,好了,所以,这是第二个请求。findCost.do
这个,而后者呢,是自动的,这你不用关注了,因为那么多请求,它自动会访问,但这个事实你要知道。../
,那你看啊,这个我们在网页上引入样式文件和图片,那么是网页,咱们就以图片为例吧,是网页和图片的关系,是这样吧,是吧,网页上引入图片,是网页和图片的关系,我们从网页到图片,是这样吧,网页时当前,图片是目标,这样的。那你得知道,那网页的路径是什么啊,图片的路径是什么啊,你得知道,从这个图中看啊,这个web项目浏览器加载网页的关系图中看,就是从网页上加载图片,这件事是谁干的,肯定是浏览器干的,对吧,所以我们应该站在浏览器的角度,去分析这个问题啊,很多问题,我们需要找一个角度,因为这里有浏览器,还有服务器对吧,你站的角度得对,这件事浏览器干的,我们是以浏览器为角度。find.jsp
这个路径,没有以斜线开头,写的是相对路径对吧:
find.jsp
,你再想一下,JSP1:转发和重定向,转发这件事,浏览器知道么,不知道,它知道有jsp存在么,不知道,它就是写了findCost.do
,访问的服务器对吧,在它看来,这个网页,我是通过findCost.do
得到的,而这个网页访问路径就是.do
,是这意思吧,是这样的,听明白了么,这里面就没有,就是对于浏览器而言,jsp不存在,明白吧,就当它没有。所以呢,你看啊,那么是浏览器在加载这个网页时访问图片,是浏览器端得到的HTML和img的相对关系,而网页的访问路径就是findCost.do
,对吧,对于浏览器而言。那图片img的路径,就是图片存在的位置,对吧,是这样吧,就是图片存放的位置啊。/netctoss/findCost.do
(浏览器不知道转发这件事),是这样的吧,括号解释一下,浏览器不知道转发这件事,它不知道转发这件事,它不知道有jsp,明白吧,它就认为是findCost.do
给我的网页啊;然后呢,第4点,那么图片的访问路径,就是图片存放的位置啊,就是什么呢,就是/netctoss/images/logo.png
,咱们直接在webapp下放的图片目录对吧,所以就在这底下啊,然后呢,比如说logo.png
,随便写个图片啊,就是它。然后你再看,那既然是这两者的相对路径,那是不是,是不是只写image/logo.png
这一段啊,是吧。1.浏览器在加载网页时获取图片
2.获取图片的相对路径,是加载的网页和图片的相对关系
3.加载的网页的访问路径 /netctoss/findCost.do(浏览器不知道转发这件事)
4.图片的访问路径 /netctoss/images/logo.png
5.相对路径:images/logo.png
images/logo.png
,所以就没有点点杠,是这样得出的一个结论。那么这个结论呢,我把它摆到这来了,这块有点绕,再多想想。所以你看啊,咱们之前啊,做案例啊,讲路径啊,有人很烦,感觉这路径好像没什么可讲的,但其实呢,为啥我老强调路径呢,路径呢,没你想的那么简单啊,如果你真的能把每一个地方的路径都搞清楚的话,那一定是我们对整个网页加载的这个顺序和结构,有了一个非常清楚的认识才能做到,所以,通过路径的背后,我们是理解这个程序执行的完整流程,它背后是这样一个话题,所以呢,我们探讨路径这件事啊,是很有,很有意思啊,挺有意思的,它真的是把这个,怎么说呢,把这个浏览器和服务器之间的交互,就是演绎的比较,怎么说呢,比较生动吧,那你到底能不能理解这个web项目,其实通过路径,能看到很大的一部分,那尽量去理解吧。find.jsp
,它放到了WEB-INF里,假设我画的这个黄色的范围,就是WEB-INF
啊,假设啊,好,这个也是一个前提吧,咱们也解释一下,WEB-INF目录,它有,天生有保护能力,它有保护能力,它可以保护内部的资源避免其,避免该资源被直接访问。这是一个,这是前提条件,咱们需要先想一下。假设这个黄色的范围就是WEB-INF
啊,WEB-INF
具有保护能力,它可以保护内部的资源,避免资源被直接访问,那怎么才能访问呢,需通过转发才能访问,这样的。WEB-INF
之下,因为它是class对吧,是吧,Servlet是class ,class是在WEB-INF之下吧,那有人说,那Servlet为啥能直接访问呢,因为Servlet有独立注册的网名,明白吧,它和别人不一样,我们说的这个资源,是不包括Servlet的,它比较特别,它有网名,所以可以直接访问,那么其他的资源,没有网名的,就不能,WEB-INF具有保护能力,它能保护内部资源,避免该资源直接访问,那怎么访问呢,必须通过转发,才能访问。有人说,那为什么要这样呢,这个没有为什么,Sun是这样设计的,那有人说这有用么,肯定有用,你想啊,咱们上网时,很多软件会提供一个上传的功能,对吧,上传,如果把这个资源传到了这个服务器的硬盘上,如果对资源不加以保护它,有没有可能被别人直接访问到呢,有没有可能啊,很有可能对吧,如果你不保护的话,是不是别人可以直接访问这个资源啊,是这样吧,对吧,是的。.net
没有,如果说其他的语言,你想保护一个东西的话,得自己写代码,那java呢,就考虑到这一点了,它给我们一个目录WEB-INF
,能直接保护,如果你上传的话,直接把那个上传文件啊,丢到WEB-INF下,谁也访问不了,明白吧,就是说保护了,必须转发才能访问,而转发的前提是,你得处理它的请求啊,这是前提啊。https://www.taobao.com
,访问淘宝的话,我右键,右键查看网页源代码,那淘宝的代码一目了然对吧,他想保护,保护不了,因为你最终啊,想让浏览器看到这个内容,就必须把代码给它,明白吧,这东西没有什么保护的这个必要,就谁也,没人保护它,就这样。再一个呢,比如说你看这个,看这个网站啊,F12,你看这个Sources,Sources是代码,在这代码里,你能看到这个静态网页,当然它这个是在,部署到云上面去了啊,你能够看到什么呢,这个网页所依赖的所有的图片,这都能一目了然,都能看到,这不是什么秘密。localhost:8080/netctoss/findCost.do
,访问的是Servlet转发到jsp了吧,我肯定访问到了jsp对吧,那jsp输出了这个内容,我们这个网页里有,还有这个pageEncoding那个东西么,看一下啊,我们可以这样,右键/查看网页源代码:package util;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.tomcat.dbcp.dbcp.BasicDataSource;
public class DBUtil {
//连接池对象- 由DBCP提供
private static BasicDataSource ds;
static {
//加载参数
Properties p = new Properties();
try {
p.load(DBUtil.class.getClassLoader()
.getResourceAsStream("db.properties"));
//读取这些参数
String driver = p.getProperty("driver");
String url = p.getProperty("url");
String user = p.getProperty("user");
String pwd = p.getProperty("pwd");
String initSize = p.getProperty("init_size");
String maxSize = p.getProperty("max_size");
/*
*
*
*
*
* c3p0
*/
//创建连接池
ds = new BasicDataSource();
//设置参数
//使用这个参数注册驱动
ds.setDriverClassName(driver);
//使用这3个参数创建连接
ds.setUrl(url);
ds.setUsername(user);
ds.setPassword(pwd);
//使用其他参数管理连接
ds.setInitialSize(Integer.parseInt(initSize));
ds.setMaxActive(Integer.parseInt(maxSize));
/*ds.setInitialSize(new Integer(initSize));
ds.setMaxActive(new Integer(maxSize));*/
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(
"加载db.properties失败", e);
}
}
/**
* 由连接池创建的连接,其实现类由连接池提供.
*/
public static Connection getConnection()
throws SQLException {
return ds.getConnection();
}
/**
* 连接池提供的实现类,其close方法内部逻辑是,
* 将连接归还给连接池,即它会清空连接对象中的数据,
* 并且将连接标记为空闲态.
* 或者说:
* 由连接池创建的连接,连接的close方法被连接池重写了,
* 变为了归还连接的逻辑,即:连接池会将连接的状态设置为空闲,
* 并清空连接中所包含的任何数据。
*/
public static void close(Connection conn) {
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(
"归还连接失败", e);
}
}
}
public static void rollback(Connection conn) {
if(conn != null) {
try {
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(
"回滚事务失败", e);
}
}
}
public static void main(String[] args) throws SQLException {
Connection conn = DBUtil.getConnection();
System.out.println(conn);
DBUtil.close(conn);
}
}
# database connection parameters
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:orcl
user=SYSTEM
pwd=Oracle123
# datasource parameters
init_size=1
max_size=3
url=jdbc:oracle:thin:@localhost:1521:xe
driver=oracle.jdbc.OracleDriver
user=lhh
password=123456
package entity;
import java.io.Serializable;
import java.sql.Timestamp;
public class Cost implements Serializable {
private Integer costId;
private String name;
//基本时长
private Integer baseDuration;
//基本费用
private Double baseCost;
//单位费用
private Double unitCost;
//状态(枚举):0-开通;1-暂停;
private String status;
//资费说明
private String descr;
//创建时间
private Timestamp creatime;
//开通时间
private Timestamp startime;
//资费类型(枚举):1-包月;2-套餐;3-计时;
private String costType;
public Integer getCostId() {
return costId;
}
public void setCostId(Integer costId) {
this.costId = costId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getBaseDuration() {
return baseDuration;
}
public void setBaseDuration(Integer baseDuration) {
this.baseDuration = baseDuration;
}
public Double getBaseCost() {
return baseCost;
}
public void setBaseCost(Double baseCost) {
this.baseCost = baseCost;
}
public Double getUnitCost() {
return unitCost;
}
public void setUnitCost(Double unitCost) {
this.unitCost = unitCost;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
this.descr = descr;
}
public Timestamp getCreatime() {
return creatime;
}
public void setCreatime(Timestamp creatime) {
this.creatime = creatime;
}
public Timestamp getStartime() {
return startime;
}
public void setStartime(Timestamp startime) {
this.startime = startime;
}
public String getCostType() {
return costType;
}
public void setCostType(String costType) {
this.costType = costType;
}
}
package dao;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import com.sun.corba.se.spi.orbutil.fsm.Guard.Result;
import entity.Cost;
import util.DBUtil;
public class CostDao implements Serializable {
public List findAll(){
Connection conn = null;
try {
conn = DBUtil.getConnection();
//String sql = "select * form cost_lhh "+"order by cost_id";//测试错误页面error.jsp
String sql = "select * from cost_lhh "+"order by cost_id";
Statement smt = conn.createStatement();
ResultSet rs = smt.executeQuery(sql);
List list = new ArrayList();
while(rs.next()) {
Cost c = new Cost();
c.setCostId(rs.getInt("cost_id"));
c.setName(rs.getString("name"));
c.setBaseDuration(rs.getInt("base_duration"));
c.setBaseCost(rs.getDouble("base_cost"));
c.setUnitCost(rs.getDouble("unit_cost"));
c.setStatus(rs.getString("status"));
c.setDescr(rs.getString("descr"));
c.setCreatime(rs.getTimestamp("creatime"));
c.setStartime(rs.getTimestamp("startime"));
c.setCostType(rs.getString("cost_type"));
list.add(c);
}
return list;
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException("查询资费失败",e);
}finally {
DBUtil.close(conn);
}
}
public static void main(String[] args) {
CostDao dao = new CostDao();
List list = dao.findAll();
for(Cost c : list) {
System.out.println(c.getCostId()+","+c.getName());
}
}
}
package web;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import dao.AdminDao;
import dao.CostDao;
import entity.Admin;
import entity.Cost;
import util.ImageUtil;
public class MainServlet extends HttpServlet {
@Override
protected void service(
HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
//获取访问路径
String path = req.getServletPath();
//根据规范(图)处理路径
if("/findCost.do".equals(path)) {
findCost(req,res);
} else {
throw new RuntimeException("没有这个页面");
}
}
//查询资费
protected void findCost(
HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
//查询所有的资费
CostDao dao = new CostDao();
List list = dao.findAll();
//将请求转发到jsp
req.setAttribute("costs", list);
//当前:/netctoss/findCost.do
//目标:/netctoss/WEB-INF/cost/find.jsp
req.getRequestDispatcher("WEB-INF/cost/find.jsp").forward(req, res);
}
}
netctoss
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
main
web.MainServlet
main
*.do
达内-NetCTOSS
<%@page pageEncoding="utf-8" %>
达内-NetCTOSS