首页 > 代码库 > 网上在线商城项目总结

网上在线商城项目总结

大概做了三个星期的网上在线商城终于完成,过程中学到了很多的知识,特别是实际软件开发流程和规范,一个最深的感受就是在一个如此大的系统中一个人完成所有功能模块是不可能的,团队是很重要的,在这个项目中前台页面借鉴了一些优秀的网站,后台的功能主要为自己和团队的另外一个同学完成,整个项目的业务逻辑都设计得较为简单,故完成得时间较快,其中仍然有一些小问题需要改善,在日后的学习中我们都会进一步优化。

网上在线商城项目 :
这个系统整合了商品展示、商品管理、商品类别管理、购物车、会员管理等功能,提供了简易的操作,丰富的功能和完善的权限管理,为用户提供了一个低成本、高效率的网上商城建设方案。这个项目在商品类别设计中采用了树状层次设计结构;在前台可以分类浏览所有商品详细信息,下订单购买商品,查看购物车状态以及购买用户的反馈信息;在系统后台可以管理会员、管理商品和商品类别,并使用上传组件上传商品图片,管理查看商品库存以及进货渠道,并使用报表组件将商品的销售情况做成图表,供商城管理者做市场分析。前台对数据的修改使用Ajax技术直接与后台交互,提高了用户体验。

Web项目开发的一般流程--总纲
1.需求确定(通过各种手段确定系统的功能与性能):
<1.功能:购物、注册、浏览、搜索
<2.性能:可同时支持n个并发访问,并且响应时间不低于m毫秒...
<3.手段:头脑风暴(brain storm)、会议、询问、原型-界面原型、业务原型
本阶段是项目开发的最重要阶段,在web项目中,通常界面设计会在本阶段进行。
2.分析与设计
<1.架构分析与设计:
<<1.逻辑架构:
3层架构、n层架构(分层是各层独立,加大重用的机会,但是开发成本更大)
MVC
Model1(jsp直接访问数据库) fro Model2(jsp+javabean访问数据库)
...
<<2.物理架构:
Web服务器的分布
数据库服务器的分布
...
<<3.技术解决方案的确定
java/.net
Open Source/商业
...
<2.业务逻辑分析(本阶段与需求的确定密切相关,通常在确定需求的时候就会进行相关的分析,根据需求分析业务逻辑):
<<1.有哪些人会使用本系统
<<2.他们会使用本系统做什么
<<3.通常他们使用本系统的步骤是什么样的
<<4.会有哪些明显的类来支撑本系统的运行
<<5.会有哪些不同的提示会反馈给用户
...
<3.业务逻辑设计(不同项目可能不尽相同):
<<1.根据需求的分析来确定具体的类
<<2.确定类的属性
<<3.确定类的接口和方法
<<4.确定类之间的关系
<<5.确定用户操作流程在设计上的反映
<<6.数据库的设计
<4.界面设计
<<1.设计系统的界面风格(颜色、style)
<<2.设计系统的具体“模拟”界面
<<3.能够从头走到尾
<<4.方便进行需求的确定
<<5.方便JSP程序员的开发
3.开发环境搭建
<1.开发工具的确定
<2.配置管理工具的确定
<3.测试工具的确定
<4.文件服务器/配置服务器等的确定
...
4.开发-测试-开发-测试
<1.按照设计进行开发
<<1.迅速开发原型
<<2.进行迭代开发
<<3.提早进行测试
<<<1.单元测试
<<<2.黑盒测试
<<<3.性能测试
<<<4.易用性测试
...
5.文档编纂
<1.需求描述文档
<2.系统分析与设计
<3.数据库设计
<4.开发接口API docs & 源代码的注释
<5.用户帮助(前台)
<6.管理员手册(后台)
<7.测试文档

