学 号 201610411221、101610411203
姓 名 吕晶、曹宣勇
班 级 计科2班
题 目 网上书店
授课老师 袁飞
目录
第1章 概述 1
1.1 课程设计的核心任务 1
1.2 课程设计工作进程 1
第2章 需求分析 2
2.1 用户需求 2
2.1.1 业务需求 2
2.1.2 商业需求 2
2.1.3 特殊需求 2
2.2 可行性分析 2
2.2.1 技术可行性 2
2.2.2 经济可行性 2
2.3 系统功能 3
第3章 概要设计 4
3.1 系统设计思想 4
3.2 系统(或网络)总体结构 4
3.3 数据库设计 4
第4章 详细设计 5
第5章 课程设计总结 6
第1章 概述
1.1 课程设计的核心任务
(1)满足网站管理员对其小型书店能够查看书的库存、上架和下架书籍、管理客户订单、随时能更 改书籍信息的要求。
(2)网站中书籍购买者能够注册登陆账号、随意选购书籍、将书籍添加进购物车、购买购物车中选 中的商品、修改订单等。
(3)网站简介,界面布局合理,资源利用率高
1.2 课程设计工作进程
1.2.1 需求分析阶段:
4月15日——5月8日完成对项目的需求分析、可行性分析、经济分析、系统模型设计和持久层设计,并写入需求分析文档中。
1.2.2 开发阶段:
5月8日——5月30日进行代码的编写,实现项目的基本功能。
1.2.3 测试和部署阶段:
5月30日——6月18日将项目完成并部署到服务器上,进行测试;完成设计文档。
第2章
需求分析
2.1 用户需求
2.1.1 业务需求
在实际的销售运营过程中,采购商或顾客只能通过上门咨询、电话沟通等方式进行各种产品信息的获取,而且时间与物理的局限性影响了图书的销售,并且在无形中提高了产品的销售成本。本系统可以改变这种现状,以少量的时间和资金建立企业商务网络,以此来使企业和消费者之间的经济活动变得更加灵活、主动。
2.1.2 特殊需求
管理员希望能够对书籍的库存有较方便的管理,在线下售出书也可以减库存。
2.2 可行性分析
2.2.1 技术可行性
本系统采用B/S架构、MVC设计模式,根据Java EE 标准开发,后端的数据库采用MySQL,MySQL小巧高效的特点足以满足系统需求,通过JDBC驱动程序和数据库进行无缝连接。前端采用可以跨平台的Html、Css、JavaScript、Ajax等技术进行开发。本系统采用intelliJ IDEA集成开发环境、Tomcat服务器进行程序开发和发布。本系统采用的技术和开发环境在实际的开发中应用非常广泛,充分说明本系统在技术方面可行。
2.2.2 经济可行性
本系统可以运行于现在市场上出售的各种个人电脑,系统成本主要集中在系统的开发上。当系统投入运行后,可以实现在网上销售图书及管理库存功能。所带来的效益远远大于系统软件的开发成本。在经济上是可行的。
2.3 系统功能
网上书店系统主要包括前台网站和后台管理两个部分。前台网站实现图书的动态展示、购物车管理、客户信息注册登陆管理、订单处理等功能模块,后台管理系统主要实现管理员对前台网站进行日常管理和信息发布,即对用户、图书、订单等的管理功能。经过综合分析,确定了网上书店系统主要包括以下功能。
2.3.1 用户登陆注册
用户需要有个账号来储存自己的个人信息、购物信息等。
2.3.2 浏览与搜索图书
用户在购买书籍前需要浏览上架的图书来进行选择。
2.3.3 购物车管理
用户对自己的购物车可以进行对书籍数量的添加和减少、移除等操作。
2.3.4 提交订单和订单管理
用户对挑选好要购买的商品可进行购买,购买后可查询自己的购买信息等。
2.3.5 后台管理
书店的管理人员要能处理用户提交的订单请求、能管理书店所发布的图书等。
第3章 概要设计
3.1 系统设计模式
3.1.1 用例图(Use case diagram):
3.2 系统总体结构
3.2.1 系统架构图:
3.3 持久层设计
3.3.1 数据库总体E-R图:
3.3.2 实体E-R图:
1) 用户实体的E-R图,如图3.3.2.1所示:
图3.3.2.1 用户实体的E-R图
2) 订单实体的E-R图,如图3.3.2.2所示:
图3.3.2.2 订单实体的E-R图
3) 订单条目实体的E-R图,如图3.3.2.3所示:
图3.3.2.3 订单条目实体的E-R图
4) 图书实体的E-R图,如图3.3.2.4所示:
图3.3.2.4 图书实体的E-R图
5) 类别实体的E-R图,如图3.3.2.5所示:
图3.3.2.5 类别实体的E-R图
6) 购物车实体的E-R图,如图3.3.2.6所示:
图3.3.2.6 购物车实体的E-R图
第4章
详细设计与系统实现
4.1 业务逻辑设计与实现
4.1.1 业务逻辑的设计:
4.1.2 业务逻辑层的实现:
用户相关操作、图书管理、订单处理以及购物车相关操作:
4.2 表现层设计与实现
4.2.1 首页:
4.2.2 管理员登陆后显示选项:
4.2.3 管理员工作台界面:
4.2.4 管理员添加图书界面:
4.2.5 普通用户登陆后显示选项:
4.2.6 购物车界面:
4.2.7 订单界面:
4.3 项目难点及解决方案
4.3.1 添加图书时,一个图书信息既有图片文件又有普通表单项,此时普通表单不能满足要求,后台对含有文件输入的表单也要特殊处理。
解决:设置form表单中的enctype属性为multipart/form-data,在后台对表单的文件项和普通项分别处理
4.4 典型代码片段与设计过程
4.4.1 添加图书(处理enctype属性为multipart/form-data的表单):
@WebServlet("/AddBookServlet")
public class AddBookServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//将表单提交的数据放在Book类中
Book b = new Book();
//判断前端form表单是否为enctype="multipart/form-data"属性
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
//如果前端传过来的表单不是enctype="multipart/form-data"属性
if(!isMultipart){
throw new RuntimeException("该请求不支持文件上传");
}
//创建一个DisFileItemFactory对象
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建ServletFileUpload的对象,该对象是上传的核心组件
ServletFileUpload sfu = new ServletFileUpload(factory);
//使用解析器解析上传的表单数据,每个FileItem对应一个表单项
List<FileItem> fileItemList = null;
try {
fileItemList = sfu.parseRequest(request);
} catch (FileUploadException e) {
e.printStackTrace();
}
//遍历表单项集合
for (FileItem item : fileItemList) {
if (item.isFormField()){
//普通表单项
String fieldName = item.getFieldName();//字段名
String fieldValue = item.getString("utf-8");//字段值
if(fieldName.equals("bookname")){
b.setBookname(fieldValue);
}else if(fieldName.equals("inventory")){
if(fieldValue != null && !fieldValue.equals("")){
b.setInventory(Integer.parseInt(fieldValue));
}
}else if(fieldName.equals("depict")){
b.setDepict(fieldValue);
}else if(fieldName.equals("price")){
if(fieldValue != null && !fieldValue.equals("")){
b.setPrice(new BigDecimal(fieldValue));
}
}else if(fieldName.equals("sellingPrice")){
if(fieldValue != null && !fieldValue.equals("")){
b.setSellingPrice(new BigDecimal(fieldValue));
}
}else if(fieldName.equals("recommend")){
if(fieldValue != null && !fieldValue.equals("")){
b.setRecommend(Integer.parseInt(fieldValue));
}
}else if(fieldValue != null && !fieldValue.equals("")){
if(fieldName.equals("onSale")){
b.setOnSale(Integer.parseInt(fieldValue));
}
}
}else{
//不是普通的表单项,即是上传的是文件
//获取文件保存路径,判断是否存在该目录如果不存在创建
String path = path = this.getServletContext().getRealPath("/img");
File file0 = new File(path);
//判断文件是否存在,不存在就创建
if (!file0.exists() && !file0.isDirectory()) {
file0.mkdirs();
}
//获取文件名称
String fileName = item.getName();
fileName = fileName.substring(fileName.lastIndexOf("\") + 1);
fileName = UUID.randomUUID() + "_" + fileName;
if (fileName.isEmpty()) {
//如果文件名为空
continue;
}
//获取输入流
InputStream is = item.getInputStream();
//创建输出流
File file = new File(path, fileName);
FileOutputStream fos = new FileOutputStream(file);
byte[] bytes = new byte[1024];
int len = -1;
while((len = is.read(bytes)) != -1){
fos.write(bytes, 0, len);
}
String imgAdd = "/img/" + fileName;
System.out.println(imgAdd);
b.setImgAddress(imgAdd);
}
}
if(b.getBookname() == null || b.getBookname().equals("")){
response.getWriter().write("书名不能为空!1秒后重新添加");
response.setHeader("refresh", "1;url=" + request.getContextPath()
+ "/addBook.html");
} else {
//调用业务逻辑
BookService bs = new BookServiceImpl();
try {
//执行添加操作
bs.addBook(b);
//分发转向
String path="/WEB-INF/admin/backstage.html";
request.getRequestDispatcher(path).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4.4.2 数据交互(根据请求参数的不同向html返回不同的Json格式数据):
@WebServlet("/NewsServlet")
public class NewsServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String id = request.getParameter("id");
HttpSession session = request.getSession();
if(id.equals("reg")){//返回用户名是否为空或重复
String username = request.getParameter("username");
String result = "";
//将表单提交的数据放在User类中
User u = new User();
u.setUsername(username);
//调用业务逻辑
UserService us = new UserServiceImpl();
try {
result = us.judgeUsername(u);
} catch (Exception e) {
e.printStackTrace();
}
if(result.equals("null")){
out.print("null");
}else {
if(result.equals("true")){ //用户名重复
out.print(true);
}else if(result.equals("false")){
//用户名不重复时
out.print(false);
}
}
}else if(id.equals("book")){//返回用户信息和findOnSaleBooks的集合
BookService bs = new BookServiceImpl();
try {
List bookList = bs.findOnSaleBooks();
Object userS = session.getAttribute("user");
//把集合中的数据转换为字符串返回到页面
String newsJ = "";
List news = new ArrayList();
news.add(userS);
for(int i = 0;i < bookList.size(); i++) {
news.add(bookList.get(i));
}
//使用json格式进行数据传输
newsJ = JSONArray.toJSONString(news);
//将数据响应到客户端
response.getWriter().write(newsJ);
} catch (Exception e) {
e.printStackTrace();
}
}else if(id.equals("shop")){ //返回用户和购物车信息
User user = (User)session.getAttribute("user");
List<ShopCart> shopCartList = new ArrayList<>();
if(user != null){
//用户登陆
//获取该用户购物车List
ShopCartService shopCartService = new ShopCartServiceImpl();
try {
shopCartList = shopCartService.findByUserId(String.valueOf(user.getId()));
} catch (Exception e) {
e.printStackTrace();
}
//获取用户session
Object userS = session.getAttribute("user");
//将session和购物车打包
List news = new ArrayList();
news.add(userS);
if(shopCartList!=null){
for(int i = 0;i < shopCartList.size(); i++) {
news.add(shopCartList.get(i));
}
}
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
//将数据响应到客户端
response.getWriter().write(newsJ);
}else if(user == null){
//未登录
//获取用户session
Object userS = session.getAttribute("user");
List news = new ArrayList();
news.add(userS);
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
//将数据响应到客户端
response.getWriter().write(newsJ);
}
}else if(id.equals("myOrder")){ //返回用户和订单和订单详情
User user = (User)session.getAttribute("user");
if(user != null){
List news = new ArrayList();
news.add(user);
OrderService orderService = new OrderServiceImpl();
//获取用户订单
List<Order> orders = orderService.findOrdersByUserId(user.getId());
System.out.println(orders);
//获取迭代器遍历List
Iterator iter = orders.iterator();
while(iter.hasNext()) {
//向下转型
Order order = (Order) iter.next();
news.add(order);
//获取订单详情
List<OrderItem> orderItems = orderService.findOrderItems(order.getId());
for(int i = 0;i < orderItems.size(); i++) {
news.add(orderItems.get(i));
}
news.add("stop");
}
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
System.out.println(newsJ);
//将数据响应到客户端
response.getWriter().write(newsJ);
}else{
//未登录
//获取用户session
Object userS = session.getAttribute("user");
List news = new ArrayList();
news.add(userS);
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
//将数据响应到客户端
response.getWriter().write(newsJ);
}
}else if(id.equals("allOrder")){//返回用户和所有订单
User user = (User)session.getAttribute("user");
if(user != null){
List news = new ArrayList();
news.add(user);
OrderService orderService = new OrderServiceImpl();
//获取所有订单
List<Order> orders = orderService.findAllOrders();
//获取迭代器遍历List
Iterator iter = orders.iterator();
while(iter.hasNext()) {
//向下转型
Order order = (Order) iter.next();
news.add(order);
//获取订单详情
List<OrderItem> orderItems = orderService.findOrderItems(order.getId());
for(int i = 0;i < orderItems.size(); i++) {
news.add(orderItems.get(i));
}
news.add("stop");
}
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
System.out.println(newsJ);
//将数据响应到客户端
response.getWriter().write(newsJ);
}else{
//未登录
//获取用户session
Object userS = session.getAttribute("user");
List news = new ArrayList();
news.add(userS);
//使用json格式进行数据传输
String newsJ = "";
newsJ = JSONArray.toJSONString(news);
//将数据响应到客户端
response.getWriter().write(newsJ);
}
}
}
}
第5章
测试与部署
5.1 系统测试
5.1.1 Pc端测试:
用电脑对目标网站进行访问,对网站的功能模块进行逐一的测试,并在测试中发现书店的购物车为空时点击购买会出现页面错误,经过修改代码修复了这个bug。
5.1.2 移动端测试:
使用手机对网站进行访问并经过,注册、登陆、添加购物车、查看订单逐步对网站进行了测试,未发现漏洞。
5.2 系统部署
服务器镜像:windows server 2016
- 建ftp站点用来传输文件
- 安装MySQL
- 安装Tomcat
- maven打包项目
- 部署项目到服务器Tomcat
第6章 课程设计总结
6.1 系统基本软件度量数据
1. LOC(Line Of Code)
LOC:2776
CLOC (注释行数): 345
BLOC(空白行数): 482
Requirement: >600
- Function Point = UFC * VAF
Factor |
count |
Weight |
Note |
Input |
5 |
16% |
|
Output |
5 |
16% |
|
Transaction |
9 |
60% |
|
Domain model |
5 |
16% |
|
Query |
20 |
38% |
|
file |
46 |
100% |
|
Interface |
8 |
38% |
|
Requirement: >=3 Function Points
6.2 课程设计项目的收获与展望
通过这次课程设计,我更加深入地了解了Java SE和Java EE的许多功能与原理,提高了实践能力。在课程设计过程中,我遇到了很多问题,如在上传文件的表单的处理、Json传输数据的封装等,最终在小组的共同努力下,这些问题都一一得到圆满解决,系统还有以下部分有待完善:
(1) 数据库安全性还有待加强。
(2) 功能还可以更完善,如可以增加顾客对自己信息的修改权限,例如联系方式、住址等的更改。
(3) 代码的优化也还有进步空间,许多方便快捷的第三方框架也还未使用。
这次课程设计使我们更加熟悉的掌握了Java语言和SQL语句的运用,帮助我们熟悉了更多IDEA和Mysal8.0的功能,提高了我们的动手能力,在实践中能够及时的发现问题、解决问题,学到了许多解决实际问题的宝贵经验.同时也挖掘出了我们潜在的能力,使我们对自己更有自信,对编程也更有兴趣。
最后,衷心感谢袁老师的悉心指导,感谢这次课程设计的机会,使我们得到了很好的锻炼,学无止境,我们现在了解的东西还很少,还不能很好地掌握自己的专业知识,我们要谦虚的积极认真学习,不断的增强自身的能力,提高个人素质,向一个真正的IT人士发展。