商品展示

一、验证码

验证码展示

<img  id="pagecode" src="/user?action=valid">
//在UserController中验证码展示
public void valid(HttpServletRequest request,HttpServletResponse response) throws IOException {
    ValidateCode vc = new ValidateCode(120, 50, 1, 5);
    System.out.println("验证码:"+vc.getCode());
    request.getSession().setAttribute("imgCode",vc.getCode());
    vc.write(response.getOutputStream());
}

验证码校验

//3.验证输入的验证码 是否正确
$("#vcode").change(function(){
    $.get("/user","action=checkCode&code="+this.value,function(data){
        if(data==0){
            $("#checkMsg").html("<font color='green'>OK</font>");
            $("#btn").removeAttr("disabled");
        }else{
            $("#checkMsg").html("<font color='red'>ERROR</font>");
            $("#btn").prop("disabled",true); //设置disable属性
        }
    })
});
//验证码校验
public String checkCode(HttpServletRequest request,HttpServletResponse response){
    String code = request.getParameter("code");  //获取表单子控件验证码值
    //获取验证码图片的内容
    String imgCode = (String) request.getSession().getAttribute("imgCode");
    if(code.equalsIgnoreCase(imgCode)){
        return "0";  //0代表验证成功
    }else{
        return "1";  //1代表验证失败
    }
}

刷新验证码

//2.点击验证码 跟新验证码
$("#pagecode").click(function(){
    $("#pagecode").attr("src","/user?action=valid&c=?"+Math.random());
});

二、记录账户

在登录成功后,如果勾选了"记录登录账户",则存储Cookie;在展示首页时,获取cookie,根据存储的cookie,取出后进行登录测试,如果登录成功,则设置凭证。

设置Cookie

//记录登录账户:
String auto = request.getParameter("auto");
Cookie cookie = new Cookie(ConstUtils.UPASS,username+"-"+password);
if(auto!=null){ //不为null,则说明勾选了;为null则去掉勾选
    cookie.setMaxAge(60*60*24*14);  //单位秒  14天
}else{
    cookie.setMaxAge(0);  //清除cookie
}
response.addCookie(cookie);

获取Cookie

在首页中获取Cookie:

<%
    //获取Cookie
    Cookie[] cookies = request.getCookies();
    String username = null;  //接收用户名和密码
    String password = null;
    if(cookies!=null){
        for(Cookie c:cookies){ //循环变量,并判断登录cookie
            if(c.getName().equals(ConstUtils.UPASS)){
                username = c.getValue().split("-")[0];
                password = c.getValue().split("-")[1];
                break;
            }
        }
    }
    //判断是否取到登录cookie值
    if(username!=null&&password!=null){
        UserService userService = new UserServiceImpl();
        User user = userService.login(username,password); //交给业务层登录
        //对应的设置凭证
        request.getSession().setAttribute(ConstUtils.LOGIN,user);
    }
%>

清除cookie

点击首页”注销“,可以清除cookie及登录凭证

//在header.jsp中触发注销功能
<a href="user?action=logOut" id="a_top">注销</a>
//注销session与cookie
public String logOut(HttpServletRequest request,HttpServletResponse response){
    //移除session
    request.getSession().removeAttribute(ConstUtils.LOGIN);

    //清除cookie
    Cookie cookie = new Cookie(ConstUtils.UPASS,"xxx");
    cookie.setMaxAge(0);  //立马失效
    response.addCookie(cookie);
    return ConstUtils.RED+"/index.jsp";
}

三、商品类别

访问首页时,会报错误,原因是访问商品类别失败;需要创建商品类别模块

创建类别模块

在控制层和service和DAO层分别创建商品类别模块;并修改类别实体

展示类别信息

在header.jsp中发送ajax请求,在类别controller中处理

$.ajax({
    url:"${pageContext.request.contextPath}/type?action=show",
    type:"GET",
    //dataType:"json", //返回json字符串后,进行json解析成对象
    success:function(data){
        data= JSON.parse(data);  //解析成对象
        for(var i in data){
            var a = $("<a href='${pageContext.request.contextPath}/getGoodsListByTypeId?typeid="+data[i].t_id+"'>"+data[i].t_name+"</a>");
            $("#goodsType").append(a);
        }
    },
    error:function(){
        alert("失败");
    }
})

在控制层接收请求,并交给业务层处理

