分页与项目准备

一、EL与JSTL应用

在项目展示中使用EL+JSTL的应用:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
 <c:forEach items="${emps}" var="emp">
            <tr>
                <td>${emp.id}</td>
                <td>${emp.name}</td>
                <td>${emp.salary}</td>
                <td>${emp.age}</td>
                <td><a href='${pageContext.request.contextPath}/manage/safe/remove?id=${emp.id}'>删除</a></td>
                <td><a href='<%=request.getContextPath()%>/manage/safe/showEmp?id=${emp.id}'>修改</a></td>
            </tr>
        </c:forEach>

在显示单个对象时,使用EL表达式:

<form action="<%=request.getContextPath()%>/manage/safe/update">
    <%-- 编号不可变更,要么设置为只读,要么隐藏该控件 --%>
    编号:<input type="text" name="id" value="${emp.id}" readonly><br>
    姓名:<input type="text" name="name" value="${emp.name}"><br>
    工资:<input type="text" name="salary" value="${emp.salary}"><br>
    年龄:<input type="text" name="age" value="${emp.age}"><br>
    <input type="submit" value="修改">
</form>

二、MVC框架

概述

三个单词的组合:Model,View,Controller

M–Model:模型层,包含了业务模型,数据模型,实体模型

V–View: 视图层,用于展示后端数据,使用JSP/HTML展示视图

C–Controller:控制层,Servlet控制,用于和模型层打交道

应用场景:在java的很多框架中使用了MVC架构,例如:Struts2,SpringMVC

MVC与三层架构

MVC:将三层架构中的表示层分离了;抽取出了视图层,侧重点在于前后端的交互,封装了业务层与DAO层。

三层架构:重点在于模型层,在于后端数据的处理;将业务层和DAO分离,封装了控制层与视图层。

三、分页

分析:关于分页功能,我们可以先进行后端的处理,将SQL语句完成,并测试DAO,如果没问题,再进行前后端交互即可,需要考虑数据的封装。

后端操作

完成SQL语句:

第一页: select * from emp limit 0,5

第二页: select * from emp limit 5,5

以此类推…

员工DAO层的分页测试:

@Override
public List<Emp> selectEmpsPage(int startIndex, int pageSize) throws SQLException {
    String sql = "select * from emp limit ?,?";
    return runner.query(sql,new BeanListHandler<>(Emp.class),startIndex,pageSize);
}

public static void main(String[] args) throws SQLException {
    List<Emp> emps = new EmpDaoImpl().selectEmpsPage(0,5);
    System.out.println(emps);
}

封装Page

从后端回传到前端的数据有很多,例如:内容,当前页,页数量等,所以需要封装成Page实体类,将这些数据装起来。

创建Page实体类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Page <T>{ //分页的实体类
    private  int currentPage;   //当前页
    private  int pageSize;      //页大小(每页条数)
    private  long totalCount;   //总条数
    private  long pageCount;    //总页数
    private  List<T> list;      //存内容

    public Page(int currentPage,int pageSize){
        this.currentPage = currentPage;
        this.pageSize = pageSize;
    }
}

在业务层进行Page数据的封装与逻辑判断

