项目-家具网购
程序框架图

分层 | 对应包 | 说明 |
---|---|---|
web层 | com.lzw.furns.web/servlet/controller/handler | 接收用户请求,调用service |
service层 | com.lzw.furns.service | Service接口包 |
com.lzw.furns.service.impl | Service接口实现类 | |
dao持久层 | com.lzw.furns.dao | Dao接口包 |
com.lzw.furns.dao.impl | Dao接口实现类 | |
实体bean对象 | com.lzw.furns.pojo/entity/domain/bean | JavaBean类 |
工具类 | com.lzw.furns.utils | 工具类 |
测试包 | com.lzw.furns.test | 完成dao/service测试 |
MVC
介绍
MVC 全称∶ Model 模型、View 视图、 Controller 控制器。
MVC 最早出现在 JavaEE 三层中的 Web 层,它可以有效的指导 WEB 层的代码如何有效分离,单独工作。
View 视图∶只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合(Vue/JSP/Thymeleaf/HTML)
Controller 控制器∶只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个"调度者"的角色(Servlet), 这个概念会贯穿 javaee
Model 模型∶将与业务逻辑相关的数据封装为具体的 JavaBean 类,其中不掺杂任何与数据处理相关的代码(JavaBean/Domain/Pojo)
MVC是一种思想
MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了解耦合), 也有很多落地的框架比如 SpringMVC
示意图

- model 最早期就是 javabean, 就是早期的 jsp+servlet+javabean
- 后面业务复杂度越来越高, model 逐渐分层/组件化 (service + dao)
- 后面有出现了持久成技术 (service + dao + 持久化技术(hibernate / mybatis / mybatis-plus))
- 还是原来的 mvc ,但是变的更加强大了

家具网购开发环境搭建
实现功能 1-正确运行静态页面
把前端人员给的静态页拷贝到 web 即可(如图)

实现功能 2-会员注册前端 JS 校验
- 验证用户名:必须字母,数字下划线组成,并且长度为 6 到 10 位 =》 正则表达式
- 验证密码:必须由字母,数字下划线组成,并且长度为 6 到 10 位
- 邮箱格式验证:常规验证即可
- 验证码:后面实现
实现功能 3-会员注册后端
- 会员注册信息,验证通过后
- 提交给服务器,如果用户名在数据库中已经存在,后台给出提示信息,并返回重新注册
- 如果用户名没有在数据库中,完成注册,并返回注册成功的页面

实现功能 4-会员登录
- 输入用户名、密码后提交
- 判断会员是否存在
- 会员存在(数据库),显示登录成功页面
- 否则,返回登录页面,重新登录
- 要求改进登录密码为 md5 加密

实现功能 5-登录错误提示回显
- 输入用户名、密码后提交
- 如果输入有误,则给出提示
- 在登录表单回显用户名

实现功能 6-web 层 servlet 减肥
- 如图:一个请求对应一个 Servlet,会造成 Servlet 太多,不利于管理
- 在项目开发中,同一个业务(模块),一般对应一个 Servlet 即可,比如 LoginServlet 和RegisterServlet 都是在处理和会员相关的业务,应当合并
方案1-if_else
- 给 login 和 register 表单增加hidden元素,分别表示注册和登录
- 当信息提交到 MemberServlet后,获取 action 参数值
- 再根据不同的值来调用对应的方法即可
方案2-反射+模板设计模式+动态绑定

实现功能 7-后台管理 显示家具
- 给后台管理提供独立登录页面,不对外公开
- 管理员登录成功后,显示管理菜单页面
- 管理员点击家居管理,显示所有家居信息

实现功能 8-后台管理 添加家居
- 管理员进入到家居管理页面
- 点击添加家居,进入到 furn_add.jsp 页面,可以添加家居(如图)