本项目的开发流程:
1.需求确定
<1.不同用户可以通过系统浏览商品(按类别)
<2.普通用户可以通过系统搜索商品(按类别、价位、日期等)
<3.普通用户可以通过系统下订单(享受市场价)
<4.普通用户可以注册成为系统会员(免费注册)
<5.会员可以浏览和检索商品
<6.会员可以下订单(享受会员价)
<7.会员可以浏览自己下过的订单
<8.会员可以管理自己的信息(自服务系统),如:修改密码、修改送货地址、修改联系方式
<9.会员可以分级别(不做s):
<<1.不同级别享受不同等级的优惠
<<2.通过购物的金额确定级别
<10.管理员通过后台进行会员管理
<<1.会员浏览
<<2.会员历史订单浏览
<<3.会员删除
<<4.指定会员级别
<11.管理员通过后台进行产品分类的管理,如:浏览、添加、删除、修改
<12.管理员通过后台进行产品管理,如:
<13.管理员通过后台进行订单的管理,如:订单查询、修改订单状态、订单搜索、订单跟踪、订单提醒

2.架构分析与设计
<1.逻辑架构:JSP+JAVABEAN+DATABASE
JSP负责表现
javabean负责业务逻辑
database负责持久保持数据
<2.物理架构
WEB服务器一台
database服务器一台
<3.技术解决方案
webserver-tomcat5.5
database-mysql5.0

3.业务逻辑分析
<1.会员类(User)
包装系统会员
与订单类有一对多的关系
properties:
id
username
password
phone
addr
rdate
methods:
getOrder()
save()
change()
delete()
static search()

<2.管理员类(Administrator)
包装系统管理员
properties:
username
password
methods
login()

<3.产品类(Product)
包装产品的信息
与订单是多对一的关系
properties:
id
name
descr
normalPrice
menberPrice
pdate
category
methods:
getCategory
getSalesCount()
save()
change()
search()

<4.类别类(Category)
包装产品的类别
树状结构
与产品是一对多的关系
properties:
id
name
descr
pid(parent:Category)
methods:
getProductCounts()
save()
change()

<5.订单类(SalesOrder & Saleitem)
包装订单的信息
与产品是多对多的关系
与会员是多对一的关系
properties:
id
userid
addr
SalesItem[]
odate
methods:
getTotalPrice()
save()
change()
getSalesItems()

<6.购物车类(ShoppingCart & CartItem)
包装购物车的信息
与产品是一对多的关系
properties:
productID
unitPrice
pCount
methods:
getTotalPrice()

 

4.数据库的设计
User
id int
username varchar
password varchar
phone varchar
addr varchar
rdate datetime
Product
id int
name varchar
descr varchar
normalprice varchar
memberprice varchar
pdate datetime
categoryID int
Category
id int
name varchar
descr varchar
pid varhar
SalesOrder
id int
userid int
addr varchar
odate datetime
status int(o未处理 1处理成功 2废单)
SalesItem
id int
productid int
unitprice varchar
pcount int
orderid id

5.界面设计
前台
<1.首页index.jsp
显示某类商品
根据id显示图片
搜索
注册
登陆
自服务
<2.搜索界面search.jsp
<3.搜索结果searchresult.jsp
<4.注册
注册页面register.jsp
注册成功registerok.jsp
注册失败registererr.jsp
<5.登陆
登陆页面login.jsp
登陆成功loginok.jsp
登陆失败loginerr.jsp
<6.自服务selfservice.jsp
修改密码changepassword.jsp
修改成功changepasswordok.jsp
修改失败changepassworderr.jsp
修改其他信息changeinfo.jsp
修改其他信息成功changeinfook.jsp
修改其他信息失败changeinfoerr.jsp
<7.购物
购物车浏览cart.jsp
结账buy.jsp

后台(位于admin目录下,放置与前台文件重名)
<1.登陆页面login.jsp
<2.首页index.jsp
用户管理
产品管理
类别管理
订单管理
<3.用户管理
显示用户userlist.jsp
删除用户userdelete.jsp
搜索用户usersearch.jsp
<4.产品管理
产品显示productlist.jsp
产品添加productadd.jsp
产品更改productchange.jsp
产品删除productdelete.jsp
产品搜索productSearch.jsp
<5.类别管理
类别显示categorylist.jsp
、 类别添加categoryadd.jsp
类别删除categorydelete.jsp
类别修改categorychange.jsp
<6.订单管理
订单浏览salesorderlist.jsp
订单处理salesorderdeal.jsp
6.其他:
开发工具--eclipse3.2
webserver--tomcat5.5
database--mysql
scm--cvs