public class EmpServiceImpl implements EmpService {
    private EmpDao empDao = new EmpDaoImpl();
    @Override
    public Page<Emp> getPage(String current) {
        try {
            //分页数据的封装:
            int currentPage = 1;  //初始数据:当前页默认为1
            int pageSize = 5;     //页大小默认5条
            if(current!=null){ //为null则默认为第一页;不为null,则赋值
                currentPage=Integer.parseInt(current);
            }
            Page page = new Page<>(currentPage,pageSize);
            long totalCount = empDao.getEmpCounts();
            page.setTotalCount(totalCount);  //设置总条数
            long pageCount = (long) Math.ceil ((double)totalCount/pageSize);
            page.setPageCount(pageCount); //设置总页数
            int startIndex = (currentPage-1)*pageSize; //求起始页
            page.setList(empDao.selectEmpsPage(startIndex,pageSize));
            return page;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

控制层只需传一个封装的Page数据

@WebServlet("/manage/safe/show")
public class EmpShowController extends HttpServlet {
    private EmpService empService = new EmpServiceImpl();  //员工业务层
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String current = req.getParameter("currentPage");
        //传入currentPage,表示根据选择的当前页,返回分页数据
        Page<Emp> page = empService.getPage(current); //获取封装后的Page实体
        req.setAttribute("p",page);  //存储page实体
        req.getRequestDispatcher("/showEmps.jsp").forward(req,resp);
    }
}

前端测试:http://localhost:8080/manage/safe/show?currentPage=2,根据传入的当前页,显示不同页数的内容。

分页展示

<a href="<%=request.getContextPath()%>/manage/safe/show?currentPage=1">首页</a>
<c:if test="${p.currentPage!=1}"><%--如果不是第一页,则显示上一页--%>
    <a href="<%=request.getContextPath()%>/manage/safe/show?currentPage=${p.currentPage-1}">上一页</a>
</c:if>
<c:if test="${p.currentPage!=p.pageCount}"> <%-- 如果不是尾页,则显示下一页 --%>
    <a href="<%=request.getContextPath()%>/manage/safe/show?currentPage=${p.currentPage+1}">下一页</a>
</c:if>
<a href="<%=request.getContextPath()%>/manage/safe/show?currentPage=${p.pageCount}">尾页</a>
共${p.currentPage}/${p.pageCount}

四、项目准备

电商项目目前虽然不是最主流,但是应用场景还是非常广;所以,以电商项目作为web项目,熟悉里面的项目流程是非常合适的。

商城类别

B2B: 商家对商家—阿里巴巴,中国制造

B2C: 商家对客户—京东

C2C: 客户对客户—淘宝(引入第三方售卖)

O2O:线上线下结合—京东,淘宝等都有线下实体店

商城模块

商城模块主要分为前端和后端的模块,通过用户的角色来设计前后端模块(这里的前后端模块都是动态web资源)

前端模块:(普通会员访问的模块)

会员用户模块管理、商品模块、类别模块、购物车模块、订单模块、订单详情模块,发货地址模块等。

后端模块:(管理员访问的模块)

后端登录模块、商品模块、类别模块、订单模块等(权限会更大,设置DML等功能)

开发流程

一个正规的公司,基本上会具备以下开发流程:

需求分析:产品经理与客户谈需求-项目需求,工期,收费

概要设计:技术总监完成需求文档,模块划分

详细设计:主管或架构师进行架构设计,从业务需求转为技术实现;需要的框架,数据结构,算法等

编码:前端和后端工程师进行编程开发

测试:黑盒测试(功能体验角度测试)与白盒测试(写代码及案例进行测试)

项目交付:程序员编写操作手册交付给客户,以及操作培训

验收:产品经理与客户洽谈功能是否合格,收款(90%~95%)

维护:程序员后期维护

五、项目设计

设计细节

考虑开发环境、开发工具、操作系统、数据库等等

主要业务功能:前端模块需要有那些设计以及后端模块要求

项目完成效果:根据普通会员,游客及管理员身份的登录进行流程化的设计

数据库设计

设计工具为PD,通过该工具创建表后,可以直观的看成这些表之间的关系;图形化效果较好。

PD生成SQL文件的步骤:

1.先创建CDM(概念数据模型):也就是创建了实体,实体中包含多个属性

2.再创建PDM(物理数据模型):将实体转为表设计,CDM中的属性转为PDM中的字段

3.最后生成SQL文件,该SQL文件即可导入到数据建库

表的关系

表的关系指的是多张表之间的关联关系,有以下几种:

一对一:从当前表的一条记录可查询到另一张表的一条记录;例如:一个人对应一个身份证

一对多:从当前表的一条记录可查询到另一张表的多条记录;例如:一个用户对应多个地址

多对多:双方都是一对多关系 例如:一个老师教多门课程;一门课程可以被多个老师教

六、项目搭建

导入素材

导入数据库的SQL文件

导入前端页面

导入项目中需要的依赖包

导入Utils工具类

BaseServlet设计

在前面的员工管理综合案例中,一个员工模块,在Controller层写了多个Controller,针对于功能进行编写的Controller(从功能角度设计);因为在之前的设计中,无法将这些功能整合到一个Controller中。

现在的商城项目中,有多个模块,我们可以从模块的角度出发,根据模块去整合多个应用功能;此处再使用功能去设计Controller则无法进行管理。

设计案例:有一个用户模块,里面整合登录和注册功能;另一个产品模块里面整合展示和搜索功能

思路1:创建BaseServlet,将每个模块的service方法处理都统一到BaseServlet,提升了复用性;

处理方案:BaseServlet继承HttpServlet;模块Servlet则继承BaseServlet

思路2:判断BaseServlet中的功能调用,找到对应模块中的方法调用,如何提升判断的维护性?

处理方案:使用反射机制,得到模块Servlet的类对象,再通过反射调用模块对应功能

public class BaseServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getParameter("action");
        //反射应用:
        try{
            Class clazz = this.getClass(); //获取反射对象  哪个模块访问的service,则反射对象代表谁
            Method method = clazz.getMethod(action,HttpServletRequest.class,HttpServletResponse.class);
            Object o = method.invoke(this,req,resp); //调用指定功能
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
@WebServlet("/user")   //http://localhost:8080/user?action=login
public class UserController extends BaseServlet {
    public void login(HttpServletRequest request,HttpServletResponse response){
        System.out.println("登录功能");
    }
    public void register(HttpServletRequest request,HttpServletResponse response){
        System.out.println("注册功能..");
    }
}
@WebServlet("/product")
public class ProductController extends BaseServlet {
    public void show(HttpServletRequest request,HttpServletResponse response){
        System.out.println("产品展示");
    }
    public void search(HttpServletRequest request,HttpServletResponse response){
        System.out.println("产品搜索");
    }
}

访问规则:http://localhost:8080/user?action=login

七、总结与作业

总结

1.EL与JSTL应用
EL+JSTL完成if及for循环操作
2.MVC框架(重点)
概述、MVC与三层架构的区别
3.分页
后端操作-DAO测试SQL、封装Page-在业务层完成封装数据、分页展示
4.项目准备
商城类别、商城模块-前端会员、后端管理员模块、开发流程
5.项目设计
设计细节-环境准备、数据库设计-PD、表的关系(重点)
6.项目搭建
导入素材,BaseServlet设计(重点)

作业

1.BaseServlet设计的优势是什么?为什么调用方法需要传request和response参数
2.完成Servlet模块中统一返回String类型,并在BaseServlet中完成转发与重定向及字符串的判断;并说明这样设计的好处

晨考

1. MVC与三层架构区别
2. 分页中为什么需要Page实体类?
3. 为什么需要按模块划分控制层?为什么需要BaseServlet? 为什么用到了反射处理?

答: