JavaWeb项目 音乐海专辑商城
完整项目地址:项目地址
需求分析
首页展示专辑列表,分页显示
专辑列表可以根据价格进行筛选
注册和登录功能,根据用户名和密码登录,如果是普通用户账号则跳转到首页,如果是管理员账号则跳转到后台管理页面
注册 通过用户名,密码,用户邮箱和验证码来完成注册
用户登陆成功以后,可以将专辑列表中的专辑加入购物车
点击购物车可以显示购物车详细信息,也可以对购物车内商品数量进行编辑或删除某商品
之后可以进行结算,生成账单
生成账单后可以通过点击我的订单查看已生成的订单详情信息
管理员后台管理功能:对专辑进行管理,修改信息,库存,价格等信息。也可以下架某商品。
下架商品为假删除,因为以往订单和购物车可能会引用某些被删除商品,如果真删会删除失败
管理员还可以进行订单管理功能,可以看到所有用户的订单,同时进行发货状态的修改和订单详情的查看
数据库设计
-
实体分析
专辑 Album
用户 User
订单 OrderBean
订单项 OrderItem
购物车项 CartItem -
实体属性分析
专辑 : 名称、艺人、价格、销量、库存、封面、状态
用户 : 用户名、密码、邮箱、权限
订单 : 订单编号、订单日期、订单金额、订单数量、订单状态、用户
订单项 : 商品、数量、所属订单
购物车项 : 商品、数量、所属用户 -
创建数据库,设计初始数据并备份
类设计
Controller类:
AlbumController
CartController
OrderController
UserController
DAO类(继承BaseDAO):
接口:
AlbumDAO
CartItemDAO
OrderDAO
OrderItemDAO
UserDAO
实现类:
AlbumDAOImpl
CartItemDAOImpl
OrderDAOImpl
OrderItemDAOImpl
UserDAOImpl
pojo基本类:
Album
Cart
CartItem
OrderBean
OrderItem
User
Service类:
接口:
AlbumService
CartItemService
OrderService
UserService
实现类:
AlbumServiceImpl
CartItemServiceImpl
OrderServiceImpl
UserServiceImpl
filter类:
SessionFilter
创建项目
环境:Windows11 JDK 16.0.2 IntelliJ IDEA 2021.1.2 MySQL 5.5.40 Tomcat 8.5.31
Tomcat URL配置:http://localhost:8080/mall/page.do?operate=page&page=user/login
导入功能模块 myssm 内包含基础数据库操作类BaseDAO,实用工具Util类等
导入html页面和css js资源以及静态资源文件
加入Thymeleaf、Tomcat、Druid、mysql-connector kaptcha等依赖jar包
配置xml文件,包括Web.xml jdbc.properties applicationContext.xml
创建基本pojo类
设置Tomcat启动URL:http://localhost:8080/mall/page.do?operate=page&page=user/login
建立Controller,每个Controller要用到对应的DAO,DAO上面有一层Service,故再新建Service
实现顺序 DAO-DAOImpl-Service-ServiceImpl
验证可以获取CartList后 用Thymeleaf修改页面中写死的假数据
<link rel="stylesheet" href="./static/css/minireset.css" />
<link rel="stylesheet" href="./static/css/common.css" />
<link rel="stylesheet" href="./static/css/iconfont.css" />
<link rel="stylesheet" href="./static/css/index.css" />
<link rel="stylesheet" href="./static/css/swiper.min.css" />
改为
<link rel="stylesheet" th:href="@{/static/css/minireset.css}" />
<link rel="stylesheet" th:href="@{/static/css/common.css}" />
<link rel="stylesheet" th:href="@{static/css/iconfont.css}" />
<link rel="stylesheet" th:href="@{static/css/index.css}" />
<link rel="stylesheet" th:href="@{static/css/swiper.min.css}" />
<div class="list-content">
<div class="list-item">
<img src="./static/uploads/huozhe.jpg" alt="">
<p>书名:活着</p>
<p>作者:余华</p>
<p>价格:¥66.6</p>
<p>销量:230</p>
<p>库存:1000</p>
<button>加入购物车</button>
</div>
</div>
留下这一个作为模板,后面的死数据全部删除
三层架构
客户端从页面发来请求后,ContextLoaderListener监听上下文创建并首先响应,从配置文件中读取信息并创建IOC容器BeanMap,接着Filter层响应,设置编码,开启事务。开启事务之后中央控制器DispatcherServlet响应并调用相关的Controller,Controller调用相应的Service方法,Service方法内是一系列对DAO对象的调用操作,一个DAO对象操作数据库中相应的一张表 。重新返回结果到Controller层之后Controller层返回给中央控制器一个字符串值,中央控制器根据返回值进行最后一步:对页面视图的渲染,然后将用户转发或重定向至某页面。
- 表述层(Servlet层):负责处理浏览器请求、返回响应、页面调度
- 业务逻辑层Service:负责处理业务逻辑,根据业务逻辑把持久化层从数据库查询出来的数据进行运算、组装,封装好后返回给表述层,也可以根据业务功能的需要调用持久化层把数据保存到数据库、修改数据库中的数据、删除数据库中的数据
- 持久化层DAO:根据上一层的调用对数据库中的数据执行增删改查的操作
好处:所有和当前业务功能需求相关的代码全部耦合在一起,如果其中有任何一个部分出现了问题,牵一发而动全身,导致其他无关代码也要进行相应的修改。这样的话代码会非常难以维护。
所以为了提高开发效率,需要对代码进行模块化的拆分。整个项目模块化、组件化程度越高,越容易管理和维护,出现问题更容易排查。
登录功能
SessionFilter , 用来判断session中是否保存了currUser,判断是否是合法用户。
购物车
关于金额的精度问题:
验证码
Kaptcha
导入kaptcha-2.3.2.jar
配置web.xml
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
<init-param>
<param-name>kaptcha.border.color</param-name>
<param-value>red</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.char.string</param-name>
<param-value>abcdefg</param-value>
</init-param>
<init-param>
<param-name>kaptcha.noise.impl</param-name>
<param-value>com.google.code.kaptcha.impl.NoNoise</param-value>
</init-param>
<init-param>
<param-name>kaptcha.image.width</param-name>
<param-value>120</param-value>
</init-param>
<init-param>
<param-name>kaptcha.image.height</param-name>
<param-value>40</param-value>
</init-param>
<init-param>
<param-name>kaptcha.textproducer.font.size</param-name>
<param-value>28</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptch.jpg</url-pattern>
</servlet-mapping>
用Vue Axios对购物车页面进行改造
原生的Ajax(了解)
第一步: 客户端发送异步请求;并绑定对结果处理的回调函数
- 定义ckUname方法:
- 创建XMLHttpRequest对象
- XMLHttpRequest对象操作步骤:
- open(url,“GET”,true)
- onreadyStateChange 设置回调
- send() 发送请求
- 在回调函数中需要判断XMLHttpRequest对象的状态:
readyState(0-4) , status(200)
第二步:服务器端做校验,然后将校验结果响应给客户端
目的: 用来发送异步的请求,然后当服务器给我响应的时候再进行回调操作
好处: 提高用户体验;局部刷新:降低服务器负担、减轻浏览器压力、减轻网络带宽压力
开发步骤:
- 创建XMLHttpRequest
- 调用open进行设置:“GET” , URL , true
- 绑定状态改变时执行的回调函数 - onreadystatechange
- 发送请求 - send()
- 编写回调函数,在回调函数中,我们只对XMLHttpRequest的readystate为4的时候感兴趣
我们只对XMLHttpRequest的status为200的时候感兴趣
0: (Uninitialized) the send( ) method has not yet been invoked.
1: (Loading) the send( ) method has been invoked, request in progress.
2: (Loaded) the send( ) method has completed, entire response received.
3: (Interactive) the response is being parsed.
4: (Completed) the response has been parsed, is ready for harvesting.
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
Vue
- {{}} - 相当于innerText
- v-bind:attr 绑定属性值。例如,v-bind:value - 绑定value值
简写: :value - v-model 双向绑定
v-model:value , 简写 v-model - v-if , v-else , v-show
v-if和v-else之间不能有其他的节点
v-show是通过样式表display来控制节点是否显示 - v-for 迭代
v-for={fruit in fruitList} - v-on 绑定事件
- 其他:
- trim:去除首尾空格 , split() , join()
- watch表示侦听属性
- 生命周期
Axios
Axios是Ajax的一个框架,简化Ajax操作
Axios执行Ajax操作的步骤:
- 添加并引入axios的js文件
2-1. 客户端向服务器端异步发送普通参数值
- 基本格式: axios().then().catch()
- 示例:
axios({
method:"POST",
url:"....",
params:{
uname:"lina",
pwd:"ok"
}
})
.then(function(value){}) //成功响应时执行的回调 value.data可以获取到服务器响应内容
.catch(function(reason){}); //有异常时执行的回调 reason.response.data可以获取到响应的内容
reason.message / reason.stack 可以查看错误的信息
2-2. 客户端向服务器发送JSON格式的数据
-
什么是JSON
JSON是一种数据格式
XML也是一种数据格式
XML格式表示两个学员信息的代码如下:<students> <student sid="s001"> <sname>jim</sname> <age>18</age> </student> <student sid="s002"> <sname>tom</sname> <age>19</age> </student> </students>
JSON格式表示两个学员信息的代码如下:
[{sid:"s001",age:18},{sid:"s002",age:19}]
-
JSON表达数据更简洁,更能够节约网络带宽
-
客户端发送JSON格式的数据给服务器端
-
客户端中params需要修改成: data:
-
服务器获取参数值不再是
request.getParameter()...
而是:StringBuffer stringBuffer = new StringBuffer(""); BufferedReader bufferedReader = request.getReader(); String str = null ; while((str=bufferedReader.readLine())!=null){ stringBuffer.append(str); } str = stringBuffer.toString() ;
-
我们会发现 str的内容如下:
{"uname":"lina","pwd":"ok"}
服务器端给客户端响应JSON格式的字符串,然后客户端需要将字符串转化成js Object
- 获取文档中某一个节点的方式:
//DOM:Document
//var unameTxt = document.getElementById("unameTxt");
//BOM:Browser
//document.forms[0].uname
总体思路:
html-js-controller-service-serviceimpl-DAO-daoimpl
问题
未将lib添加到工件
-parameters导致空指针异常
applicationContext.xml路径填写错误导致beanFactory不能正确新建实例,报错classNotFoundException修改后正确,调试beanFactory实例正确加载配置文件中的参数如下图:
//32位全球唯一码,表示订单编号,不用手动生成
在user/login点击登陆后需要访问user.do,如果用户存在则在session中存入currUser,此时用户才合法
//有时没有给定某些参数时传的参数不为null而是空字符串(&lowPrice=&highPrice=),因此字符串判空不可忽略
//http://localhost:8080/mall/album.do?operate=index&turnLoc=search&lowPrice=&highPrice=
过滤器
已有的过滤器在com.hive.myssm...
下,新建的filter路径若在com.hive.album
则必然会让myssm里的所有filter失效,故应该新建包名使之字典序不能高于myssm
如果新加一个合法用户验证过滤器,过滤器类名应保证字典序低于已有的设置编码的filters,以免用户验证过滤器让设置编码的CharacterEncodingFilter失效
故新建com.hive.userfilters