1.基于jsp+servlet+javaBean的MVC架构
Controller:Servlet, servlet的职责是接收并处理请求,生成响应给客户端(把页面需要的数据存起来,跳转到页面显示)
Model: 在原有的结构上(entity+dao(impl)+util )加入service层(业务层),为什么需要加入service?
对于复杂的业务,如客户在电商网站上下订单,下订单的处理步骤较多:
1.订单表操作: 添加订单编号 收货人 地址 总金额 时间
2.订单明细表多个添加操作: 明细编号 商品编号 商品单价 商品数量,所属订单
3.修改商品的库存: 买的商品库存量要更新
4.转账操作:买家-money 商家+money
5.交易记录:谁在什么时间和谁进行了一笔交易,交易总额
此时如果直接在servlet中调用Dao,导致Servlet很复杂(不符合开发需求)
如何将servlet和dao解除耦合?
提取一个service层,在service层的service类中调用dao, 再由servlet调用service
在这个图里反映了各个层的调用关系,service层中的业务类里的方法称为业务方法
对于简单的业务,业务层看似多余;但是为了养成良好的开发习惯,即使业务简单,也使用业务层。
当使用业务层后,Service中的业务方法应该直接返回Servlet所需要的数据。
业务层的开发和Dao是相似的,先编写业务接口,放到xxx.service包下
再编写业务接口的实现类,简称业务类,放到xxx.service.impl下
最后在Servlet中调用Service的业务方法
2今天任务:
任务1:在首页展示5个商品
步骤1:创建web项目,把已编译项目的静态资源拷贝到自己项目的WebRoot目录下
拷贝到我们的项目的js文件上会有红叉,这是MyEclipse的误报,可以无视它,或者
让MyEclipse不去校验它(Exclude from Validation)
步骤2:在欢迎页index.jsp上请求Servlet获取最新的5个商品
<script type="text/javascript">
//用js来发请求给servlet,就是一个GET请求
location.href='goods.action?method=queryFive';
</script>
步骤3:在GoodsDao中增加方法selectFive,查询前5个商品
public class GoodsDaoImpl extends BaseDao<Goods> implements GoodsDao {
@Override
public List<Goods> selectFive() {
// TODO Auto-generated method stub
String sql = "select goods_id,goods_name,mall_price,goods_pic from t_goods order by goods_id desc limit 0,5";
List<Goods> list = this.getList(Goods.class, sql);
return list;
}
}
步骤4:创建GoodsService,添加获取前5个商品的方法,实现类的方法代码
@Override
public List<Goods> queryData(PageBean<Goods> pb) {
// TODO Auto-generated method stub
String sql="select goods_id,goods_name,goods_pic,market_price from t_goods limit ?,?";
List<Goods> list = this.getList(Goods.class, sql, (pb.getCurrentPage()-1)*pb.getPageSize(),pb.getPageSize());
return list;
}
@Override
public int queryTotalCount() {
// TODO Auto-generated method stub
String sql="select count(goods_id) from t_goods";
int total = this.getTotal(sql);
return total;
}
步骤5:在GoodsServlet中添加处理查询5个商品的方法queryFive
@Override
public void getPageBean(PageBean<Goods> pb) {
// TODO Auto-generated method stub
// 调用Dao的两个方法
// 获取数据集合
List<Goods> list = goodsDao.queryData(pb);
// 获取总记录数
int totalCount = goodsDao.queryTotalCount();
// 封装pageBean的其它属性
pb.setData(list);
pb.setTotalCount(totalCount);
}
步骤6:在qiantai/index.jsp上循环生成商品数据
<table width="100%" align="left" cellpadding="0" cellspacing="0"
border="0">
<tr>
<!-- 循环生成商品信息 -->
<c:forEach var="gd" items="${goods }">
<td>
<table width="100%" cellpadding="0" cellspacing="0"
border="0">
<tr>
<td sytle="height:60px;">
<dl
style="width: 100%; height: 200px; padding-right: 10px;">
<dd style="margin-left: 0;">
<a
href="${pageContext.request.contextPath}/goods.action?method=queryDetail&goodsId=${gd.goods_id}">
<!-- 商品图片 --> <img width="105" height="110"
src="${pageContext.request.contextPath}/${gd.goods_pic}" />
</a>
</dd>
<dt style="margin-left: 0; width: 90%">
<a
href="${pageContext.request.contextPath}/goodsDetail.action?goodsId=${gd.goods_id}">
<font size="2"> ${gd.goods_name } </font>
</a>
</dt>
<dt>
<font size="2">¥: ${gd.mall_price }</font>
</dt>
</dl>
</td>
</tr>
</table>
</td>
</c:forEach>
</tr>
</table>
任务2:在首页右侧登录div的下方显示所有商品分类数据
1)创建CatelogDao及其实现类,定义查询商品分类的方法
public class CatelogDaoImpl extends BaseDao<Catelog> implements CatelogDao {
@Override
public List<Catelog> queryAll() {
// TODO Auto-generated method stub
String sql="select catelog_id,catelog_name from t_catelog";
List<Catelog> list = this.getList(Catelog.class, sql);
return list;
}
}
2)创建CatelogService及其实现类,定义获取所有商品分类的方法
public class CatelogServiceImpl implements CatelogService {
private CatelogDao catelogDao=new CatelogDaoImpl();
@Override
public List<Catelog> getAllCatelogs() {
// TODO Auto-generated method stub
List<Catelog> list = catelogDao.queryAll();
return list;
}
}
3)在GoodsServlet的queryFive()方法中调用获取所有商品分类的方法
//处理查询最新5个商品的请求
public void queryFive(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
//调用GoodsService的查询方法,获取5个最新商品
GoodsService service=new GoodsServiceImpl();
List<Goods> goods = service.getTopFiveGoods();
//把5个商品 的集合数据存到request作用域中
request.setAttribute("goods", goods);
//获取所有商品分类的数据
CatelogService cateService=new CatelogServiceImpl();
List<Catelog> allCatelogs = cateService.getAllCatelogs();
//把商品分类集合存到session中
HttpSession session=request.getSession();
session.setAttribute("catelogs", allCatelogs);
//转发到qiantai/index.jsp request.getRequestDispatcher("qiantai/index.jsp").forward(request, response);
}
4).修改qiantai/index.jsp,动态生成商品分类数据
<c:forEach var="c" items="${catelogs }">
<tr>
<td height="28" id="roll-line-1607838439" width="100%">
<div class="" style="padding:2px 0px;">
<div class="f-left">
<img
src="${pageContext.request.contextPath}/img/head-mark3.gif"
align="middle" class="img-vm" border="0" /> <a
href="${pageContext.request.contextPath}/goods.action?method=queryByCatelog&catelogId=${c.catelog_id}">
<span style="font-size:12px">${c.catelog_name }</span>
</a>
</div>
<div class="clear"></div>
</div>
</td>
</tr>
</c:forEach>
任务3:点击“更多”在商品列表页面分页显示商品列表
第1步:封装一个分页工具类,代码见PageBean
第2步:把qiantai/index.jsp上的“更多”超链接的请求路径改过来
<a href="${pageContext.request.contextPath}/goods.action?method=queryByPage">更多</a>
第3步:在BaseDao中加入一个查询,返回单行单列结果的方法
public int getTotal( String sql, Object... params) {
//返回值
int total=0;
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt=conn.prepareStatement(sql);
// 给占位符?赋值
for (int i = 0; i < params.length; i++) {
stmt.setObject(i + 1, params[i]);
}
rs=stmt.executeQuery();
if (rs.next()) {
total= rs.getInt(1);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcUtil.closeAll(rs, stmt, conn);
}
return total;
}
第4步:在GoodsDao中加入根据页号和每页条数查询数据集合、查询总记录数的方法
@Override
public List<Goods> queryData(PageBean<Goods> pb) {
// TODO Auto-generated method stub
String sql="select goods_id,goods_name,goods_pic,market_price from t_goods limit ?,?";
List<Goods> list = this.getList(Goods.class, sql, (pb.getCurrentPage()-1)*pb.getPageSize(),pb.getPageSize());
return list;
}
@Override
public int queryTotalCount() {
// TODO Auto-generated method stub
String sql="select count(goods_id) from t_goods";
int total = this.getTotal(sql);
return total;
}
第5步:在GoodsService中加入分页查询的方法
@Override
public void getPageBean(PageBean<Goods> pb) {
// TODO Auto-generated method stub
// 调用Dao的两个方法
// 获取数据集合
List<Goods> list = goodsDao.queryData(pb);
// 获取总记录数
int totalCount = goodsDao.queryTotalCount();
// 封装pageBean的其它属性
pb.setData(list);
pb.setTotalCount(totalCount);
}
第6步:在GoodsServlet中加入分页查询商品的方法
//处理分页查询商品的请求
public void queryByPage(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取请求的页号,即要查询第几页数据,假设请求参数名currentPage
String pageStr=request.getParameter("currentPage");
//保存请求的页号
int currentPage=1;
if(pageStr!=null){
currentPage=Integer.parseInt(pageStr);
}
//每页条数
int pageSize=5;
//封装一个pageBean对象,它只有2个数据currentPage和pageSize
PageBean<Goods> pb=new PageBean<>();
pb.setCurrentPage(currentPage);
pb.setPageSize(pageSize);
//把每页条数和页号传给Service,获取PageBean对象
GoodsService service=new GoodsServiceImpl();
service.getPageBean(pb);
//把PageBean存到request中
request.setAttribute("pb", pb);
//转发到列表页面qiantai/goods/list.jsp
request.getRequestDispatcher("qiantai/goods/list.jsp").forward(request, response);
}
第7步:在qiantai/goods/list.jsp页面上分页显示PageBean中的数据
<table width="99%" border="0" cellpadding="2" cellspacing="1"
bgcolor="#FFFFFF" align="center" style="margin-top:8px">
<tr align="center" bgcolor="#FAFAF1" height="22">
<td>商品名称</td>
<td>市场价</td>
<td>商品图片</td>
<td>操作</td>
</tr>
<c:forEach var="gd" items="${pb.data }">
<tr align='center' bgcolor="#FFFFFF" height="22">
<td>${gd.goods_name }</td>
<td>¥${gd.market_price } <br /></td>
<td><a
href="${pageContext.request.contextPath}/goods.action?method=queryDetail&goodsId=${gd.goods_id}">
<img
src="${pageContext.request.contextPath}/${gd.goods_pic}"
width="60" height="60" border="0" />
</a></td>
<td><a
href="${pageContext.request.contextPath}/goods.action?method=queryDetail&goodsId=${gd.goods_id}"><img
alt=""
src="${pageContext.request.contextPath}/images/icon_buy.gif"
border=0 /></a></td>
</tr>
</c:forEach>
</table>
当前第${pb.currentPage }页,每页<font color="red">${pb.pageSize }</font>条/共<font
color="red">${pb.totalCount }</font>条记录
<!-- 当前页号>1时,给用户提供上一页超链接;否则直接显示“上一页” -->
<c:choose>
<c:when test="${pb.currentPage gt 1}">
<a
href="${pageContext.request.contextPath }/goods.action?method=queryByPage¤tPage=${pb.currentPage-1}">上一页</a>
</c:when>
<c:otherwise>
上一页
</c:otherwise>
</c:choose>
<!-- 生成一组页号的超链接 -->
<c:forEach var="sn" begin="1" end="${pb.totalPage }">
<a
href="${pageContext.request.contextPath }/goods.action?method=queryByPage¤tPage=${sn}">${sn }</a>
</c:forEach>
<!-- 当前页号<总页数时,给用户提供下一页超链接;否则直接显示“下一页” -->
<c:choose>
<c:when test="${pb.currentPage lt pb.totalPage}">
<a
href="${pageContext.request.contextPath }/goods.action?method=queryByPage¤tPage=${pb.currentPage+1}">下一页</a>
</c:when>
<c:otherwise>
下一页
</c:otherwise>
</c:choose>