图书商城_day6遇到的难点

图书分页

在进行图书分页的时候,我们的基本思路是

  • 定义一个PageBean<E>类,表示分页中的数据,其中包含了当前的页码pc,总记录数total,每一页的记录数ps以及每一页的内容数据List<E>,以及访问参数url。
    对应代码为:
package entity;

import java.util.List;

public class PageBean<E> {
    private int pc;//当前的页码
    private int ps;//一页能够多少条记录
    private int total;//总记录数
    private String url;//访问的资源
    private List<E> pageList;

    public PageBean() {
    }

    public PageBean(int pc, int ps, int total, String url) {
        this.pc = pc;
        this.ps = ps;
        this.total = total;
        this.url = url;
    }
    //获取总页数
    public int getPage_count(){
        int page_count = total / ps;
        if(total % ps != 0){
            ++page_count;
        }
        return page_count;
    }
    public int getPc() {
        return pc;
    }

    public void setPc(int pc) {
        this.pc = pc;
    }

    public int getPs() {
        return ps;
    }

    public void setPs(int ps) {
        this.ps = ps;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public List<E> getPageList() {
        return pageList;
    }

    public void setPageList(List<E> pageList) {
        this.pageList = pageList;
    }

    @Override
    public String toString() {
        return "PageBean{" +
                "pc=" + pc +
                ", ps=" + ps +
                ", total=" + total +
                ", url='" + url + '\'' +
                ", pageList.size()=" + pageList.size() +
                '}';
    }
}

  • 然后我们在获取相关数据的时候,需要在Servlet中获取参数pc,以及设置ps,这样就可以直到要获取的是第pc页的数据。
  • 在对应的dao中获取数据的时候,利用limit ps offset (pc - 1) * ps子句来获取第pc页的记录,返回的是PageBean对象。此时我们仅仅能够设置它的pc以及ps以及pageList属性了,但是还有url以及total属性还没有设置。而要设置total属性,那么就会获取所有的记录即可。
  • 在url中,我们需要通过request来调用getContextPath()和getServletPath()方法来获取对应的路径,然后再调用getQueryString()来获取请求参数。但是需要注意的是,因为我们的页面中,页码的超链接href属性是这样的<a href="${requestScope.pageBean.url}&pc=${requestScope.pageBean.pc - 1}">上一页</a>,由于我们获取到的queryString已经包含了pc=xxx了,这时候如果我们直接使用getQueryString的话,那么就会导致这时候的超链接含有了2个pc,从而导致错误。因此为了避免出现pc=出现重复的情况,我们需要将queryString中的pc删除。因此我们首先需要获取queryString中子串&pc=的下标index,然后获取queryString = queryString.substring(0,index)子串,这时候,在和contextPath + servletPath + “?” + queryString,这样才是正确的url。注意的是servletPath和参数字符串之间需要用?分开.
  • 分页列表的设置:我们假设分页列表的长度为5,那么begin就等于当前的页码-2,而end就是当前的页码+2.此时需要注意的是溢出的问题。所以如果一开始设置的begin <= 0了,那么此时的begin需要等于1,end需要等于5,同理,如果一开始的end大于等于总页数,那么这时候的begin需要是总页数-4,而end就等于了总页数。
    对应的代码为:
<div>
	   <a href="${requestScope.pageBean.url}">首页</a>
	   <c:choose>
	          <c:when test="${requestScope.pageBean.pc eq 1}">
	              <a href="#">上一页</a>
	          </c:when>
	          <c:otherwise>
	              <a href="${requestScope.pageBean.url}&pc=${requestScope.pageBean.pc - 1}">上一页</a>
	          </c:otherwise>
	    </c:choose>
        <!--生成分页列表-->
        <c:choose>
            <c:when test="${requestScope.pageBean.page_count <= 5}">
                <!--少于5页,那么直接遍历即可-->
                <c:set var="begin" value="1"></c:set>
                <c:set var="end" value="${requestScope.pageBean.page_count}"></c:set>
            </c:when>
            <c:otherwise>
                <!--
                大于5页,那么就就在当前页的基础上,来设置begin和end
                其中begin = 当前的页码 - 2
                end = 当前的页码 + 2
                -->
                <c:set var="begin" value="${requestScope.pc - 2}"></c:set>
                <c:set var="end" value="${requestScope.pc + 2}"></c:set>
                <!--考虑是否有发生越界的问题-->
                <c:if test="${begin <= 0}">
                    <c:set var="begin" value="1"></c:set>
                    <c:set var="end" value="5"></c:set>
                </c:if>
                <c:if test="${end >= requestScope.pageBean.page_count }">
                    <c:set var="end" value="${requestScope.pageBean.page_count}"></c:set>
                    <c:set var="begin" value="${requestScope.pageBean.page_count - 4}"></c:set>
                </c:if>
            </c:otherwise>
         </c:choose>
         <c:forEach var="i" begin="${begin}" end="${end}">
             <c:choose>
                 <c:when test="${requestScope.pageBean.pc eq i}">
                     <!--当前的页码和i相等,那么超链接失效-->
                     <a href="#">[ ${i} ]</a>
                 </c:when>
                 <c:otherwise>
                     <a href="${requestScope.pageBean.url}&pc=${i}">[ ${i} ]</a>
                 </c:otherwise>
             </c:choose>


