Java
程序开发
需求分析
项目需求
使用控制台作为用户交互界面,实现用户进入购物网站后,从首页到最终下单支付的流程中的一系列动作
分析出要开发的系统的模块,以及每个模块下的功能
本系统操作流程
本系统功能模块
用户角色
普通用户(买家)业务模块
管理员用户(商家)业务模块
概要设计
对要开发的系统功能进行设计,包括以下方面:
- 运行流程
- 功能分配
- 接口设计
- 数据结构
- 出错处理
- 日志设计
商城系统的运行流程
一个 web 网站系统大体由三部分构成:客户端(浏览器、手机等移动端)、服务器、数据库
客户端 主要负责用户交互,向用户展示信息和数据,支持用户操作,并根据用户的操作进行动态响应;
服务器端 主要负责业务处理数据,进行业务逻辑的处理,并对客户端响应数据;
数据库 则是用来存储数据的,一般操作分为添、删、改、查四大类
客户端访问服务端,一般称为客户端向服务端发送 “请求”,反过来,服务端向客户端发消息时,我们称为向客户端 “响应”;
请求和响应的过程,是用网络编程相关的技术实现的,涉及到很多网络相关的协议和过程
商城系统的功能分配
客户端(Client)
- Client 客户端页面的顶层父类
- UserClient 用户(登录/注册)操作页面
- GoodsClient 商品操作页面
- CartClient 购物车操作页面
- OrderClient 订单操作页面
服务端
- BaseAction 控制器基类(Controller)
- UserAction 用户控制器类
- GoodsAction 商品控制器类
- CartAction 购物车控制器类
- OrderAction 订单控制器类
- Service 服务层
- DAO 数据访问层(Data Access Object)
数据库
- TXT 文件
- JSON 格式存储
- IO 流读写
商城系统的接口设计
Service 层的接口:可能向多个模块提供服务
- BaseService 服务层的顶层接口,所有模块的服务层接口的父接口
- UserService 用户模块的接口,处理所有与用户数据相关的业务逻辑
- GoodsService 商品模块的接口,处理所有与商品数据相关的业务逻辑
- CartService 购物车模块的接口,处理所有与购物车数据相关的业务逻辑
- OrderService 订单模块的接口,处理所有与订单数据相关的业务逻辑
DAO 层的接口:可能向多个服务层提供数据
- BaseDAO 数据访问层的顶层接口,所有模块的数据访问层接口的父接口
- UserDAO 用户模块的接口,处理所有与用户相关的数据
- GoodsDAO 商品模块的接口,处理所有与商品相关的数据
- CartDAO 购物车模块的接口,处理所有与购物车数据相关的数据
- O人的人DAO 订单模块的接口,处理所有与订单数据相关的数据
数据库的接口:可能操作不同的数据库
IDataAccess 定义数据的基本操作
日志模块的接口:支持控制台打印和写入本地文件
ISysLog 定义日志的基本操作
商城系统的数据结构设计
实体类:描述现实事物的类
Entity
实体类,所有子模块的实体类的父类
-
id
数据的唯一标识,String
-
create Time
数据的创建时间,String
-
delete Time
数据的删除时间,String
-
isDel
数据的删除状态,String
,0
已删除,1
正常, 默认1
-
User
用户模块的实体类,用于描述用户的基本信息 -
Goods
商品模块的实体类,用于描述商品的基本信息 -
Cart
购物车模块的实体类,用于描述购物车的基本信息 -
Order
订单模块的实体类,用于描述订单的基本信息
数据文件:和每个实体类是一一对应的
-
User
db_user.txt -
Goods
db_goods.txt -
Cart
db_cart.txt -
Order
db_order.txt
商城系统的出错处理和日志设计
出错处理:顶层调用者处理异常,其他抛出
- Action 在控制器中捕获异常
- Service 服务层的所有异常全部抛出
- DAO 数据访问层的所有异常全部抛出
日志设计:支持控制台打印和写入本地文件
- ISysLog 日治模块接口
-
info
普通信息 -
warn
警告信息 -
error
错误信息
- ConsoleLog 实现类,打印日志信息到控制台
- TxtLog 实现类,打印日志信息到 txt 文件
开发前的准备工作
项目模块和分包
创建项目 EShop,并添加如下模块
- user 用户模块
- log 日志模块
- goods 商品模块
- cart 购物车模块
- order 订单模块
- client 客户端模块
- common 公共模块,存放所有顶层父类、接口,公共 bean、工具等
各模块下的包
- cn.itcast.eshop.user
- cn.itcast.eshop.log
- cn.itcast.eshop.goods
- cn.itcast.eshop.cart
- cn.itcast.eshop.order
- cn.itcast.ehsop.client
- cn.itcast.eshop.common
公共模块的基类和顶层接口
common 模块下的基类和接口
- cn.itcast.eshop.common.action.BaseAction
- cn.itcast.eshop.common.service.BaseService
- cn.itcast.eshop.common.dao.BaseDAO
- cn.itcast.eshop.common.dao.IDataAccess
- cn.itcast.eshop.common.entity.Entity
client 模块下的基类
- cn.itcast.eshop.client.Client
数据交换格式 - JSON 技术简介
JSON 概念
JSON(JavaScript Object Notation) 是一种使用文本存储和表示数据的格式
- JSON 格式的数据其实就是一个字符串
JSON 格式数据的表现形式
-
{}
: 对象 -
[]
: 数组 - 对象的数据表示为键值对
- 数据之间使用逗号隔开
JSON 支持的数据类型(任意组合)
- 数值:整数对应
int
,浮点数对应double
-
boolean
:布尔型,true
,false
- 字符串:如 “案例”
-
null
:Java
中的null
-
array
: 数组[]
-
object
: 对象{}
{
"dates":{
"date":[{
"id":1,
"name":"JSON",
"abb":"JavaScript Object Notation"
},
{
"id":2,
"name":"XML",
"abb":"eXtensible Markup Language"
},
{
"id":3,
"name":"HTML",
"abb":"HyperText Markup Language"
}
]
}
}
JSONUtil 工具类封装
导入 jar 包,例如,fastjson-1.2.53.jar
// 把对象转为 JSON 格式的字符串
public static String entity2JSON(Object entity)
// 把实体对象列表转换成 JSON 字符串
public static String entityList2JSON(List<?> entityList)
// 将 JSON 字符串转换成指定类型对象
public static <T> T JSON2Entity(String json, Class<T> clazz)
public static Object JSON2Entity(String json, Class<?> clazz)
// 将 JSON 数组转换成指定类型对象列表
public static <T> List<T> JSONArray2List(String json, Class<T> clazz)
public static List<?> JSONArray2List(String json, Class<?> clazz)
用户管理
用户登录模块主要功能
用户登录
输入用户名、密码,并根据用户名、密码获取用户,若该用户存在,则登录成功,否则登录失败
用户注册
提示用户输入用户信息和个人基本信息,封装成用户对象,向数据库添加一条数据
用户实体类
username, password, role (NORMAL, ADMIN)
Person 实体类
name, sex, phone, address
登录功能分析
客户端登录页面
分析步骤:
- 使用控制台提示用户输入用户名、密码
- 向服务器发送请求,并接收返回消息字符串,使用
setter
方法把数据传递给Action
;调用Action
的登录功能 - 解析消息字符串,提示用户信息
- 页面跳转:使用字符串常量作为跳转标记
- 成功:返回上一次操作的页面
- 失败:返回登录页面
package cn.itcast.eshop.client;
import cn.itcast.eshop.common.entity.Msg;
import cn.itcast.eshop.common.util.JSONUtil;
import cn.itcast.eshop.user.UserAction;
import java.util.Scanner;
/**
* <用户操作界面>
* 处理所有用户的后台操作,并返回 JSON 格式的字符串信息
*/
public class UserClient extends Client {
/**
* 用户登录操作页面
* 1. 使用控制台提示用户输入用户名和密码
* 2. 向服务器发送请求,并接收返回消息字符串
* 使用 setter 方法把数据传递给 Action
* 调用 Action 的登录功能
* 3. 解析消息字符串,提示用户信息
* 4. 页面跳转,使用字符串常量作为跳转标记
* 成功,返回上一次操作的页面
* 失败,返回登录页面
* @return
* */
public String showLogin() {
System.out.println("========欢迎登录========");
// 1. 使用控制台提示用户输入用户名和密码
Scanner sc = new Scanner(System.in);
System.out.println("Please input UserName: ");
String username = sc.nextLine();
System.out.println("Please input Password: ");
String password = sc.nextLine();
// 2. 向服务器发送请求,并接收返回消息字符串
UserAction userAction = new UserAction();
// 使用 setter 方法把数据传递给 Action
userAction.setUsername(username);
userAction.setPassword(password);
// 调用 Action 的登录功能
String result = userAction.login();
// 3. 解析消息字符串,提示用户信息
Msg msg = JSONUtil.JSON2Entity(result, Msg.class);
if(msg.getType().equals(Msg.SUCCESS)) {
// 登录成功
System.out.println("登录成功");
// 4 成功,返回上一次操作的页面
return HISTORY;
} else {
System.out.println("登录失败");
// 4 失败,返回登录页面
return LOGIN;
}
}
}
服务端登录 - Controller
层的实现
分析步骤:
- 封装数据到
User
对象 - 调用
UserService
处理逻辑User login(User user) throws Exception;
- 异常处理
- 根据服务层返回结果生成消息
消息实体类Msg
- 记录日志(待开发)
- 响应消息到客户端
/**
* 用户登录功能
* 1. 封装数据到 user 对象
* 2. 调用 UserService 处理逻辑,并抛出异常
* 3. 异常处理
* 4. 根据服务层返回结果生成消息
* 5. 记录日志(待开发)
* 6. 响应消息到客户端
* @return
* */
public String login() {
Msg msg = new Msg();
try {
// 1. 封装数据到 user 对象
User user = new User();
user.setUsername(username);
user.setPassword(password);
// 2. 调用 UserService 处理逻辑,并抛出异常
UserService userService = new UserServiceImpl();
user = userService.login(user);
// 3. 异常处理
// 4. 根据服务层返回结果生成消息
if (user != null) {
msg.setType(Msg.SUCCESS); // 登录成功
msg.setMsg("登录成功");
} else {
msg.setType(Msg.FAIL); // 登录成功
msg.setMsg("用户名或者密码不正确");
}
// 5. 记录日志(待开发)
// 6. 响应消息到客户端
return JSONUtil.entity2JSON(msg);
} catch (Exception e) {
e.printStackTrace();
msg.setType(Msg.FAIL); // 登录成功
msg.setMsg("登录失败,捕获异常");
return JSONUtil.entity2JSON(msg);
}
}
服务端登录 - Service
层的实现
分析步骤:
- 调用
UserDAO
获取用户列表数据List getEntityList() throws Exception;
- 遍历用户列表,逐个与给定用户对象的用户名、密码进行匹配
- 匹配成功则返回该用户对象,失败则返回
null
注意事项:
实际环境中,使用操作数据库的语言SQL
将用户名、密码作为条件进行查询
服务端登录 - DAO
层的实现
分析步骤:
- 创建
IDataAccess
子类TXTDataAccess
的对象IDataAccess dataAccess = new TXTDataAccess();
- 调用该对象的方法获取所有用户数据并返回
List userList = dataAccess.getList(User.class);
getList()
方法定义分析:
- 作用:获取全部用户数据
- 返回值:
List
用户对象列表 - 参数:
Class
(JSON 转换需要)
getList()
方法实现步骤:
- 根据实体类的字节码文件对象获取类名
- 根据类名获取用户数据文件名
- 合成数据文件路径
- 使用文件操作工具类读取文件中的字符串数据
- 将字符串数据转换成
List
对象并返回
日志管理
日志是记录系统操作或者消息的数据文件,具有处理历史数据、诊断问题等作用
- 常见的日志级别(
level
)
-
info
普通信息 -
warn
警告信息 -
error
错误信息
- 实体类
Log
-
String msg
:日志内容 -
String level
:日志级别 -
String time
: 日志发生时间
ISysLog
接口定义
级别常量:
public static final String INFO = "INFO";
public static final String WARN = "WARN";
public static final String ERROR = "ERROR";
方法定义:
void info(String msg)
void warn(String msg)
void error(String msg)
日志操作步骤:
- 封装日志对象
- 打印日志数据到控制台
商品管理
商城首页
GoodsClient 步骤分析:
- 向后台发送请求,获取商品数据
- 解析响应消息字符串
- 展示商品列表
GoodsAction 步骤分析:
- 获取所有商品的对象列表
- 将商品对象转换成字符串并返回
- 异常处理
- 记录日志
- 响应消息到客户端
公共用户操作:
String userOperate(String msg, String... oprs)
msg
: 提示信息,如“请根据序号…”oprs
: 用户操作,可变参数,本质是一个数组
返回值: 用户录入的操作
查看商品详情
思路:
商品列表页→输入商品编号→根据编号从 Map
中获取商品对象→展示商品详细信息
购物车管理
添加购物车
思路分析:
在实际开发中,购物车的实现大致有两种情况:
- 第一,以
Map
集合作为购物车对象,将相关数据临时存储在系统中(内存) - 第二,将用户添加到购物车中的商品,以购物车实体类对象的形式存储到数据库中
本系统实现第一种方式
购物车 Map
集合:key
: 商品 ID
value
: 商品数量
我的购物车
展示购物车中商品列表,包含每种商品的数量
订单管理
生成订单
生成订单的过程,实际就是封装订单实体类的过程
生成订单前,要验证是否登录
将订单基本信息如收货人姓名、收货地址、联系方式等封装到订单对象中,根据购物车中商品列表和数量计算出订单总金额。
生成订单后展示订单基本信息
去支付,订单详情
去支付,根据订单总金额,提示用户输入对应数值,输入数值大于等于总金额则支付成功,否则则支付失败,提示余额不足
订单详情,打印订单信息和订单状态