家居网购项目--项目总结
家居网购项目总结
- 本项目是基于java的前后端项目,使用原生的Servlet + jsp 开发。
- 主要的技术点:
- 1.登录注册功能:使用kaptcha去生成验证码,使用邮件完成注册
- 2.使用拦截器拦截用户请求,限制用户访问权限
- 3.使用ThreadLocal 确保是同一线程来完成事务的提交和回滚
- 4.使用MVC模式使用DAO-Serice-Servlet进行分层
- 5.使用数据模型entity Cart.java 将数据存入session中来进行购物车的存储
- 6.使用ajax对页面进行局部刷新
- 7.使用json格式进行前后端数据的交换
- 8.前端使用jsp进行服务器渲染
- 9.数据库使用Mysql
复制代码 项目预备
1.一些工作环境的设置,IDE使用IntellijIDEA,jdk1.8,下面先容一些关于此项目的主要模块后端代码的实现部分
2.搭建项目的框架
注册与登录功能的实现
注册和登录功能是每个网站最基本的功能,实现的主要难点我觉得在于正则表达式的编写。- //完成对用户名的校验
- var usernamePattern = /^\w{6,10}$/;
- //验证邮箱
- var emailVal = $("#email").val();
- var emailPattern = /^[\w-]+@([a-zA-Z]+\.)+[a-zA-Z]+$/
- if (!emailPattern.test(emailVal)) {
- $("span[class= 'errorMsg']").text("电子邮箱格式不正确");
- return false;
- }
- //...
复制代码 用户表实现
暗码MD5加密
为了保证安全,暗码不能明文的在网络中进行传输,也不能以明文的形式存到数据库中。
存在数据库的暗码 = MD5( 暗码 ) 防止暗码泄露
Kaptcha 天生验证码
导入 Kaptcha.jar 后,服务器会天生的验证码并保存在session中,我们必要通过 com.google.code.kaptcha下的 Constants.java类 的 属性 拿到对应的验证码- public static final String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";//静态属性
- //获取验证码
- String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
复制代码 并且为了防止验证码被重复使用必要立即删除验证码- //立即删除验证码防止验证码被重复使用
- request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
复制代码 过滤器的使用
本项目有两个过滤器,分别是:
1.用于用户权限验证的 AuthFilter.java
2.用于配合JDBC提交和回滚事务的 TransactionFilter.java
使用过滤器必要在web.xml文件中设置相关参数,并且过滤器一样平常设置的优先级较高(高于Servlet的设置)-
- <filter>
- <filter-name>AuthFilter</filter-name>
- <filter-class>com.code_study.furns.filter.AuthFilter</filter-class>
- <init-param>
-
- <param-name>excludedUrls</param-name>
- <param-value>/views/manage/manage_login.jsp,/views/member/login.jsp</param-value>
- </init-param>
- <init-param>
-
- <param-name>interceptUrls</param-name>
- <param-value>
- /views/cart/*
- ,/views/manage/*
- ,/views/member/*
- ,/views/order/*
- ,/cartServlet
- ,/manage/furnServlet
- ,/orderServlet
- </param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>AuthFilter</filter-name>
-
- <url-pattern>/views/cart/*</url-pattern>
- <url-pattern>/views/manage/*</url-pattern>
- <url-pattern>/views/member/*</url-pattern>
- <url-pattern>/views/order/*</url-pattern>
- <url-pattern>/cartServlet</url-pattern>
- <url-pattern>/manage/furnServlet</url-pattern>
- <url-pattern>/orderServlet</url-pattern>
- </filter-mapping>
复制代码 使用拦截器AuthFilter来拦截所有的用户请求,判定请求中的session是否存在有效的member或者admin,如果都没有就请求转发到登岸页面,如果有,根据member或者admin对应权限判定 放行的资源是否包含 请求的url。如果不包含设置的放行url 就走验证- <param-name>excludedUrls</param-name>
- <param-value>/views/manage/manage_login.jsp,/views/member/login.jsp</param-value>
复制代码 Servlet归并
将Servlet归并成一个BasicServlet——利用了模板设计模式+动态绑定+反射- //解决接收到的数据中文乱码问题
- request.setCharacterEncoding("utf-8");
- //获取action不同的值
- String action = request.getParameter("action");
- try {
- //反射获取servlet对应的方法的对象
- Method declaredMethod = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
- declaredMethod.invoke(this, request, response);
- } catch (Exception e) {
- //将发生的异常继续throw
- throw new RuntimeException(e);
- }
复制代码 分页表现
将分页表现抽象成一个数据模型entity Page.java- //每页显示多少条记录其他地方也可以使用
- public static final Integer PAGE_SIZE = 4;//表示 每页显示几条记录
- private Integer pageNo;//表示 第几页
- private Integer totalRow;//表示 多少条记录
- private Integer pageTotalCount;//表示 共有多少页 -> totalRow / pageSize
- private List<T> items;//当前页显示的数据
- private String url;//分页导航的字符串
- private Integer pageSize = PAGE_SIZE;//每页显示几条记录
复制代码 进行分页的方法page- public Page<Furn> page(int pageNo, int pageSize) {
- Page<Furn> page = new Page<>();
- page.setPageNo(pageNo);
- page.setPageSize(pageSize);
- int totalRow = furnDAO.getTotalRow();
- page.setTotalRow(totalRow);
- //pageTotalCount 计算得到
- int pageTotalCount = totalRow / pageSize;
- if (totalRow % pageSize > 0) {
- pageTotalCount += 1;
- }
- page.setPageTotalCount(pageTotalCount);
- //begin计算得到 ->int pageNo, int pageSize
- int begin = (pageNo - 1) * pageSize;
- List<Furn> pageItems = furnDAO.getPageItems(begin, pageSize);
- page.setItems(pageItems);
- String url = "/manage/furnServlet?action=page&pageNo=" + pageNo;
- page.setUrl(url);
- return page;
- }
复制代码 从而在前端可以进行分页导航栏的展示- <li><a target="_blank" href="https://www.cnblogs.com/customerFurnServlet?action=pageByName&pageNo=1">首页</a></li>
- <c:if test="${requestScope.page.pageNo > 1}">
- <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${requestScope.page.pageNo-1}">上一页</a></li>
- </c:if>
- <c:choose>
- <c:when test="${requestScope.page.pageTotalCount<=5}">
- <c:set var="begin" value="1"/>
- <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
- </c:when>
- <c:when test="${requestScope.page.pageTotalCount > 5}">
- <c:choose>
- <c:when test="${requestScope.page.pageNo<=3}">
- <c:set var="begin" value="1"/>
- <c:set var="end" value="5"/>
- </c:when>
- <c:when test="${requestScope.page.pageNo>requestScope.page.pageTotalCount-3}">
- <c:set var="begin" value="${requestScope.page.pageTotalCount - 4}"/>
- <c:set var="end" value="${requestScope.page.pageTotalCount}"/>
- </c:when>
- <c:otherwise>
- <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
- <c:set var="end" value="${requestScope.page.pageNo +2 }"/>
- </c:otherwise>
- </c:choose>
- </c:when>
- </c:choose>
- <c:forEach begin="${begin}" end="${end}" var="i">
- <c:if test="${i == requestScope.page.pageNo}">
- <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${i}">${i}</a></li>
- </c:if>
- <c:if test="${i != requestScope.page.pageNo}">
- <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${i}">${i}</a></li>
- </c:if>
- </c:forEach>
- <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotalCount}">
- <li><a target="_blank" href="https://www.cnblogs.com/${requestScope.page.url}&pageNo=${requestScope.page.pageNo+1}">下一页</a></li>
- </c:if>
- <li><a target="_blank" href="https://www.cnblogs.com/customerFurnServlet?action=pageByName&pageNo=${requestScope.page.pageTotalCount}">末页</a></li>
- <li><a>共${requestScope.get("page").pageTotalCount}页</a></li>
- <li><a>共${requestScope.get("page").totalRow}条</a></li>
- </ul>
复制代码 搜索功能
在首页我们必要根据用户提供的家居名称进行查询相关家居信息
使用Mysql中的模糊查询- public int getTotalRowByName(String name) {
- String sql = "SELECT COUNT(*) FROM furn WHERE`name` LIKE ?";
- return ((Number)queryScalar(sql,"%"+name+"%")).intValue();//模糊查询
- }
复制代码 使用Ajax局部刷新
ajax实现异步请求有三种常用方法1) $.ajax 2)$.get和 $.post 3)$.getJson
这里满足发送的请求方式是get请求因此使用方便的$.getJson- $("button.add-to-cart").click(function () {
- //获取到点击的furn.id
- var furnId = $(this).attr("furnId");
- //发出一个请求添加家居
- $.getJSON(
- "cartServlet", {
- "action": "addItemByAjax",
- "id": furnId
- },
- function (data) {
- if (data.url == undefined) {//没有返回url 已经登录过
- //局部刷新
- $("span.header-action-num").text(data.cartTotalCount);
- } else {
- // 说明当前服务器返回url 要求定位
- location.href = data.url;
- }
- }
- )
- })
复制代码 文件上传
文件上传是 前端的form 表单里的enctype 必要修改成multipart/form-data 提交的才可以是文件和文本
为了让文件可以按照年月日分类进行存放 我们可以提供一个工具方法- public static String getYearMonthDay() {
- int year = LocalDateTime.now().getYear();
- int month = LocalDateTime.now().getMonthValue();
- int day = LocalDateTime.now().getDayOfMonth();
- return year + "/" + month + "/" + day;
- }
复制代码 并且在创建目次时拼接到 fileRealPath中- File fileRealPathDirectory = new File(fileRealPath + "/" + yearMonthDay);
复制代码 必要更新图片的路径- //更新图片路径
- furn.setImgPath(WebUtils.FURN_IMG_DIRECTORY + "/" +yearMonthDay+ "/"+ name);
复制代码 以下是部分代码结语
以上只是对本项目的相对比较重要的功能进行了总结,当然了这个项目尚有一些其他的功能,好比订单天生/管理,购物车的天生/管理,统一错误404,500的页面表现等。总的来说,原生的Web项目对我帮助很大,在之后学习完框架之后很多的底层很多细节会被隐藏起来,不再让我们看到,以是我觉得做完这个项目一定对之后学习框架有所帮助。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |