目录

写代码之前的分析

相关数据表的创建

对应的配置文件

用户管理场景的实现

相关的数据对象

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自动化测试用例的设计

功能的改善点