中文乱码问题
修改 jiaju_mall\src\com\lzw\furns\web\BasicServlet.java
//处理接收乱码问题
request.setCharacterEncoding("utf-8");
表单重复提交问题
如果用户刷新页面,就会发现有重新添加一次家居
原因:当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户刷新页面(f5),就会发起浏览器记录的上一次请求
解决: 使用重定向即可,因为重定向本质是两次请求,而且最后一次就是请求显示家居,而不是添加家居
修改 jiaju_mall\src\com\lzw\furns\web\FurnServlet.java
req.getRequestDispatcher("/manage/furnServlet?action=list").forward(req, resp);
//改为
resp.sendRedirect(req.getContextPath() + "/manage/furnServlet?action=list");
实现功能 9-后台管理 删除家居
- 管理员进入到家居管理页面
- 点击删除家居链接,弹出确认窗口,确认删除,取消放弃

实现功能 10-后台管理 修改家居
- 管理员进入到家居管理页面
- 点击修改家居链接,回显该家居信息
- 填写新的信息,点击修改家居按钮
- 修改成功后,重新刷新显示家居列表

实现功能 11-后台分页(分页显示家居)
- 管理员进入到家居管理后台页面
- 点击家居管理,可以按分页规则显示家居

实现功能 12-后台分页(分页导航)
- 管理员进入到家居管理后台页面
- 可以通过分页导航条来进行分页显示
- 完成上页
- 下页
- 显示共多少页
- 点击分页导航, 可以显示对应页的家居信息
- 在管理员进行修改, 删除, 添加 家居后,能够回显原来操作所在页面数据

实现功能 13-首页分页
- 顾客进入首页页面
- 分页显示家居
- 正确显示分页导航条

实现功能 14-首页搜索
- 顾客进入首页页面
- 点击搜索按钮,可以输入家居名
- 正确显示分页导航条,并且要求在分页时,保留上次搜索条件

实现功能 15-显示登录名
- 顾客登录成功
- login_ok.jsp 显示欢迎信息
- 返回首页,显示登录相关菜单

实现功能 16-注销登录
- 顾客登录成功后
- login_ok.jsp 点击安全退出,注销登录
- 返回首页,也可点击安全退出, 注销登录

实现功能 17-注册验证码
- 提交完表单。服务器使用请求转发进行页面跳转。用户刷新(F5),会发起最后一次的请求, 造成表单重复提交问题。解决:用重定向
- 用户正常提交,由于网络延迟等原因,未收到服务器的响应,这时,用户着急多点了几次提交操作,也会造成表单重复提交。解决: 验证码
- 用户正常提交,服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交,解决:验证码
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setDateHeader("Expires", 0L);
resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
resp.setHeader("Pragma", "no-cache");
resp.setContentType("image/jpeg");
String capText = this.kaptchaProducer.createText();
req.getSession().setAttribute(this.sessionKeyValue, capText);
req.getSession().setAttribute(this.sessionKeyDateValue, new Date());
BufferedImage bi = this.kaptchaProducer.createImage(capText);
ServletOutputStream out = resp.getOutputStream();
ImageIO.write(bi, "jpg", out);
}

配置KaptchaServlet
<!--配置KaptchaServlet-->
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptchaServlet</url-pattern>
</servlet-mapping>
实现功能 18-添加家居到购物车
- 会员登录后,可以添加家居到购物车
- 完成购物车的设计和实现
- 每添加一个家居, 购物车的数量+1,并显示

实现功能 19-显示购物车
- 查看购物车,可以显示如下信息
- 选中了哪些家居,名称,数量,金额
- 统计购物车共多少商品,总价多少

实现功能 20-修改购物车
- 进入购物车,可以修改购买数量
- 更新该商品项的金额
- 更新购物车商品数量和总金额

实现功能 21-删除/清空购物车
- 进入购物车,可以删除某商品
- 可以清空购物车
- 要求给出适当的确认信息

实现功能 22-生成订单
- 进入购物车,点击购物车结账
- 生成订单和订单项
- 如会员没有登录,先进入登录页面,完成登录后再结账