开发优先级:
先写用户
再写分类
然后写产品
接下来购物
最后订单处理
其他功能

开发安排:每个版本开发什么功能

1.引入类库mysql-connector-java-5.1.29-bin.jar

2.封装数据库连接(方便修改,如:以后使用不同的数据库则只用修改这个类)

3.写一个javabean分层封装各个业务逻辑类的数据(如:user,category,product等),而不是直接JSP访问。

4.数据库建表:

-----shopping.sql-----

create database shopping;
use shopping;
create table user
(
id int primary key auto_increment,
username varchar(40),
password varchar(16),
phone varchar(40),
addr varchar(255),
rdate datetime
);
create table category
(
id int primary key auto_increment,
name varchar(255),
descr varchar(255),
pid int,
isleaf int,
grade int
);
create table product
(
id int primary key auto_increment,
name varchar(255),
descr varchar(255),
normalprice double,
menberprice double,
pdate datetime,
categoryid int references catetory(id)
);
create table salesorder
(
id int primary key auto_increment,
userid int,
addr varchar(255),
odate datetime,
status int
);
create table salesitem
(
id int primary key auto_increment,
productid int,
unitprice double,
pcount int,
orderid int
);

5.用户注册(利用表单userReg.html修改):

-----register.jsp-----
<%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030" %>
<%@ page import="com.bjsxt.shopping.*" %>

<%
request.setCharacterEncoding("GB18030"); //解决在form表单里头填写中文的解码是的乱码问题,设置request的编码,只对post方式有效
String action=request.getParameter("action");
if(action!=null&&action.trim().equals("register")){ //利用隐藏域的值判断是哪个页面跳转过来的额
String username = request.getParameter("username");
String password = request.getParameter("password");
String phone = request.getParameter("phone");
String addr = request.getParameter("addr");
User u = new User(); //创建新的User把表单传来的值设置进去
u.setUsername(username);
u.setPassword(password);
u.setPhone(phone);
u.setAddr(addr);
u.setRdate(new java.util.Date(System.currentTimeMillis()));
u.save();
out.println("注册成功!恭喜!");
return;
}
%>



<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030">
<script language=JavaScript src="http://www.mamicode.com/script/regcheckdata.js"></script>
<title>用户注册</title>
</head>
<body>
<form name="form" action="register.jsp" method="post" onSubmit="return checkdata()">
<input type=hidden name="action" value="http://www.mamicode.com/register"/>
<table width="750" align="center" border="2">
<tr>
<td colspan="2" align="center">用户注册</td>
</tr>
<tr>
<td>用户名:</td>
<td><input type=text name="username" size="30" maxlength="10">
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type=password name="password" size="15" maxlength="12">
</td>
</tr>
<tr>
<td>密码确认</td>
<td><input type=password name="password2" size="15" maxlength="12">
</td>
</tr>
<tr>
<td>电话</td>
<td><input type=text name="phone" size="15" maxlength="12"></td>
</tr>
<tr>
<td>地址</td>
<td><textarea rows="12" cols="80" name="addr"></textarea></td>
</tr>

<tr>
<td></td>
<td><input type="submit" value="http://www.mamicode.com/提交"> <input type="reset"
value="http://www.mamicode.com/重置"></td>
</tr>
</table>
</form>
</body>
</html>


ps:数据库中使用小写,jsp使用小写,javabean使用驼峰标示

6.后台:admin文件夹

7.用户自服务系统

8.主页

9.类别(Catagory)
有添加根类别,添加类别,修改类别,删除类别的功能

10.产品(Product)

Product
ProductMgr--使用productDAO的一个对象;使用了Product的JavaBean
ProductDAO(接口)
ProductMySQLDAO--实现ProductDAO
ProductOracleDAO--实现ProductDAO

增加产品--productadd.jsp
只可以在叶子节点下添加产品

产品搜索--productsearch.jsp
分为简单搜索和复杂搜索(还有一个简单搜索,一次可以选中多个类别)
在搜索显示中使用搜索分页

