家居网购项目--项目总结

饭宝  金牌会员 | 2024-5-16 09:27:55 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 905|帖子 905|积分 2715

家居网购项目--项目总结

家居网购项目总结
  1. 本项目是基于java的前后端项目,使用原生的Servlet + jsp 开发。
  2. 主要的技术点:
  3. 1.登录注册功能:使用kaptcha去生成验证码,使用邮件完成注册
  4. 2.使用拦截器拦截用户请求,限制用户访问权限
  5. 3.使用ThreadLocal 确保是同一线程来完成事务的提交和回滚
  6. 4.使用MVC模式使用DAO-Serice-Servlet进行分层
  7. 5.使用数据模型entity Cart.java 将数据存入session中来进行购物车的存储
  8. 6.使用ajax对页面进行局部刷新
  9. 7.使用json格式进行前后端数据的交换
  10. 8.前端使用jsp进行服务器渲染
  11. 9.数据库使用Mysql
复制代码
项目预备

1.一些工作环境的设置,IDE使用IntellijIDEA,jdk1.8,下面先容一些关于此项目的主要模块后端代码的实现部分
2.搭建项目的框架

注册与登录功能的实现

注册和登录功能是每个网站最基本的功能,实现的主要难点我觉得在于正则表达式的编写。
  1. //完成对用户名的校验
  2.    var usernamePattern = /^\w{6,10}$/;
  3. //验证邮箱
  4.     var emailVal = $("#email").val();
  5.     var emailPattern = /^[\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+$/
  6.     if (!emailPattern.test(emailVal)) {
  7.         $("span[class= 'errorMsg']").text("电子邮箱格式不正确");
  8.         return false;
  9.     }
  10. //...
复制代码
用户表实现

暗码MD5加密

为了保证安全,暗码不能明文的在网络中进行传输,也不能以明文的形式存到数据库中。
存在数据库的暗码 = MD5( 暗码 ) 防止暗码泄露
Kaptcha 天生验证码

导入 Kaptcha.jar 后,服务器会天生的验证码并保存在session中,我们必要通过 com.google.code.kaptcha下的  Constants.java类 的 属性 拿到对应的验证码
  1. public static final String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";//静态属性
  2. //获取验证码
  3.   String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
复制代码
并且为了防止验证码被重复使用必要立即删除验证码
  1. //立即删除验证码防止验证码被重复使用
  2. request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
复制代码
过滤器的使用

本项目有两个过滤器,分别是:
1.用于用户权限验证的 AuthFilter.java
2.用于配合JDBC提交和回滚事务的 TransactionFilter.java
使用过滤器必要在web.xml文件中设置相关参数,并且过滤器一样平常设置的优先级较高(高于Servlet的设置)
  1.     <filter>
  2.         <filter-name>AuthFilter</filter-name>
  3.         <filter-class>com.code_study.furns.filter.AuthFilter</filter-class>
  4.         <init-param>
  5.             
  6.             <param-name>excludedUrls</param-name>
  7.             <param-value>/views/manage/manage_login.jsp,/views/member/login.jsp</param-value>
  8.         </init-param>
  9.         <init-param>
  10.             
  11.             <param-name>interceptUrls</param-name>
  12.             <param-value>
  13.       /views/cart/*
  14.       ,/views/manage/*
  15.       ,/views/member/*
  16.       ,/views/order/*
  17.       ,/cartServlet
  18.       ,/manage/furnServlet
  19.       ,/orderServlet
  20.             </param-value>
  21.         </init-param>
  22.     </filter>
  23.     <filter-mapping>
  24.         <filter-name>AuthFilter</filter-name>
  25.         
  26.         <url-pattern>/views/cart/*</url-pattern>
  27.         <url-pattern>/views/manage/*</url-pattern>
  28.         <url-pattern>/views/member/*</url-pattern>
  29.         <url-pattern>/views/order/*</url-pattern>
  30.         <url-pattern>/cartServlet</url-pattern>
  31.         <url-pattern>/manage/furnServlet</url-pattern>
  32.         <url-pattern>/orderServlet</url-pattern>
  33.     </filter-mapping>
复制代码
使用拦截器AuthFilter来拦截所有的用户请求,判定请求中的session是否存在有效的member或者admin,如果都没有就请求转发到登岸页面,如果有,根据member或者admin对应权限判定 放行的资源是否包含 请求的url。如果不包含设置的放行url 就走验证
  1. <param-name>excludedUrls</param-name>
  2. <param-value>/views/manage/manage_login.jsp,/views/member/login.jsp</param-value>
复制代码
Servlet归并

将Servlet归并成一个BasicServlet——利用了模板设计模式+动态绑定+反射
  1. //解决接收到的数据中文乱码问题
  2.         request.setCharacterEncoding("utf-8");
  3. //获取action不同的值
  4.         String action = request.getParameter("action");
  5.         try {
  6. //反射获取servlet对应的方法的对象
  7.             Method declaredMethod = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
  8.             declaredMethod.invoke(this, request, response);
  9.         } catch (Exception e) {
  10. //将发生的异常继续throw
  11.             throw new RuntimeException(e);
  12.         }
复制代码
分页表现

将分页表现抽象成一个数据模型entity Page.java
  1.     //每页显示多少条记录其他地方也可以使用
  2.     public static final Integer PAGE_SIZE = 4;//表示 每页显示几条记录
  3.     private Integer pageNo;//表示 第几页
  4.     private Integer totalRow;//表示 多少条记录
  5.     private Integer pageTotalCount;//表示 共有多少页 -> totalRow / pageSize
  6.     private List<T> items;//当前页显示的数据
  7.     private String url;//分页导航的字符串
  8.     private Integer pageSize = PAGE_SIZE;//每页显示几条记录
复制代码
进行分页的方法page
  1. public Page<Furn> page(int pageNo, int pageSize) {
  2.         Page<Furn> page = new Page<>();
  3.         page.setPageNo(pageNo);
  4.         page.setPageSize(pageSize);
  5.         int totalRow = furnDAO.getTotalRow();
  6.         page.setTotalRow(totalRow);
  7.         //pageTotalCount 计算得到
  8.         int pageTotalCount = totalRow / pageSize;
  9.         if (totalRow % pageSize > 0) {
  10.             pageTotalCount += 1;
  11.         }
  12.         page.setPageTotalCount(pageTotalCount);
  13.         //begin计算得到 ->int pageNo, int pageSize
  14.         int begin = (pageNo - 1) * pageSize;
  15.         List<Furn> pageItems = furnDAO.getPageItems(begin, pageSize);
  16.         page.setItems(pageItems);
  17.         String url = "/manage/furnServlet?action=page&pageNo=" + pageNo;
  18.         page.setUrl(url);
  19.         return page;
  20.     }
复制代码
从而在前端可以进行分页导航栏的展示
  1. <li><a target="_blank" href="https://www.cnblogs.com/customerFurnServlet?action=pageByName&pageNo=1">首页</a></li>
  2.     <c:if test="${requestScope.page.pageNo > 1}">
  3.         <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${requestScope.page.pageNo-1}">上一页</a></li>
  4.     </c:if>
  5.     <c:choose>
  6.         <c:when test="${requestScope.page.pageTotalCount<=5}">
  7.             <c:set var="begin" value="1"/>
  8.             <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
  9.         </c:when>
  10.         <c:when test="${requestScope.page.pageTotalCount > 5}">
  11.             <c:choose>
  12.                 <c:when test="${requestScope.page.pageNo<=3}">
  13.                     <c:set var="begin" value="1"/>
  14.                     <c:set var="end" value="5"/>
  15.                 </c:when>
  16.                 <c:when test="${requestScope.page.pageNo>requestScope.page.pageTotalCount-3}">
  17.                     <c:set var="begin" value="${requestScope.page.pageTotalCount - 4}"/>
  18.                     <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
  19.                 </c:when>
  20.                 <c:otherwise>
  21.                     <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
  22.                     <c:set var="end" value="${requestScope.page.pageNo +2 }"/>
  23.                 </c:otherwise>
  24.             </c:choose>
  25.         </c:when>
  26.     </c:choose>
  27.     <c:forEach begin="${begin}" end="${end}" var="i">
  28.         <c:if test="${i == requestScope.page.pageNo}">
  29.             <li><a  target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${i}">${i}</a></li>
  30.         </c:if>
  31.         <c:if test="${i != requestScope.page.pageNo}">
  32.             <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${i}">${i}</a></li>
  33.         </c:if>
  34.     </c:forEach>
  35.     <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotalCount}">
  36.         <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${requestScope.page.pageNo+1}">下一页</a></li>
  37.     </c:if>
  38.     <li><a target="_blank" href="https://www.cnblogs.com/customerFurnServlet?action=pageByName&pageNo=${requestScope.page.pageTotalCount}">末页</a></li>
  39.     <li><a>共${requestScope.get("page").pageTotalCount}页</a></li>
  40.     <li><a>共${requestScope.get("page").totalRow}条</a></li>
  41.     </ul>
复制代码
搜索功能

在首页我们必要根据用户提供的家居名称进行查询相关家居信息
使用Mysql中的模糊查询
  1. public int getTotalRowByName(String name) {
  2.         String sql = "SELECT COUNT(*) FROM furn WHERE`name` LIKE ?";
  3.         return ((Number)queryScalar(sql,"%"+name+"%")).intValue();//模糊查询
  4.     }
复制代码
使用Ajax局部刷新

ajax实现异步请求有三种常用方法1) $.ajax            2)$.get和 $.post        3)$.getJson
这里满足发送的请求方式是get请求因此使用方便的$.getJson
  1. $("button.add-to-cart").click(function () {
  2.                 //获取到点击的furn.id
  3.                 var furnId = $(this).attr("furnId");
  4.                 //发出一个请求添加家居
  5.                 $.getJSON(
  6.                     "cartServlet", {
  7.                         "action": "addItemByAjax",
  8.                         "id": furnId
  9.                     },
  10.                     function (data) {
  11.                         if (data.url == undefined) {//没有返回url 已经登录过
  12.                             //局部刷新
  13.                             $("span.header-action-num").text(data.cartTotalCount);
  14.                         } else {
  15.                             // 说明当前服务器返回url 要求定位
  16.                             location.href = data.url;
  17.                         }
  18.                     }
  19.                 )
  20.             })
复制代码
文件上传

文件上传是 前端的form 表单里的enctype 必要修改成multipart/form-data 提交的才可以是文件和文本
为了让文件可以按照年月日分类进行存放 我们可以提供一个工具方法
  1. public static String getYearMonthDay() {
  2.         int year = LocalDateTime.now().getYear();
  3.         int month = LocalDateTime.now().getMonthValue();
  4.         int day = LocalDateTime.now().getDayOfMonth();
  5.         return year + "/" + month + "/" + day;
  6.     }
复制代码
并且在创建目次时拼接到 fileRealPath中
  1. File fileRealPathDirectory = new File(fileRealPath + "/" + yearMonthDay);
复制代码
必要更新图片的路径
  1. //更新图片路径
  2. furn.setImgPath(WebUtils.FURN_IMG_DIRECTORY + "/" +yearMonthDay+ "/"+ name);
复制代码
以下是部分代码
  1. //1. 判断是不是文件表单(enctype="multipart/form-data")
  2.         if (ServletFileUpload.isMultipartContent(request)) {
  3.             //2. 创建 DiskFileItemFactory 对象, 用于构建一个解析上传数据的工具对象
  4.             DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
  5.             //3. 创建一个解析上传数据的工具对象
  6.             ServletFileUpload servletFileUpload =
  7.                     new ServletFileUpload(diskFileItemFactory);
  8.             //解决接收到文件名是中文乱码问题
  9.             servletFileUpload.setHeaderEncoding("utf-8");
  10.             try {
  11.                 List<FileItem> list = servletFileUpload.parseRequest(request);
  12.                 for (FileItem fileItem : list) {
  13.                     if (fileItem.isFormField()) {//如果是true就是文本 input text
  14.                         if ("name".equals(fileItem.getFieldName())) {
  15.                             furn.setName(fileItem.getString("utf-8"));
  16.                         } else if ("maker".equals(fileItem.getFieldName())) {
  17.                             furn.setMaker(fileItem.getString("utf-8"));
  18.                         } else if ("price".equals(fileItem.getFieldName())) {
  19.                             furn.setPrice(new BigDecimal(fileItem.getString()));
  20.                         } else if ("sales".equals(fileItem.getFieldName())) {
  21.                             furn.setSales(new Integer(fileItem.getString()));
  22.                         } else if ("stock".equals(fileItem.getFieldName())) {
  23.                             furn.setStock(new Integer(fileItem.getString()));
  24.                         }
  25.                     } else {
  26.                         //用一个方法
  27.                         //获取上传的文件的名字
  28.                         String name = fileItem.getName();
  29.                         System.out.println("上传的文件名=" + name);
  30.                         if (!"".equals(name)) {
  31.                             //把这个上传到 服务器的 temp下的文件保存到你指定的目录
  32.                             //1.指定一个目录 , 就是我们网站工作目录下
  33.                             String filePath = "/" + WebUtils.FURN_IMG_DIRECTORY ;
  34. //
  35.                             //2. 获取到完整目录
  36.                             String fileRealPath =
  37.                                     request.getServletContext().getRealPath(filePath);
  38.                             //3. 创建这个上传的目录=> 创建目录
  39.                             String yearMonthDay = WebUtils.getYearMonthDay();
  40.                             File fileRealPathDirectory = new File(fileRealPath + "/" + yearMonthDay);
  41.                             if (!fileRealPathDirectory.exists()) {//不存在,就创建
  42.                                 fileRealPathDirectory.mkdirs();//创建
  43.                             }
  44.                             //4. 将文件拷贝到fileRealPathDirectory目录
  45.                             //   构建一个上传文件的完整路径 :目录+文件名
  46.                             name = UUID.randomUUID().toString() + "_" + System.currentTimeMillis() + "_" + name;
  47.                             String fileFullPath = fileRealPathDirectory + "/" + name;
  48.                             fileItem.write(new File(fileFullPath));
  49.                             fileItem.getOutputStream().close();
  50.                             //5. 提示信息
  51.                             response.setContentType("text/html;charset=utf-8");
  52.                             response.getWriter().write("上传成功~");
  53.                             //todo
  54.                             //删除原先的图片
  55.                             //1.获取原先的图片路径
  56.                             String imgPath = furnService.queryFurnById(id).getImgPath();
  57.                             //2.判断是否存在
  58.                            String path =  "out/artifacts/jiaju_mall_war_exploded/"+imgPath;
  59.                           
  60.                             File file = new File(path);
  61.                             if (file.exists()){
  62.                                 file.delete();
  63.                                 System.out.println("图片删除成功");
  64.                             }else{
  65.                                 System.out.println("图片并不存在,无需删除");
  66.                             }
  67.                             path = "web/"+imgPath;
  68.                             System.out.println("path= "+path);
  69.                             file = new File(path);
  70.                             if (file.exists()){
  71.                                 file.delete();
  72.                                 System.out.println("图片删除成功");
  73.                             }else{
  74.                                 System.out.println("图片并不存在,无需删除");
  75.                             }
  76.                            
  77.                             //更新图片路径
  78.                             furn.setImgPath(WebUtils.FURN_IMG_DIRECTORY + "/" +yearMonthDay+ "/"+ name);
  79.                         }
  80.                     }
  81.                 }
  82.             } catch (Exception e) {
  83.                 e.printStackTrace();
  84.             }
  85.         } else {
  86.             System.out.println("不是文件表单...");
  87.         }
  88.         //更新furn
  89.         furnService.updateFurnById(furn);
  90.         request.getRequestDispatcher("/views/manage/update_ok.jsp").forward(request, response);
  91.     }
复制代码
结语

以上只是对本项目的相对比较重要的功能进行了总结,当然了这个项目尚有一些其他的功能,好比订单天生/管理,购物车的天生/管理,统一错误404,500的页面表现等。总的来说,原生的Web项目对我帮助很大,在之后学习完框架之后很多的底层很多细节会被隐藏起来,不再让我们看到,以是我觉得做完这个项目一定对之后学习框架有所帮助。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表