基于Session的购物车的设计与实现

学习java Web会话基础时,设计了一个简易的购物车 。

此demo使用了当前比较流行的bootsrrap前端框架,设计的效果图如下:

网站提供的购置主页


个人购物车页面




登录与注销页面




本购物车是基于Session实现的,充当一个临时信息存储平台。实现了如下要求:

基本的添加、删除与清空购物车

购物车中可以更新商品的数量

自动计算购物车商品的价格

应用Filter实现中文乱码处理

应用Filter实现添加购物车访问控制:进入主页后,单击“加入购物车”链接,如果用户尚未登录则直接跳转到登录页面,登录后用户查看购物车或者继续购物,也可以付账。

     用户的登录与注销以及验证码。


1.模拟商品数据库(BookDB类)

商品Book类,需要序列化,因为book需要存放在session中。

package com.lilei.bean;

import java.io.Serializable;

public class Book implements Serializable {
	private static final long serialVersionUID = 1L;
	private String id;
	private String name;
	private double price;

	public Book() {
	}

	public Book(String id, String name, double price) {
		this.id = id;
		this.name = name;
		this.price = price;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getPrice() {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return name + "   " + price + "   ";
	}	
	

}

商品信息存放的数据库,为简便起见,我将商品简单的存储在Map中。(当然,一般都是应用数据库存放商品信息的)

package com.lilei.dao;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

import com.lilei.bean.Book;
public class BookDB {
private static Map<String, Book> books = new LinkedHashMap<String, Book>();
	static {
		    books.put("1", new Book("1", "javaweb开发",88));
		    books.put("2", new Book("2", "jdbc开发",68));
			books.put("3", new Book("3", "java开发",48));
			books.put("4", new Book("4", "struts开发",108));
			books.put("5", new Book("5", "spring开发",168));
		}
		
		public static Collection<Book> getAll() {
			return books.values();
		}
		public static Book getBook(String id) {
			return books.get(id);
		}
	}

然后将所有商品存放入session中,用于展示商品。

package com.lilei.servlet;

import java.io.*;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import com.lilei.bean.Book;
import com.lilei.dao.BookDB;

public class ListBookServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        HttpSession session = req.getSession();
        //将获取的商品信息存入session
        Collection<Book> books = BookDB.getAll();
        req.setAttribute("books", books);
        req.getRequestDispatcher("/listBook.jsp").forward(req, resp);
        return;
    }
}

2.购物车

购物车类(ShopCart类)内置了一个Map<Book, Integer>,并进行了一层封装,主要用来映射存放商品和它的数量,好用于在个人购物车页面展示。

package com.lilei.bean;

import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

public class ShopCart implements Serializable{
    private Map<Book, Integer> map;

    public ShopCart() {
        map = new LinkedHashMap<>();
    }

    public Map<Book, Integer> getMap() {
        return map;
    }

    public void setMap(Map<Book, Integer> map) {
        this.map = map;
    }

    public boolean containsKey(Book book){
        return map.containsKey(book);

    }

    public Integer get(Book book) {
        return map.get(book);
    }

    public Integer put(Book book, Integer count){
        return map.put(book, count);
    }

    public Integer remove(Book book){
        return map.remove(book);
    }

    public boolean isEmpty(){
        return map.isEmpty();
    }

    public void clear(){
        map.clear();
    }

    public Set<Map.Entry<Book, Integer>> entrySet(){
        return map.entrySet();
    }
}

CartServlet的主要职责是接收页面请求并进行逻辑处理。根据接收参数type的值进行”添加”、“增加”,”减少”,“清空”的操作,如图所示。



其编码如下:

package com.lilei.servlet;

import java.io.*;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import com.lilei.bean.Book;
import com.lilei.bean.ShopCart;
import com.lilei.dao.BookDB;

public class CartServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String type = req.getParameter("type");
        //获取Session
        HttpSession session = req.getSession();
        //获取购物车
        ShopCart cart = (ShopCart) session.getAttribute("cart");
        //标识购物车是否为空
        boolean purFlag = true;
        //如果购物车不存在就创建
        if (cart == null) {
            cart = new ShopCart();
        }

        //往购物车添加商品
        if(type.equals("add")){
            purFlag = false;
            String id = req.getParameter("id");
            Book book = BookDB.getBook(id);
            if(cart.containsKey(book)){
                int count = cart.get(book) + 1;
                cart.put(book, count);
            }else{
                cart.put(book, 1);
            }

        //在购物车中删除商品
        }else if(type.equals("remove")){
            String id = req.getParameter("id");
            Book book = BookDB.getBook(id);
            cart.remove(book);
            if(cart.isEmpty()){
                purFlag = true;
            }else{
                purFlag = false;
            }
        //修改购物车
        }else if(type.equals("update")){
            purFlag = false;
            String direct = req.getParameter("direct");
            String id = req.getParameter("id");
            Book book = BookDB.getBook(id);
            Integer count = cart.get(book);
            if(direct.equals("plus")){
                count++;
                cart.put(book, count);
            }else{
                count--;
                cart.put(book, count);
                //count为0则删除此商品
                if(count==0){
                    cart.remove(book);
                    //当删除此商品时判断此时购物车是否还有商品,如果没有商品则需置purFlag = true
                    if(cart.isEmpty()){
                        purFlag = true;
                    }
                }
            }


        //清空购物车
        }else if(type.equals("clear")){
            cart.clear();
        //其他情况
        }else{
            if(!cart.isEmpty()){
                purFlag = false;
            }
        }
        //计算商品总价
        Double sumPrice = 0d;
        Iterator<Map.Entry<Book, Integer>> it = cart.entrySet().iterator();
        while(it.hasNext()) {
            Map.Entry<Book, Integer> entry = it.next();
            Book book = entry.getKey();
            Integer count = entry.getValue();
            sumPrice = sumPrice + book.getPrice() * count;
        }
        session.setAttribute("purFlag", purFlag);
        session.setAttribute("sumPrice",sumPrice);
        session.setAttribute("cart", cart);
        resp.sendRedirect("/myCart.jsp");
        return ;
    }
}