         </c:forEach>
         <c:choose>
             <c:when test="${requestScope.pageBean.pc != requestScope.pageBean.page_count}">
                 <a href="${requestScope.pageBean.url}&pc=${requestScope.pageBean.pc + 1}">下一页</a>
             </c:when>
             <c:otherwise>
                 <a href="#">下一页</a>
             </c:otherwise>
         </c:choose>
         <a href="${requestScope.pageBean.url}&pc=${requestScope.pageBean.page_count}">尾页</a>
</div>

前台过滤

客户端: 如果当前的用户还没有登录,那么他只能进行查看,但是不可以购买商品,或者将商品加入到购物车。所以这时候我们需要利用到了Filter,然后再web.xml中配置拦截的路径,由于是购买商品,加入购物车需要拦截,所以对于url为/OrderServlet,/CartServlet的都要进行拦截,然后再对应的filter中利用session判断是由已经登录,如果没有登录,那么就给出对应的提示信息,返回到商品的界面,否则,就放行.对应Filter代码:

package web.filters;

import entity.Book;
import entity.Customer;
import service.BookService;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.sql.SQLException;

/*
只有在登录之后,才可以进行购买,否则无法进行购买
 */
public class BuyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //判断是否已经登陆了
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        Customer customer = (Customer)request.getSession().getAttribute("customer");
        if(customer == null){
            //没有登录,那么就需要给出对应的提示信息,转发到对应的界面中
            request.setAttribute("msg","没有登录,无权进行对应操作");
            String value = request.getParameter("id");//获取图书的id
            if(value == null){
                throw new RuntimeException("BuyFilter中,没有传递参数id");
            }
            int id = Integer.parseInt(value);
            Book book = null;
            try {
                book = new BookService().queryById(id);
            } catch (SQLException e) {
                e.printStackTrace();
            }
            //因为需要返回到对应的商品界面,所以我们需要获取对应的商品的id,然后将这个
            //商品保存到request域中,否则,如果没有执行setAttribute这一步,直接进行转发
            //操作,那么就会导致转发之后的界面没有看到商品
            request.setAttribute("book",book);
            request.getRequestDispatcher("/jsps/desc.jsp")
                    .forward(request,servletResponse);
        }else{
            filterChain.doFilter(request,servletResponse);//已经登录了,那么就放行
        }

    }

    @Override
    public void destroy() {

    }
}

web.xml中的配置信息:

<filter>
     <filter-name>BuyFilter</filter-name>
     <filter-class>web.filters.BuyFilter</filter-class>
 </filter>
 <filter-mapping>
     <filter-name>BuyFilter</filter-name>
     <!--没有登录的时候,没有办法执行加入购物车,或者购买的操作-->
     <url-pattern>/OrderServlet</url-pattern>
     <url-pattern>/CartServlet</url-pattern>
 </filter-mapping>

管理员:对于管理员来说,只要没有登录,就什么功能都不可以实现,即在没有登录的时候,点击某一项功能的时候,就会给出提示,然后转发到jsps/admin/index.jsp界面。
在这里插入图片描述
但是我们却可以进行登录,注册功能,由于登录,注册方法也是定义在AdminServlet中,而且我们定义的拦截器拦截的url也是/AdminServlet,那么这时候我们还需要在拦截器中利用request,来获取参数method的值,这样我们才可以判断是否为我们拦截的方法。

同时点击添加图书的时候,我们是直接来到了jsps/admin/addBook.jsp,所以拦截的路径中也需要添加这个值
对应的代码为:

