一、项目介绍
今天是1024哦,忙碌的程序猿们加班之余不要忘了来优家益购买适合自己的商品哦,今天给大家打8.8折,本商城有配件、服饰、家用三大种类商品,满足程序猿们的日常需求。
优家益购分为用户、购物车、订单、后台四大模块;注册采用Ajax技术实现注册用户名是否重复,登录包含验证码的校检,商城采用过滤器技术,必须登录才能加购物车和访问其他页面,提交订单时通过session拿到登录用户名,然后显示默认手机号和地址,每个用户有自己的订单和购物车,用户有两种权限,1是普通用户,2是管理员,只有管理员才能访问后台和查看所有用户的订单,后台可以对商品进行增删改查。
优家益购——JavaWeb项目(Jsp+Servlet+MySQL+tomcat)
页面展示
首页
登录
注册
购物车
提交订单
订单查询
订单详情
后台商品管理
编辑商品
二、项目模块
1.用户模块:注册(ajax验证用户名是否存在),登录(验证码的校检),因为商城使用过滤器技术,用户只有登录才能进入其他模块
2.购物车模块:用户可以往购物车里加入商品、删除商品以及清空购物车(通过url传参,设置session,后端操作数据库存储,前端通过el表达式和jstl标签拿值)
3.订单模块:提交订单页可以显示登录用户的默认手机号和收货地址(提交订单页面采用bootstrap响应式布局,点击提交按钮的时候,通过购物车集合的session同时往数据库的订单表和订单详情表添加数据,再把购物车标清空;订单查询页只有管理员才能查询所有的订单,普通用户只能查询自己的订单;订单详情页的数据通过查询数据库订单详情表封装商品对象显示)
4.后台模块:管理员可以对商品进行增删改查,只有管理员才有权限进入后台管理
三、涉及技术
JSP、Servlet、Html、CSS、JS、Bootstrap、JDBC、EL、JSTL、Ajax
dao层:与数据库交互
domain层:实体类
service层:业务类
util层:工具类
web层:过滤器及Servlet
四、数据库设计
costume:服饰表
household:家用表
indent:订单表
indents:订单详情表
mountings:配件表
shopping:购物车表
user:用户表
五、项目细节
1.首页访问数据库设置商品集合和购物车的session,通过el表达式和jstl显示数据
<%//查询所有配件信息MountingsDao mDao = new MountingsDao();List<Mountings> mous = mDao.queryAllMous("");session.setAttribute("mous", mous);//查询所有服饰信息CostumeDao cDao = new CostumeDao();List<Costume> coss = cDao.queryAllCoss("");session.setAttribute("coss", coss);//查询所有家用信息HouseholdDao hDao = new HouseholdDao();List<Household> hous = hDao.queryAllHous("");session.setAttribute("hous", hous);//查询所有购物车信息String username = (String) request.getSession().getAttribute("username");User user = new UserDao().checkUsername(username);ShoppingDao sDao = new ShoppingDao();List<Shopping> shops = null;if(user != null) {shops = sDao.queryAllShops(user);}session.setAttribute("shops", shops);%>//遍历商品<c:forEach items="${mous}" var="mou" varStatus="i"><li><a href="shop?msg=add&id=${mou.id}&name=${mou.name}&price=${mou.price}&picture=${mou.picture}&commodity_type=${modity_type}"><i class="iconfont icon-ic_jiarugouwuche gwc"></i></a><img src="${mou.picture}" alt=""><p>${mou.name}</p><span>¥<i>${mou.price}</i></span></li></c:forEach>
2.通过jstl标签库判断用户权限是否为管理员,el表达式拿session数据
<c:if test="${user.getU_type() == 2}"><div align="center"><a href="managerServlet?action=list"><p style="color: #f0f1eb">后台管理</p></a></div></c:if>
同理判断是否登录
<c:if test="${username eq null}"><a href="LoginRegister.html"><p style="color: #f0f1eb">登录</p></a></c:if><c:if test="${username ne null}"><div align="center"><p style="color: white">${username}</p></div><a href="quitServlet" onclick="showYesMsg()"><br/><p style="color: #f0f1eb">退出</p></a></c:if>
同理判断购物车是否为空
<c:if test="${shops.size() eq 0}"><div class="operation"><div class="del" onclick="showNoMsg()">清除购物车</div><div class="submit" onclick="showNoMsg()">提交订单</div></div></c:if><c:if test="${shops.size() ne 0}"><div class="operation"><a href="shop?msg=delAll&id=1&name=1&price=1&picture=1&commodity_type=1"><div class="del" onclick="showYesMsg()">清除购物车</div></a><a href="indent.jsp"><div class="submit" onclick="showYesMsg()">提交订单</div></a></div></c:if>
3.遍历购物车商品并拿到购物车商品总价,把总价和数量设置为session
<!-- 购物车列表 --><div class="shoppingCart" style="color: #f0f1eb"><div class="title"><i class="iconfont icon-jiantouarrow483"></i><span class="text">我的购物车</span><span><i>${shops.size()}</i>件商品</span></div><div class="pro_list" ><ul><c:forEach items="${shops}" var="shop" varStatus="i"><li><a href="shop?msg=del&id=${modity_id}&name=${shop.name}&price=${shop.price}&picture=${shop.picture}&commodity_type=${modity_type}"onclick="showYesMsg()"><i class="iconfont icon-jianhao sub" style="color: #f0f1eb"></i></a><div class="content"><img src="${shop.picture}"/><div class="center"><p>数量<i>${shop.num}</i></p><p class="title">${shop.name}</p></div><div class="price"><span>小计:</span><span class="xj">${shop.price*shop.num}</span></div></div></li><c:set value="${num+shop.num}" var="num" scope="session"/><c:set value="${sum+shop.price*shop.num}" var="sum" scope="session"/></c:forEach></ul></div><div class="total"><p><span class="left">总计</span><span class="right"><i class="sum">${sum}</i></span></p></div></div>
注意每次重新访问index.jsp清除session
//清空总价格和数量缓存session.setAttribute("sum", 0);session.setAttribute("num", 0);
4.ajax判断用户名是否存在
var flag;function checkUser() {//1.创建核心对象var xmlhttp;if (window.XMLHttpRequest){// code for IE7+, Firefox, Chrome, Opera, Safarixmlhttp=new XMLHttpRequest();}else{// code for IE6, IE5xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}//2. 建立连接var username = document.getElementById("username").value;//xmlhttp.setRequestHeader("If-Modified-Since", "0");//get清空缓存//POST清空缓存// xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");xmlhttp.open("GET","checkUserServlet?username=" + username,true);//3.发送请求xmlhttp.send();//4.接受并处理来自服务器的响应结果//获取方式 :xmlhttp.responseText//什么时候获取?当服务器响应成功后再获取//当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange。xmlhttp.onreadystatechange=function(){//判断readyState就绪状态是否为4,判断status响应状态码是否为200if (xmlhttp.readyState==4 && xmlhttp.status==200){//获取服务器的响应结果var responseText = xmlhttp.responseText;var msg = document.getElementById("sp_username");if("success" == responseText){msg.innerHTML = "该用户名可以使用";flag = true;} else {msg.innerHTML = "该用户已存在,请重新输入用户名";flag = false;}}}}function checkForm(){return flag;}
5.过滤器判断是否登录,拦截请求,及设置请求响应编码(项目遇到的最大的坑就是这个了,假如没登录不放行,就会出现一个无限登录bug,点哪里请求被拦截进入登录页面,登录之后再点那个请求照样会跳到登录页面,同时浏览器会有缓存,要同时清缓存和放行才能修复bug)
@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {//1.强制转换HttpServletRequest request = (HttpServletRequest) req;//2.获取资源请求路径String uri = request.getRequestURI();//3.判断是否包含登录相关资源路径,要注意排除掉 css/js/图片/验证码等资源if(uri.contains("index.jsp") || uri.contains("login.html") || uri.contains("registerServlet")|| uri.contains("register.html") || uri.contains("loginServlet") || uri.contains("LoginRegister.html")||uri.contains("/css/") || uri.contains("/js/") || uri.contains("checkUserServlet")|| uri.contains("/img/") || uri.contains("checkCodeServlet")){//包含,用户就是想登录。放行chain.doFilter(req, resp);}else{//不包含,需要验证用户是否登录//3.从获取session中获取userObject user = request.getSession().getAttribute("username");if(user != null){//登录了。放行chain.doFilter(req, resp);}else{//没有登录。跳转登录页面request.setAttribute("login_msg","您尚未登录,请登录");request.getRequestDispatcher("LoginRegister.html").forward(request,resp);//也要放行chain.doFilter(req, resp);}}}
6.首页通过url传参跳转Servlet添加商品到购物车,再重定向到首页
<c:forEach items="${mous}" var="mou" varStatus="i"><li><a href="shop?msg=add&id=${mou.id}&name=${mou.name}&price=${mou.price}&picture=${mou.picture}&commodity_type=${modity_type}"onclick="showYesMsg()"><i class="iconfont icon-ic_jiarugouwuche gwc"></i></a><img src="${mou.picture}" alt=""><p>${mou.name}</p><span>¥<i>${mou.price}</i></span></li></c:forEach>
7.根据下单时间和用户id生成订单号
<%//获取用户sessionUser user = (User) request.getSession().getAttribute("user");//将int类型转换为StringString u_id = user.getU_id() + "";//获取当前时间Date now = new Date();//规定时间格式DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//转换成指定格式的字符串String date = df.format(now);//设置当前时间的sessionrequest.setAttribute("date", date);//规定时间格式DateFormat df2 = new SimpleDateFormat("yyyyMMddHHmmss");//生成订单号String indent_id = df2.format(now) + u_id;//设置订单号的sessionrequest.setAttribute("indent_id", indent_id);%>
8.form变得input输入框的值不能修改
<input type='text' name='num' readonly unselectable='on' value='${num}' required><br>
9.提交订单的时候通过购物车的session同时操作数据库的订单表和订单详情表
package com.beizhen.web.servlet;import com.beizhen.dao.UserDao;import com.beizhen.domain.Indent;import com.beizhen.domain.Indents;import com.beizhen.domain.Shopping;import com.beizhen.domain.User;import com.beizhen.service.IndentService;import com.beizhen.service.IndentsService;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.List;/*** @author : Bei-Zhen* @date : -10-22 3:21*/@WebServlet("/indent")public class IndentServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取请求参数String address = request.getParameter("address");String telnum = request.getParameter("telnum");String num = request.getParameter("num");String indent_date = request.getParameter("indent_date");String price = request.getParameter("price");String username = (String)request.getSession().getAttribute("username");String indent_id = request.getParameter("indent_id");User user = new UserDao().checkUsername(username);Indent indent = new Indent(0,address,telnum,Integer.parseInt(num),indent_date,Double.parseDouble(price),user.getU_id(),indent_id);//往数据库添加订单new IndentService().addInd(indent,user);//获取购物车所有商品List<Shopping> shops = (List<Shopping>) request.getSession().getAttribute("shops");//遍历购物车集合for (int i = 0; i < shops.size(); i++) {//封装订单详情对象Indents indents = new Indents(0,shops.get(i).getCommodity_id(),shops.get(i).getCommodity_type(),shops.get(i).getNum(),indent_id,user.getU_id());//往数据库添加订单详情new IndentsService().addInd(indents,user);}//重定向到订单查询页面response.sendRedirect("show_indent.jsp");}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doPost(request, response);}}
10.通过url传参订单号,根据所有订单详情查询订单详情展示集合,设置订单详情展示集合session,在订单详情页显示数据
@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取参数String indent_id = request.getParameter("indent_id");//根据订单号查询所有相关的订单的详情List<Indents> indents = new IndentsService().selInds(indent_id);//设置订单号sessionrequest.getSession().setAttribute("indent_id",indent_id);//封装订单详情展示集合List<Indentdetails> indentdetails = new IndentsService().selIndtails(indents);//设置订单详情展示集合sessionrequest.getSession().setAttribute("indentdetails",indentdetails);//重定向到订单详情页response.sendRedirect("indents.jsp");}/*** 根据所有订单详情查询订单详情展示集合* @param indss 订单详情集合* @return 订单详情展示对象集合*/public List<Indentdetails> selIndtails(List<Indents> indss){//订单详情展示对象集合List<Indentdetails> indentdetails = new ArrayList<>();//遍历订单详情集合for (int i = 0; i < indss.size(); i++) {//根据商品id和商品类型查询具体商品Commodity com = new CommodityDao().queryComs(indss.get(i).getCommodity_id(),indss.get(i).getCommodity_type());//订单详情展示对象Indentdetails indetails = new Indentdetails();//分别给它赋值indetails.setName(com.getName());indetails.setPicture(com.getPicture());indetails.setPrice(com.getPrice());indetails.setNum(indss.get(i).getCommodity_num());//添加到集合indentdetails.add(indetails);}return indentdetails;}
六、项目共享
/download/qq_33591873