@WebServlet("/type")
public class TypeController extends BaseServlet {
    private TypeService typeService = new TypeServiceImpl();
    public String show(HttpServletRequest request, HttpServletResponse response){
        List<Type> list = typeService.showAll();  //查询类别
        //将对象解析成json数据,回传出去
        return new Gson().toJson(list);
    }
}

四、商品管理

商品展示

点击商品类别,匹配类别ID,将所有商品展示出来;在后台需要创建商品的控制层,service层,DAO层。

//header.jsp中发请求
var a = $("<a href='${pageContext.request.contextPath}/goods?action=show&tid="+data[i].t_id+"'>"+data[i].t_name+"</a>");
@WebServlet("/goods")
public class ProductController extends BaseServlet {
    private GoodsService goodsService = new GoodsServiceImpl();
    public String show(HttpServletRequest request,HttpServletResponse response){
        System.out.println("产品展示");
        //获取tid参数
        int tid = Integer.parseInt(request.getParameter("tid"));
        //再调用业务层,返回集合
        List<Product> list = goodsService.showByTid(tid);
        //产品展示完成,进行转发
        request.setAttribute("glist",list);
        return ConstUtils.FOR +"/goodsList.jsp";
    }
}
//返回到goodsList.jsp中
<c:forEach items="${glist}" var="g" varStatus="i">
    <div class="col-sm-3">
        <div class="thumbnail">
            <img src="${pageContext.request.contextPath}/${g.p_image}" width="180" height="180"  alt="小米6" />
            <div class="caption">
                <h4>商品名称<a href="${pageContext.request.contextPath}/getGoodsById?id=${g.p_id}">${g.p_name}</a></h4>
                <p>热销指数
                    <c:forEach begin="1" end="${g.p_state}">
                        <img src="image/star_red.gif" alt="star"/>
                    </c:forEach>
                </p>
                <p>上架日期:${g.p_time}</p>
                <p style="color:orange">价格:${g.p_price}</p>
            </div>
        </div>
    </div>
</c:forEach>

商品分页

将分页功能的DAO层进行测试

@Override //分页具体实现
public List<Product> selectByPage(int startIndex, int pageSize,int tid) throws SQLException {
    String sql = "select * from product where t_id=? limit ?,?";
    return runner.query(sql,new BeanListHandler<>(Product.class),tid,startIndex,pageSize);
}

封装Page,创建Page实体,并在业务层封装

public Page<Product> getPage(int tid, String current) {
    int currentPage = 1;
    int pageSize = 4;
    if(current!=null){
        currentPage = Integer.parseInt(current);  //当前页赋值
    }
    Page<Product> page = new Page<>(currentPage,pageSize);
    try {
        long totalCount = goodsDao.getTotalCount(tid);  //dao层获取总条数
        page.setTotalCount(totalCount); //设置总条数
        long pageCount = (totalCount%pageSize==0)?totalCount/pageSize:totalCount/pageSize+1;
        page.setPageCount(pageCount);   //设置总页数
        int startIndex = (currentPage-1)*pageSize; //求起始行
        //设置内容
        page.setList(goodsDao.selectByPage(startIndex,pageSize,tid));
    }catch (Exception e){
        e.printStackTrace();
    }
    return page;
}
//在控制层,返回分页信息
public String show(HttpServletRequest request,HttpServletResponse response){
    System.out.println("产品展示");
    //获取tid参数
    int tid = Integer.parseInt(request.getParameter("tid"));
    String current = request.getParameter("currentPage");
    Page<Product> page = goodsService.getPage(tid, current);

    //存储分页信息
    request.setAttribute("p",page);
    return ConstUtils.FOR +"/goodsList.jsp";
}

测试链接:http://localhost:8080/goods?action=show&tid=1&currentPage=1

展示页面: <c:forEach items="${p.list}" var="g" varStatus="i">

前端展示分页效果,使用显示页数的方式(使用bootstrap中的分页标签)

<ul class="pagination"><%--分页效果:class="pagination"--%>
    <c:if test="${p.currentPage!=1}"><%--不是第一页则可显示上一页 --%>
        <li>   <%--${param.tid}:从参数中获取tid的值--%>
            <a href="/goods?action=show&tid=${param.tid}&currentPage=${p.currentPage-1}" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
    </c:if>
    <%-- 循环从起始1到到页数量的范围  begin:起始值  end:结束值
    varStatus:取值状态 --%>
    <c:forEach begin="1" end="${p.pageCount}" varStatus="vs">
        <%-- vs.index:从begin开始取值 --%>
        <c:choose>
            <c:when test="${p.currentPage==vs.index}">
                <li class="active"><a href="/goods?action=show&tid=${param.tid}&currentPage=${vs.index}">${vs.index}</a></li>
            </c:when>
            <c:otherwise><li><a href="/goods?action=show&tid=${param.tid}&currentPage=${vs.index}">${vs.index}</a></li></c:otherwise>
        </c:choose>
    </c:forEach>
    <c:if test="${p.currentPage!=p.pageCount}"><%--不是尾页,则显示下一页--%>
        <li>
            <a href="/goods?action=show&tid=${param.tid}&currentPage=${p.currentPage+1}" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </c:if>