3.用户登录与注销

用户登录时开启session,将用户信息放入session,注销时清除session。(这里硬编码了账号cat,密码123)

package com.lilei.servlet;

import java.io.*;

import javax.servlet.ServletException;
import javax.servlet.http.*;

import com.lilei.bean.User;

public class LoginServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String checkCode = request.getParameter("check_code");
        String savedCode = (String) request.getSession().getAttribute(
                "check_code");
        PrintWriter pw = response.getWriter();
        //设置账号密码
        if (("cat").equals(username) && ("123").equals(password)
                && checkCode.equals(savedCode)) {
            User user = new User();
            user.setUsername(username);
            user.setPassword(password);
            session.setAttribute("user", user);
            response.sendRedirect("/ListBookServlet");
        } else if (checkCode.equals(savedCode)) {
            pw.write("用户名或密码错误,登录失败");
        } else {
            pw.write("验证码错误");
        }
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

产生图形验证码CheckServlet类(在你前端的页面<img src="/checkServlet">)

 package com.lilei.servlet;
 import java.io.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 import java.awt.*;
 import java.awt.image.*;
 import javax.imageio.ImageIO;
 public class CheckServlet extends HttpServlet
 {
 	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static int WIDTH = 60;  //验证码图片宽度
 	private static int HEIGHT = 20;  //验证码图片高度
 	public void doGet(HttpServletRequest request,HttpServletResponse response) 
 			throws ServletException,IOException{		
 		HttpSession session = request.getSession();
 		response.setContentType("image/jpeg");
 		ServletOutputStream sos = response.getOutputStream();
		//设置浏览器不要缓存此图片
 		response.setHeader("Pragma","No-cache");
 		response.setHeader("Cache-Control","no-cache");
 		response.setDateHeader("Expires", 0);
		//创建内存图象并获得其图形上下文
 		BufferedImage image = 
 			new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); 
 		Graphics g = image.getGraphics();
		//产生随机的认证码
 		char [] rands = generateCheckCode();
		//产生图像
 		drawBackground(g);
 		drawRands(g,rands);
 		g.dispose();
		//将图像输出到客户端
 		ByteArrayOutputStream bos = new ByteArrayOutputStream();
 		ImageIO.write(image, "JPEG", bos);
 		byte [] buf = bos.toByteArray();
 		response.setContentLength(buf.length);
 		sos.write(buf);
 		bos.close();
 		sos.close();
		//将当前验证码存入到Session中
 		session.setAttribute("check_code",new String(rands));
 	}
	 //生成一个4字符的验证码
 	private char [] generateCheckCode()
 	{
		//定义验证码的字符表
 		String chars = "0123456789abcdefghijklmnopqrstuvwxyz";
 		char [] rands = new char[4];
 		for(int i=0; i<4; i++)
 		{
 			int rand = (int)(Math.random() * 36);
 			rands[i] = chars.charAt(rand);
 		}
 		return rands;
 	}
 	private void drawRands(Graphics g , char [] rands)
 	{
 		g.setColor(Color.BLACK);
 		g.setFont(new Font(null,Font.ITALIC|Font.BOLD,18));
		//在不同的高度上输出验证码的每个字符
 		g.drawString("" + rands[0],1,17);
 		g.drawString("" + rands[1],16,15);
 		g.drawString("" + rands[2],31,18);
 		g.drawString("" + rands[3],46,16);
 		System.out.println(rands);
 	}
 	private void drawBackground(Graphics g)
 	{
		//画背景
		g.setColor(new Color(0xDCDCDC));
 		g.fillRect(0, 0, WIDTH, HEIGHT);
		//随机产生120个干扰点
 		for(int i=0; i<120; i++)
 		{
 			int x = (int)(Math.random() * WIDTH);
 			int y = (int)(Math.random() * HEIGHT);
 			int red = (int)(Math.random() * 255);
 			int green = (int)(Math.random() * 255);
 			int blue = (int)(Math.random() * 255);
 			g.setColor(new Color(red,green,blue));		
 			g.drawOval(x,y,1,0);
 		}
 	}
 }


4.LoginFilter过滤器

在你添加商品到购物车时,拦截请求,用户登录了才能添加购物车,否则进入登录页面。

package com.lilei.filter;


import com.lilei.bean.User;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginFilter 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;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        User user = (User) request.getSession().getAttribute("user");
        if(user == null){
            response.sendRedirect("/login.jsp");
            return ;
        }
        filterChain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

5.其他还有一些业务像清空购物车、结算等功能,就不一一列举出来了。我把demo源码放出来,供有需之士参考吧。

demo源码下载   内含源码以及发布的war包,可直接放到tomcat下运行。

注意:此demo是在IDEA中编写,不能直接导入到myeclipse中,介意者慎点!






阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页