--创建订单表
CREATE TABLE `order` (
`id` VARCHAR(64) PRIMARY KEY, -- 订单号
`create_time` DATETIME NOT NULL, -- 订单生成时间
`price` DECIMAL(11,2) NOT NULL, -- 订单的金额
`status` TINYINT NOT NULL, -- 状态 0 未发货 1 已发货 2 已结账
`member_id` INT NOT NULL -- 该订单对应的会员 id
)CHARSET utf8 ENGINE INNODB
-- 创建订单项表
CREATE TABLE `order_item`( id INT PRIMARY KEY AUTO_INCREMENT, -- 订单项的 id
`name` VARCHAR(64) NOT NULL, -- 家居名
`price` DECIMAL(11,2) NOT NULL, -- 家居价格
`count` INT NOT NULL, -- 数量
`total_price` DECIMAL(11,2) NOT NULL, -- 订单项的总价
`order_id` VARCHAR(64) NOT NULL -- 对应的订单号
)CHARSET utf8 ENGINE INNODB
作业 01-添加购物车按钮动态处理
- 如某家居库存为 0, 前台的 "add to cart" 按钮显示为 "暂时缺货"
- 后台也加上校验,只有在库存>0 时,才能添加到购物车
- 要求小伙伴课后完成-一定要动手走代码
作业 02-订单管理
- 完成订单管理-查看
- 具体流程看老师给出的界面
- 静态页面 order.html 和 order_detail.html 老师提供
实现功能 23-过滤器权限验证
- 当前系统,用户/顾客 在没有登录,是可以添加商品到购物车的,还可以查看购物 车, 我们使用过滤器加入权限验证,要求如下:
- 用户在进入后台管理,添加购物车前,需要先登录
- 如果没有登录,则进入会员登录页面

<!--过滤器一般配置在上面-->
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>com.lzw.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>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<!--这里配置要进行验证的url
1. 在 filter-mapping中url-pattern配置要拦截/验证 的url2
2. 对于我们不去拦截的url,就不配置
3. 对于要拦截的目录的某些要放行的资源,通过配置指定
-->
<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>/mange/furnServlet</url-pattern>
<url-pattern>/orderServlet</url-pattern>
</filter-mapping>
实现功能 24-事务管理
使用 Filter + ThreadLocal 进行事务管理
在一次 http 请求,servlet-service-dao 的调用过程,始终是一个线程, 这 是使用 ThreadLocal 的前提
使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象 中完成

实现功能 25-统一错误提示页面
- 如果在访问/操作网站,出现了内部错误,统一显示 500.jsp
- 如果访问/操作不存在的页面/servlet 时,统一显示 404.jsp

实现功能 26-ajax 提示注册会员名是否存在
- 注册会员时,如果名字已经注册过,当光标离开输入框,提示会员名已经存在, 否则提示不存在
- 要求使用 ajax 完成

实现功能 27-ajax 添加购物车
- 将家居添加到购物车
- 使用 ajax 方式

测试,你会发现针对 ajax 的重定向和请求转发会失效, 也就是 AuthFilter.java 的权限拦 截没用了, 也就是我们点击 add to cart ,后台服务没有响应, 怎么办

实现功能 28-ajax 上传/更新家居图片
- 后台修改家居,可以点击图片,选择新的图片
- 这里会使用到文件上传功能.

作业 03-完成管理员登录
作业 04-会员不能登录后台管理
- 管理员 admin 登录后,可访问所有页面
- 会员登录后,不能访问后台管理相关页面,其它页面可访问
- 假定管理员名字就是 admin , 其它会员名就是普通会员
作业 05-解决图片冗余问题
- 家居图片都放在一个文件夹,会越来越多,请尝试在 assets/images/product-image/ 目录下 自动创建 年月日 目录比如 21001011 ,以天为单位来存放上传图片
- 当上传新家居图片,原来的图片就没有用了,应当删除原来的家居图片.
实现功能 29-完成分页导航条
如果总页数<=5, 就全部显示
如果总页数>5, 按照如下规则显示(这个规则是程序员/业务来确定):
2.1 如果当前页是前 3 页, 就显示 1-5
2.2 如果当前页是后 3 页, 就显示最后 5 页
2.3 如果当前页是中间页, 就显示 当前页前 2 页, 当前页 , 当前页后两页