</ul>

五、单品展示

点击单个商品信息,进入到单个商品的详情介绍

//在goodsList.jsp中点击单品展示
<h4>商品名称<a href="${pageContext.request.contextPath}/goods?action=goodsDetail&pid=${g.p_id}">${g.p_name}</a></h4>
//展示单个商品详情
public String goodsDetail(HttpServletRequest request,HttpServletResponse response){
    //获取参数信息
    int pid = Integer.parseInt(request.getParameter("pid"));
    Product product = goodsService.showByPid(pid);  //根据pid,获取唯一信息
    request.setAttribute("goods",product);
    return ConstUtils.FOR+"/goodsDetail.jsp";
}
//goodsDetail.jsp页面展示详情信息
  <h3>产品名称:<small>${goods.p_name}</small></h3>
<div style="margin-left: 10px;">
    <p>市场价格:&nbsp;&nbsp;&nbsp;<span class="text-danger" style="font-size: 15px;">${goods.p_price}</span>&nbsp;&nbsp;&nbsp;<span class="glyphicon glyphicon-yen"></span></p>
    <p>上市时间:&nbsp;&nbsp;&nbsp;${goods.p_time}</p>
    <p>热销指数:&nbsp;&nbsp;&nbsp;
        <c:forEach begin="1" end="${goods.p_state}">
            <img src="image/star_red.gif" alt="star"/>
        </c:forEach>
    </p>
    ...

六、加入购物车

购物车模块

准备购物车的实体类,控制层,service层及DAO层

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cart {
  private int c_id;  //购物车ID
  private int u_id;  //用户ID
  private int p_id;  //商品ID
  private BigDecimal c_count;  //商品小计
  private int c_num;  //商品数量
}

思考添加购物车

点击单品展示中“添加购物车”按钮,传入pid,price,uid(登录凭证中获取-购物车控制层操作);在控制层中如果没有登录凭证,则需要重新登录,如果有,则获取到uid。

注意:如果之前添加过购物车,则修改数量和小计;如果没有添加过购物车,则添加,数量为1,小计=价格

七、总结与作业

总结

1.验证码
用户模块-验证码的展示,校验,刷新
2.记录账户(重点)
用户模块-设置cookie(登录成功且勾选记录),获取cookie(首页),清除cookie
3.商品类别管理
创建类别模块-实体类,控制层,业务层,DAO层
在首页展示类别信息
4.商品管理(重点)
商品展示-根据类别id展示商品
商品分页-分页DAO测试,封装Page,分页展示
5.单品展示
点击单个商品,根据pid获取单个商品参数

作业

1.独立完成今天的所有模块功能
2.添加购物车,不考虑修改数量情况(数量为1)

晨考

手写商品的Page在业务层封装(仅仅写业务层代码即可-封装5个属性的设置)
import java.util.List;

public class ProductPage {
    private int currentPage;        // 当前页码
    private int pageSize;           // 每页显示的记录数
    private int totalRecords;       // 总记录数
    private int totalPages;         // 总页数
    private List<Product> productList; // 当前页的商品列表

    // 构造函数
    public ProductPage(int currentPage, int pageSize, int totalRecords, List<Product> productList) {
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.totalRecords = totalRecords;
        this.productList = productList;

        // 计算总页数
        this.totalPages = (int) Math.ceil((double) totalRecords / pageSize);
    }

    // Getter 和 Setter 方法
    public int getCurrentPage() {
        return currentPage;
    }

    public void setCurrentPage(int currentPage) {
        this.currentPage = currentPage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotalRecords() {
        return totalRecords;
    }

    public void setTotalRecords(int totalRecords) {
        this.totalRecords = totalRecords;
    }

    public int getTotalPages() {
        return totalPages;
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

    public List<Product> getProductList() {
        return productList;
    }

    public void setProductList(List<Product> productList) {
        this.productList = productList;
    }
}