(SQLDate和Timestamp都由utilDate继承)

在一个页面中处理三种搜索:
----productsearch.jsp----

<%@ page language="java" import="com.bjsxt.shopping.*" pageEncoding="GBK"%>
<%@ page import="java.util.*"%>
<%@ page import="com.bjsxt.shopping.dao.*"%>
<%@ page import="java.sql.Timestamp"%>

<%@ include file="_sessioncheck.jsp" %>

<%
List<Category> categorys = Category.getCategories();
List<Product> products = new ArrayList<Product>();
int pageCount = 0;
String keyWord = null;
double lowNormalPrice = -1;
double highNormalPrice = -1;
double lowMemberPrice = -1;
double highMemberPrice = -1;
Timestamp startDate = null;
Timestamp endDate = null;
String strStartDate = null;
String strEndDate = null;

String strCategoryQuery = "";

int pageNo = 1;
String strPageNo = request.getParameter("pageno");
if(strPageNo != null && !strPageNo.trim().equals("")){
pageNo = Integer.parseInt(strPageNo);
}

int categoryId = 0;

//处理复杂搜索
request.setCharacterEncoding("GBK");
String action = request.getParameter("action");
if(action != null && action.trim().equals("complexsearch")) {
keyWord = request.getParameter("keyword");
lowNormalPrice = Double.parseDouble(request.getParameter("lownormalprice"));
highNormalPrice = Double.parseDouble(request.getParameter("highnormalprice"));
lowMemberPrice = Double.parseDouble(request.getParameter("lowmemberprice"));
highMemberPrice = Double.parseDouble(request.getParameter("highmemberprice"));
categoryId = Integer.parseInt(request.getParameter("categoryid"));
int[] idArray;
if(categoryId == 0){
idArray = null;
}else{
idArray = new int[1];
idArray[0] = categoryId;
}

strStartDate = request.getParameter("startdate");
if(strStartDate == null || strStartDate.trim().equals("")){
startDate = null;
}else{
startDate = Timestamp.valueOf(request.getParameter("startdate"));
}

strEndDate = request.getParameter("enddate");
if(strEndDate == null || strEndDate.trim().equals("")){
endDate = null;
}else{
endDate = Timestamp.valueOf(request.getParameter("startdate"));
}

products = new ArrayList<Product>();
pageCount = ProductMgr.getInstance().findProducts(products,idArray,keyWord,lowNormalPrice,highNormalPrice,
lowMemberPrice,highMemberPrice,startDate,endDate,pageNo,3);

}
%>

<%
//处理简单搜索2
if(action != null && action.trim().equals("simplesearch2")) {


keyWord = request.getParameter("keyword");
String[] strCategoryIds = request.getParameterValues("categoryid");
int[] idArray;
if(strCategoryIds == null || strCategoryIds.length == 0){
idArray = null;
}else{
for(int i=0;i<strCategoryIds.length;i++){
strCategoryQuery += "&categoryid=" + strCategoryIds[i];
}
idArray = new int[strCategoryIds.length];
for(int i=0;i<strCategoryIds.length;i++){
idArray[i] = Integer.parseInt(strCategoryIds[i]);
}
products = new ArrayList<Product>();
pageCount = ProductMgr.getInstance().findProducts(products,idArray,keyWord,-1,-1,
-1,-1,null,null,pageNo,3);
}
}
%>
<!-- 显示处理结果开始 -->
<center>搜索结果</center>
<table border="1" align="center">
<tr>
<td>ID</td>
<td>name</td>
<td>descr</td>
<td>normal</td>
<td>member</td>
<td>pdate</td>
<td>categoryId</td>
<td></td>
<td></td>
</tr>
<%
for(Iterator<Product> it=products.iterator();it.hasNext();){ //创建user的迭代器,若有next()值,则执行以下语句显示用户信息
Product p=it.next();
%>
<tr>
<td><%=p.getId() %></td>
<td><%=p.getName() %></td>
<td><%=p.getDescr() %></td>
<td><%=p.getNormalPrice() %></td>
<td><%=p.getMemberPrice() %></td>
<td><%=p.getPdate() %></td>
<td><%=p.getCategoryId() %></td>
<td>
<a href="http://www.mamicode.com/productdelete.jsp?id=&keyWord=&keyWord=&keyWord=&keyWord="><%=c.getName() %><br>
<%
}else{
System.out.println(c.isLeaf());
%>
<%=c.getName() %><br>
<%
}
}
%>
</td>
</tr>

