前言
今天为大家分享的知识点是网上书城项目的购物车拦截器的使用以及购物车其他功能的逐步完善!
购物车上的传送门:购物车的初步实现
购物车拦截器
原因:购物车的所有操作都需要拦截器
例如:加入购物车、清空、继续购买、结算、更新、删除!
如果用户未登录,则不能将购物车商品放application中,并且对于大多数网站而言,购买商品都需要先登录!
使用拦截器通常有两种方式,
1、定义一个数组,将需要被拦截的放在里面,再进行判断
String excludes []={"shopping","xxx"};
2、定义一个数组,将不需要未拦截的放在里面,再进行判断
String includes []={"book","categroy","xxx"...};
代码实现
ShoppingFilter类
package com.wangqiuping.Filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wangqiuping.entity.User;
/**
* 除去login.jsp、register.jsp、index.jsp、、/static/*、/user.action
*/
@WebFilter(filterName = "urlFiter",urlPatterns = "/*")
public class ShoppingFilter implements Filter {
public ShoppingFilter(){
super();
}
// 只要以下urls是不需要session的
private boolean validateUrl(String uri){
boolean flag = true;
String[] urls = new String[]{"login.jsp","register.jsp","ndex.jsp","static","user.action","category.action","book.action"};
for (String url : urls) {
if (uri.contains(url)){
flag = false;
break;
}
}
return flag;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 这些请求路径之外都要登录后才能访问
String uri = req.getRequestURI();
if((!"/".equals(uri)) && validateUrl(uri)) {
;String methodName = req.getParameter("methodName");
// if ("add".equals(methodName) || "pay".equals(methodName) || "list".equals(methodName)){
User user = (User) req.getSession().getAttribute("currentUser");
if(user == null){
resp.sendRedirect("/login.jsp");
return;
}
// }
}
chain.doFilter(request, response);
}
public void destroy() {
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
如果用户为空,则返回到登录界面,反之,则进行放行的操作
jsp页面必须引入的样式
<!-- 写全局样式 -->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/js/jquery-easyui-1.5.1/themes/default/easyui.css">
<!-- 定义图标的样式 -->
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/js/jquery-easyui-1.5.1/themes/icon.css">
<!--组件库源文件的js文件-->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-easyui-1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-easyui-1.5.1/jquery.easyui.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/js/common.js"></script>
<title>首页</title>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/css/fg.css" />
购物车中会使用到的ShoppingVo类
package com.wangqiuping.vo;
import java.util.Objects;
public class ShoppingVo {
// 购物车列表订单项所需数据
private String name;
private float price;
private int num;
private float total;
public void calc() {
//单个商品总价=数量*单价
this.total=num*price;
}
// 提交订单所需数据
private String consignee;
private String phone;
private String postalcode;
private String address;
private int sendType;
// 页面的所有传参字符串
private String pageStr;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public float getTotal() {
return total;
}
public void setTotal(float total) {
this.total = total;
}
public String getConsignee() {
return consignee;
}
public void setConsignee(String consignee) {
this.consignee = consignee;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPostalcode() {
return postalcode;
}
public void setPostalcode(String postalcode) {
this.postalcode = postalcode;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getSendType() {
return sendType;
}
public void setSendType(int sendType) {
this.sendType = sendType;
}
public String getPageStr() {
return pageStr;
}
public void setPageStr(String pageStr) {
this.pageStr = pageStr;
}
public ShoppingVo(String name, float price, int num, float total, String consignee, String phone, String postalcode,
String address, int sendType, String pageStr) {
super();
this.name = name;
this.price = price;
this.num = num;
this.total = total;
this.consignee = consignee;
this.phone = phone;
this.postalcode = postalcode;
this.address = address;
this.sendType = sendType;
this.pageStr = pageStr;
}
public ShoppingVo() {
super();
}
@Override
public String toString() {
return "ShoppingVo [name=" + name + ", price=" + price + ", num=" + num + ", total=" + total + ", consignee="
+ consignee + ", phone=" + phone + ", postalcode=" + postalcode + ", address=" + address + ", sendType="
+ sendType + ", pageStr=" + pageStr + "]";
}
}
购物车的删除
思路:使用a标签获取后台action层传过来的方法以及传的参数进行删除
<c:forEach items="${Shopcars}" var="s" varStatus="index">
<tr>
<td>${s.name}</td>
<td>${s.price}</td>
<td>
<input type="text" value="${s.num}">
</td>
<td>${s.total}</td>
<td>
<a href="${pageContext.request.contextPath}/shopping.action?methodName=del&pageStr=${index.index}">删除</a>
<a href="#" onclick="shoppingUpdate(this)">更新</a>
</td>
</tr>
</c:forEach>
其中varStatus在c:forEach标签中通常表示循环的状态信息
,这里把index值赋给varStatus,是用来获取application存储的List集合的下标!
删除的主要代码
<a href="${pageContext.request.contextPath}/shopping.action?methodName=del&pageStr=${index.index}">删除</a>
action层:
jsp页面需要获取的del方法
package com.wangqiuping.action;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wangqiuping.dao.OrderDao;
import com.wangqiuping.dao.OrderItemDao;
import com.wangqiuping.entity.Order;
import com.wangqiuping.entity.OrderItem;
import com.wangqiuping.entity.User;
import com.wangqiuping.util.ResponseUtil;
import com.wangqiuping.util.Result;
import com.wangqiuping.util.StringUtils;
import com.wangqiuping.vo.ShoppingVo;
import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriven;
public class ShoppingAction extends ActionSupport implements ModelDriven<ShoppingVo>{
private ShoppingVo shoppingVo=new ShoppingVo();
@Override
public ShoppingVo getModel() {
return shoppingVo;
}
//删除购物车
public String del(HttpServletRequest req, HttpServletResponse resp) {
ObjectMapper om = new ObjectMapper();
try {
User currentUser = (User) req.getSession().getAttribute("currentUser");
long uid = currentUser.getId();
String shopId = "shopId_" + uid;
String shopVoStr = (String) req.getServletContext().getAttribute(shopId);
List<ShoppingVo> Shopcars = om.readValue(shopVoStr, List.class);
int index = Integer.valueOf(shoppingVo.getPageStr());
Shopcars.remove(index);
req.getServletContext().setAttribute(shopId,om.writeValueAsString(Shopcars));
} catch (Exception e) {
e.printStackTrace();
}
return list(req,resp);
}
}
删除后还需要返回购物车页面,所以需要list方法展示购物车列表
//购物列表查询
public String list(HttpServletRequest req, HttpServletResponse resp) {
ObjectMapper om = new ObjectMapper();
try {
User currentUser = (User) req.getSession().getAttribute("currentUser");
long uid = currentUser.getId();
String shopId = "shopId_" + uid;
String shopVoStr = (String) req.getServletContext().getAttribute(shopId);
List<ShoppingVo> Shopcars = null;
if (StringUtils.isNotBlank(shopVoStr)){
Shopcars = om.readValue(shopVoStr, List.class);
}
else
{
Shopcars = new ArrayList<ShoppingVo>();
}
req.setAttribute("Shopcars",Shopcars);
}catch (IOException e) {
e.printStackTrace();
}
return "shoppingCar";
}
效果
删除前的效果
如我要删除"测试"这本书籍,点击删除a标签进行删除:
购物车的更新
思路:在a标签中增加一个点击事件,调用当前页面的函数,并传参
<c:forEach items="${Shopcars}" var="s" varStatus="index">
<tr>
<td>${s.name}</td>
<td>${s.price}</td>
<td>
<input type="text" value="${s.num}">
</td>
<td>${s.total}</td>
<td>
<a href="${pageContext.request.contextPath}/shopping.action?methodName=del&pageStr=${index.index}">删除</a>
<a href="#" onclick="shoppingUpdate(this)">更新</a>
</td>
</tr>
</c:forEach>
js调用的函数:
//更新购物车
function shoppingUpdate(ele) {
var $parent = $(ele).parent().parent();
var $price_td = $parent.children().eq(1);
var $num_td = $parent.children().eq(2);
var $total_td = $parent.children().eq(3);
var price = $price_td.html();
var num = $num_td.find(":input").val();
var total = parseInt(num) * parseFloat(price);
$total_td.html(parseFloat(total).toFixed(1));
}
效果
假如我要更改"斗破苍穹"这本书的数量,将其改为10
点击更新后的效果:
可以看到斗破苍穹更改了数量后,由原本的9.6变成了96,说明更改数据成功了
清空购物车
思路:给div容器增加点击事件、获取需要调用的clearCar函数
<tr>
<td colspan="5">
<div class="btn btn-danger" onclick="clearCar();" style="width: 200px;">清空购物车</div>
<div class="btn btn-danger shop-table-tab" style="width: 200px;" onclick="javascript:history.back();">继续购物</div>
<div class="btn btn-danger car_pay" style="width: 200px;">去结算</div>
</td>
</tr>
action层:
因为每个用户的登录后的购物车的记录都不一样,所以直接移除获取到的用户id就好
package com.wangqiuping.action;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wangqiuping.dao.OrderDao;
import com.wangqiuping.dao.OrderItemDao;
import com.wangqiuping.entity.Order;
import com.wangqiuping.entity.OrderItem;
import com.wangqiuping.entity.User;
import com.wangqiuping.util.ResponseUtil;
import com.wangqiuping.util.Result;
import com.wangqiuping.util.StringUtils;
import com.wangqiuping.vo.ShoppingVo;
import com.zking.framework.ActionSupport;
import com.zking.framework.ModelDriven;
public class ShoppingAction extends ActionSupport implements ModelDriven<ShoppingVo>{
private ShoppingVo shoppingVo=new ShoppingVo();
@Override
public ShoppingVo getModel() {
// TODO Auto-generated method stub
return shoppingVo;
}
public String clear(HttpServletRequest req, HttpServletResponse resp) {
User currentUser = (User) req.getSession().getAttribute("currentUser");
long uid = currentUser.getId();
String shopId = "shopId_" + uid;
req.getServletContext().removeAttribute(shopId);
try {
ResponseUtil.writeJson(resp,Result.SUCCESS);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
清空购物车的需要调用的函数
function clearCar() {
$.messager.confirm('确认', '您确认想要清空购物车吗?',function (t) {
if (t) {
$.ajax({
url:'${pageContext.request.contextPath}/shopping.action?methodName=clear',
success: function (data) {
location.href ='${pageContext.request.contextPath}/shopping.action?methodName=list';
}
});
}
})
}
效果
现有的购物车中的数据
当点击清空购物车按钮后的效果,会弹出一个是否确认清空的提示框,点击ok则进行清空,反之则取消
点击ok后,可以看到的效果
继续购物
思路:在div容器中增加一个点击事件 回退的一个函数
<div class="btn btn-danger shop-table-tab"
style="width: 200px;" onclick="javascript:history.back();">继续购物</div>
一个回退的函数,也就是回到上一个页面
onclick="javascript:history.back();"
效果
目前购物车中的数据
假如我要回到上一个页面,点击继续购物后再重新增加一本书
目前的数据又增加了条"冷间谍"的数据,说明继续购物成功实现了
总结
目前实现的这些购物车的功能还算比较简单,编码前先弄清楚具体业务逻辑或者思路就好,之后还会继续分享的,拜拜~