public class AdminFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //管理员还没有登录的时候,没有权力进行相应的修改
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        String method_name = request.getParameter("method");
       //判断method_name是否和下面中的一项相同,如果是,说明不是我们要拦截的方法
        boolean isNotFilter = false;
        if(method_name != null){ //有传递了method参数
            isNotFilter = "login".equals(method_name) || "register".equals(method_name);
        }
        Customer customer = (Customer)request.getSession().getAttribute("customer");
        if(customer != null || isNotFilter){
            //没有登录,但是不是要拦截的方法,或者已经登录了,那么就放行
            filterChain.doFilter(request,servletResponse);
        }else{
        //没有登录,并且是需要被拦截的方法
        //或者是,没有登录,并且没有传递methdo参数,但是url为jsps/admin/addBook.jsp(前往添加图书界面)
        //同样需要拦截
            request.setAttribute("msg","没有登录,无权访问");
            request.getRequestDispatcher("/jsps/admin/index.jsp")
                    .forward(request,servletResponse);
        }
    }

    @Override
    public void destroy() {

    }
}

web.xml中:

<filter>
    <filter-name>AdminFilter</filter-name>
    <filter-class>web.filters.AdminFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>AdminFilter</filter-name>
    <!--没有登录的时候,没有办法执行相关的操作-->
    <url-pattern>/AdminServlet</url-pattern>
    <!--拦截添加图书的界面-->
    <url-pattern>/jsps/admin/addBook.jsp</url-pattern>
</filter-mapping>

倒计时t秒之后,自动登录中定时器只执行了1次

而当我们转发到对应的界面desc.jsp的时候,因为提示信息msg不为空,那么我们就会给出对应的提示信息,提示还剩下多少秒,就会前往登录界面,这时候我们同样需要调用setInterval定时器来进行操作。但是结果定时器只执行了一次。对应的代码是这样的:

<script type="text/javascript">
    var span = document.getElementById("time_show");
    var t = 5;
    function countDown(){
        --t;
        if(t <= 0){
            window.location.href = "/jsps/login.jsp"; //倒计时结束之后,修改当前界面的location
            return;
        }
        span.innerHTML = "还剩下" + t + "秒自动跳转到登录界面";
    }
    if(span.style.visibility == "visible"){ //如果span的样式中的visibility是可见的,那么就执行定时器操作(因为考虑到msg为空的实况,所以如果msg为空,span是不可见的)
        span.innerHTML = "还剩下" + t +"秒自动跳转到登录界面";
        setInterval(countDown(),1000);//这样的话导致定时器只执行一次
        //setInterval(countDown,1000);//正确的代码
    }
</script>

原来是因为setInterval(countDown(),1000)中的countDown()导致的,我们只需要将countDown中的括号删除,就可以成功实现了我们的目的,当5秒之后,就会自动来到了登录界面了。所以正确的代码只需要将setInterval(countDown(),1000)改成setInterval(countDown,1000)即可

点击某一个按钮,在页面中间出现一个输入界面

以下面的例子为例,点击添加分类的按钮,就会在页面的中间出现一个输入框,这时候我们同样是需要利用标签中的样式中的visibility的属性,只要我们点击了添加分类的按钮,就会将对应标签中的样式的visibility属性值编程visible,一旦提交了表单之后,就重置为hidden
在这里插入图片描述

对应代码:

<script type="text/javascript">
    window.onload = function(){
        var add = document.getElementById("add");//添加分类的按钮
        var add_form = document.getElementById("add_form");//提交表单
        add.onclick = function(){
            add_form.style.visibility = "visible";//一旦点击添加分类按钮,设置表单可见
        }
        var add_submit = document.getElementById("add_submit");
        add_submit.onclick = function(){
            add_form.style.visibility = "hidden";//表单提交之后,设置表单隐藏不可见
        }
    }
</script>

总结

这次做的图书商城,主要是运用了servlet + jsp + jstl + ajax + js + MySQL,以及filter进行过滤,在实现中也运用了文件上传,分页,订单未支付的时候定时器的知识。虽然整个项目可能功能还有待改进和完善(比如在支付订单的时候,还没有真正的支付)的地方,而且项目也相对简单,但是自己去做的时候,还是花了较多时间去做,也有了一定的收获,比如文件上传中,只能获取一次表单项,当在获取一次表单项之后,再次解析获取表单项的时候,会发现FileItem的列表元素为0,这是我在平时的学习中是没有遇到的。所以总体来说,完成这个项目,我还是有一些进步吧。

源码地址:https://gitee.com/MyGit_Test/simple-book-mall

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值