<tr>
<td class="altbg1" valign="top">关键字:</td>
<td class="altbg2"><input type="text" name="keyword"></td>
</tr>
</tbody></table>
<br>
<center><input value="http://www.mamicode.com/搜索" type="submit"></center>
</form>

<center>复杂搜索</center>
<form method="post" action="productsearch.jsp" onsubmit="checkdata()" name="complex">
<input type="hidden" name="action" value="http://www.mamicode.com/complexsearch"/>

<table class="tableborder" align="center" cellpadding="4" cellspacing="1" width="97%">
<tbody>

<tr>
<td class="altbg1" width="21%">category:</td>
<td class="altbg2">
<select name="categoryid">
<option value="http://www.mamicode.com/0">所有类别</option>
<%
for(Iterator<Category> it = categorys.iterator();it.hasNext();){
Category c = it.next();
String preStr = "--";
for(int i=1;i<c.getGrade();i++){
preStr += "--";
}
%>
<option value="http://www.mamicode.com/<%=c.getId() "><%=preStr+c.getName() %></option>
<%
}
%>
</select>
</td>
</tr>

<tr>
<td class="altbg1" valign="top">关键字:</td>
<td class="altbg2"><input type="text" name="keyword"></td>
</tr>

<tr>
<td class="altbg1" width="21%">normalprice:</td>
<td class="altbg2">
From:<input name="lownormalprice" size="25" maxlength="25" type="text">To:<input name="highnormalprice" size="25" maxlength="25" type="text">
</td>
</tr>

<tr>
<td class="altbg1" width="21%">memberprice:</td>
<td class="altbg2">
From:<input name="lowmemberprice" size="25" maxlength="25" type="text">To:<input name="highmemberprice" size="25" maxlength="25" type="text">
</td>
</tr>

<tr>
<td class="altbg1" width="21%">pdate:</td>
<td class="altbg2">
From:<input name="startdate" size="25" maxlength="25" type="text">To:<input name="enddate" size="25" maxlength="25" type="text">
</td>
</tr>
</tbody></table>
<br>
<center><input value="http://www.mamicode.com/搜索" type="submit"></center>
</form>
</body></html>

 

代码重构:
在一个页面接受三种搜索请求,根据搜索的不同,重定位到不同的处理页面


前台产品显示:
最新产品,推荐产品(新建一个推荐产品,推荐产品属于该类)

  产品购买(点击时转到产品详细信息展示)

    产品详细信息展示中有购买链接,点击将产品加入购物车

新建购物车类(Cart)和具体的购物物品类(CartItem)

  在购物车页面中可以修改产品的购买数量

  确认订单(可以修改地址),转到order.jsp,

订单管理订单浏览,其中有订单详情和订单修改

文件上传:利用上传组件(主要为产品的图片)

销量报表:利用报表组件Jfreechart

TagLib(标签库):JSP可以自己扩展自己的标签库

**自定义标签示例:
建立一个自定义的,可以运行于JSP文件中的标签,例如<mttag:helloworld>--用于在网页上输出字符串“helloworld”
步骤:
1.编写标签实现类
<1.从javax.servlet.jsp.tagext.SimpleTagSupport中继承
<2.从谢doTag方法,直线在网页上的输出
2.在WEB-INF目录下,或WEB-INF子目录下检录helloworld.tld文件,即自定义标签的说明文件(本例中放置在WEB-INF目录下)
3.建立testTag.jsp文件进行测试
注意:
1.标签处理类必须放置于包中,不能使裸体类
2.不需要像JSP1.2中修改web.xml

主要的调试方法:
1.debug

2.输出

3.删一段测一段

ajax:(发起一步请求,不刷新整个页面的情况下,刷新部分页面,一般为div中的内容)----javascript+xml