目录
写代码之前的分析
相关数据表的创建
对应的配置文件
用户管理场景的实现
相关的数据对象
Mapper对象
Service对象
关于密码加密
Controller对象
关于用户名和密码的校验
前端代码
货物管理场景
数据对象
Service层
Controller
JsonController编辑
前端页面
订单管理场景
数据对象
Mapper对象
Service对象
Controller对象
前端部分
纯前端设计
与我的文件搜索项目不同,上个项目我是为了练习我学的Java基础知识和多线程的使用,这个项目我会根据我学的SSM框架下进行制作,这个项目的代码量会更多
- 首先这个项目是是模拟出一个超市后台管理系统的
- 写这个项目的目的是为了巩固这一阶段我学的关于SSM框架学习的知识
写代码之前的分析
现实超市的用户角色:
- 1顾客:可以从超市进行购物
- 2货管:货品上架,货品下架,货品增量,货品减量,更新货品信息等
- 3收银:录入订单,结账….(比如订单的创建,和订单的状态变化(未结账——>结账,或者取消订单))
- 4老板:一些统计需求,进货情况,售货情况(也就是账单和货物量的情况)
场景梳理(我们这里将所有用户的功能集中到一个用户上)
- 用户管理=用户注册+用户登录
- 货物管理=货物上架+货物下架+货物信息更新+货物的浏览
- 订单管理=订单的创建+订单的状态变化+订单的浏览
关于如何实现
- 因为我是基于SSM框架进行创建项目,就涉及到SSM框架的分层,我分为三大层 Contoller(用于存储动态资源)+Service(提供一些模块化业务化的功能)+Mapper(用于操纵Mybatis),这些都是过程对象,和一些数据对象
关于订单状态的变化情况
比如创建订单这个过程会涉及什么呢?
- 我们发现一个订单的状态的变化,会涉及到多个操作(多条SQL语句),所以我们必须要保证操作的原子性,假如我们在创建订单的时候,已经把商品的库存减去了,但是出现bug,那么我们的订单没有插入到表中,但是库存已经减去了。这样就发生了错误,所以就要引入事务,将这一系列的操作变成了一个原子性的操作
相关数据表的创建
- 创建数据库
- orders表,用来存储订单信息
- order_items表,用来存储的订单中的相关货物信息
- users表,用来存储我们注册的用户信息
- products表,用来存储我们的货物信息
各个数据表的关系
对应的配置文件
用户管理场景的实现
相关的数据对象
- 这个数据对象对应着我们的数据表users的封装数据,在我们操纵数据库的时候对应一行数据
- 关于User数据对象,因为要被Mybatis调用,所以必须存在一个无参构造方法,和相关属性的setter方法,因为Mybatis就是默认先调用无参构造方法,和setter方法来注入相应的属性值,这里有@Date,所以不用我们自己写
Mapper对象
Service对象
- 利用构造方法依赖注入我们的UserMapper对象
关于密码加密
- 我们之前都是明文去保存密码,这次我们引入一个加密库(实际就是做hash,不是真正的加密),我们不再保存明文密码,我们这里引入的就是BCrypt算法
- 关于密码的等级
- 密码一般我们都采用md5加密的方式,但是用md5加密,对于一个固定的字符串,其md5值是固定的,这样就会出现彩虹表攻击情况。所谓彩虹表攻击就是指攻击者有一张表,里面有密码明文和对应md5值的对应关系,攻击者利用这些关系来破解用户密码。
Controller对象
- 我们将异常(将不合法的数据的校验也变为异常的样式)的处理与我们的业务分开
关于用户名和密码的校验
抽象父类类
- 对于密码和用户名这些校验都会有的校验方式,比如数据不能为空,不为null这些通用的放在一个抽象类中,然后让子类去继承,进一步减少了代码的数量
密码校验
用户名校验
- 用户名校验对父类多了一个用户名的长度判断
关于异常的处理
前端代码
- 用户注册的表单,输入相应的数据,根据name和申请的路径找到对应的资源,提交对应的数据,经过各层的处理保存到数据库和session当前浏览器保存了当前用户,注册也是这套逻辑
货物管理场景
数据对象
Product数据对象
- 这个数据对象是对应着我们数据表的对象,是为了从数据表Product中获得数据和存储数据
ProductParam
- 这个对象是对应我们前端表单输入的数据的接收对象,因为我们前端不是将所有的货物信息都要手动输入的,比如user_id,这个数据是我们通过当前登录的用户是是谁得到的(通过session得到)
Mapper层
Service层
Controller
JsonController
- 因为修饰的是@RestController,所以是如果返回的是String类型,那么是text/html,如果是对象,集合类则默认是JSON
前端页面
上架货物的前端页面
- 这里是post方法,将数据提交到后端,其提交的数据跟productParam
展示所有货物信息+AJAX请求所有货物的资源
更新货物信息的HTML页面
- 更新货物的数据对象也是对应着productParam,但是比上架货物多了一个关于商品ID,其实productParam中有productId,之所以我们上架的时候不填productId,是因为他在数据表中是自增主键,你不填,相应的数据就是null,那么在插入的时候,会自动根据情况分配主键
流程分析
- 访问create.html,商品上架的前提是必须先进行用户登录,用户未登录的话,是会跳转到登录页面,如何判断用户有没有登录,就靠session中的currentUser中的信息,货物上架的时候的上架用户id也是通过这个这个对象获得(我们把User类的对象存储在session,通过currentUser名称调用),先进行参数的合法性校验(复用之前的抽象类和异常处理),然后利用各层功能实现一个Product类的对象插入到数据表中,创建成功就跳转首页
- 浏览商品:我们访问list.html如果用户未登录,我们就不返回资源,而是跳转到登录页面,进行登录,如果是已经登录了,就会返回相应的数据,和跳转到相应货物信息的页面(我们是根据当前redirectUrl是否为空来判断到底是那种处理)
- 关于我们product/list.json返回类型的规定,因为前端展示的信息和后端存储的信息不一样,所以我们在Controller内部类定义一个PoductView来专门处理返回的数据,返回的类型采用JSON,所以用@Controller+ResposneBody,返回的是集合对象
- 更新商品的逻辑跟上架商品差不多,就是多了一个参数的输入,商品Id,一个在数据表插入,一个在数据表根据id进行更新操作
订单管理场景
数据对象
订单对象
- 用于封装关于订单的数据,用于存储进我们的orders表中
枚举类的内容
- 1表示未支付 2表示已支付
- 这个是用来存储我们具体的订单信息的,其中itemsList存储的是我们这个订单中每个订单项的信息,还有对应信息类型的转换,大概的内容就是这样
订单项的数据对象
- 首先为什么要有订单项这个数据,是为了让订单和商品的多对多关系变成两个一对多的关系
- 这个OrderItem对象是为了将关于订单项的数据封装起来,然后对应order_items表的数据,进行存储到数据表中
Mapper对象
OrderMapper对象
OrderItemMapper对象
Service对象
Controller对象
关于创建订单
关于具体的订单信息页面
订单取消和确认的操作
关于前端订单列表信息展示
前端部分
创建订单的大概的流程
- 用户进入/order/create.html的静态资源,然后填写1-3,2-5这样的数据,点击提交按钮,form表单发起HTTP请求(POST请求/order/create.do的资源)
- 后端:Controller:先判断是不是已经登录了,没登陆就跳转到首页,登录了就解析了1-3,2-5这种字符串为Map的数据结构,然后调用service的创建订单功能
- Service:(对应订单创建整体作为一个事务@Transactional)
- Mapper:根据具体的SQL语句将订单信息和订单项的数据插入到相对应的表
- Cotroller:然后进行重定向到具体的订单信息页面,(order/detail/{uuid})
- 浏览器会收到HTTP的重定向的响应,继续发送新的HTTP请求,也是就是(order/detail/{uuid}的GET请求)
- Controller:解析得到url中的uuid数据,然后判断用户是否登录
- Service:根据uuid查询到订单的基础信息(OrderMapper),根据orderId查询到所有属于这个订单的相关数据项(OrderItemMapper)
- Controller MVC流程中,将查询到的订单信息作为order放到model中,使用order-detail作为view的名称(对应reasource/templates/order-datail.html文件中),Spring配合(Thymeleaf)将Model和View结合在一起,生成最终的HTML内容,响应给前端
纯前端设计
我们上面的实现能让我们的功能是可用的,现在下面的设计就是将我们的前端变得美化一对,更加容易操作
首先让我们的页面有两个区域一个导航栏和一个功能区
- 导航区是一样,功能区在不同功能下进行不同的功能模块的添加
- 对公用的模块的css修饰
- 然后各个模块多出来的功能就在这个框架的功能区去添加就行了
关于deatail(就是订单详情页面的确认和取消等的css修饰)
.基本信息 { background-color: rgba(255, 255, 255, .7); border-radius: 8px; padding: 16px;}.下一步 { padding: 8px;}.下一步 a { background-color: rgba(255, 255, 255, .7); text-decoration: none;}.功能区 > * { margin: 16px 0;}
关于表格的修饰(比如商品的展示和订单的展示)
.功能区 { display: block; padding: 16px;}table { border-collapse: collapse; border: 1px solid #000; width: 100%;}th { background-color: blue; text-align: center; padding: 4px 0;}td { text-align: center; padding: 4px 0;}tr:nth-child(even) { background-color: bisque;}tr:nth-child(odd) { background-color: chartreuse;}
关于表单的修饰(比如登录注册等的表单)
form { background-color: rgba(255, 255, 255, .7); padding: 24px; border-radius: 8px; box-shadow: 0 0 10px #000; width: 400px; display: flex; flex-direction: column; justify-content: flex-start; align-items: stretch;}form > * { margin: 8px 0;}label { width: 100%;}input { width: 100%;}input { padding: 4px 8px; outline: none; height: 28px; border-radius: 4px; border: 1px solid #000;}button { outline: none; height: 28px; border-radius: 4px; border: 1px solid #000; background-color: bisque;}
测试项目功能
web自动化测试用例的设计