搜档网
当前位置:搜档网 › 基于JAVA的购物网站(含源文件)

基于JAVA的购物网站(含源文件)

基于JAVA的购物网站(含源文件)
基于JAVA的购物网站(含源文件)

1 引言

自从B2C购物出现在人们的视野中,电子商务就在全世界范围内受到了格外的关注,并且得到了快速的发展。从现实角度来看,目前购物网站的普遍用户是购买者难以自己想要购买的商品甚至用户在耗费很大的精力和时间后即使找到了自己想要的产品,最后却由于其他原因而放弃购买。很多报道指出,推销商们普遍对目前的网络行销感到失望,尽管如此,电子商务无疑是目前最好的在线商品展示的媒体和工具。然而,网上产品展示的目的不仅仅是展示产品,而更重要的是通过让客户更多地了解产品而提高产品的购买率。因此,购物网站目前所面临的最大挑战之一就是网站的设计,如何使得网页能够有效地展示自己的产品,同时方便用户的使用,使用户以愉悦的心情选购称心如意的商品。

本系统的目的和意义就是应上述挑战而尝试为用户提供一个操作简单方便的网上交易系统。利用本系统,用户可以自由地浏览商品,注册成为网站会员,选择商品加入自己的购物车,而后生成订单,实现网上购物。

2 系统应用的关键技术

2.1 EXTJS MVC的介绍

ExtJs 前台我分为了 model,store,view,controller层4层架构,对于model 层 ,用于接收后台传入的Pojo封装成前台数据Model中,创建一个model需要define 的一个继承于Ext.data.Model的一个类,其中关键不可少的配置项是fields,例如fields:[{ name:"id",type:"int",srotable:true},

{ name:"text",type:"string",srotable:true}]

其中name代表字段名称,type为字段类型,类型只有string、float、int、boolean、date、 auto(默认值, 意味着无convert方法)6种对应后台pojo,形成一条数据,而stroe层则是数据集合,也就是model的集合。开发时我们经常是用代理的方式从后台获取一条json数据,形成stroe,如

proxy:{

type:"ajax",

url:"./category/combo_category.do",

reader:{

type:"json",

root:"rows"

},

writer:{

type:"json"

}

}

是用ajax的代理方式从后台获取一个数据集,stroe还得指定你使用的model是那个,model配置项就可以指定你要指定的Model类,用字符串的形式写上类名即可配置好stroe.这时候搭建主面板视图,主面板是一个border布局,上方是login信息以及系统名称,左边属性图,中部是数据表格以及一些表单。完成的mvc架构还需要controller层,这时候我们要先建立一个app.js,内容如下:

Ext.onReady(function(){

Ext.QuickTips.init();//开启提示功能

Ext.Loader.setConfig({//动态加载js文件

enabled : true

});

Ext.application({

name : "core",//名称

appFolder : "./core",//所在的目录

launch:function(){

Ext.create("Ext.container.Viewport",{

layout : "fit",

border : 0,

items : [{

xtype : "mainviewlayout"

}]

});

},

controllers : ["core.app.controller.MainController"] });

});

我们用一个Viewport搭建系统主界面,其中items中放入的mainviewlayout就是系统主视图的别名,通过这种方式可以直接加载mianviewlayout类到页面, Cotrollers配置的则是我们的控制器层,控制器层的声明也相当的简单,创建一个继承与Ext.app.controller的类,写一个初始化方法中的this.controller方法中则是我们控制界面按钮效果的主要地方。我在搭建这套界面是写了一个公用的加载其他控制器和页面视图的方法:

this.addFunItem=function(funInfo){

if(funInfo){

var mainView=funInfo.mainView;

var funPanel=mainView.down(funInfo.funViewXtype);

if(!funPanel){

self.application.getController(funInfo.funController).init();

funPanel=Ext.create(funInfo.funViewName);

mainView.add(funPanel);

mainView.setActiveTab(funPanel);

}else{

mainView.setActiveTab(funPanel);

} } },

传入funInfo是一个js对象,用来加载不同views,models,stores,实现点击左侧树形图,加载不同的数据表格表单树形等不同的数据展示效果.

2.2 数据表格的形成

ExtJS中的数据表格中的每一条数据对应的都是Model,所有记录则是一个数据集合,所以数据表格中我们肯定要配置的有stroe对象,为了形成数据表格中可以形成复选框多选的效果我们需要加入的配置项有

selModel:{

selType:"checkboxmodel"

},

multiSelect:true,

使用的是复选形式的选择模式,数据表格必不可少有colums,也就是列模式,规范我们接收store数据形成表格的展现形式如:

columns:[

{text:"商品名称",dataIndex:"name",width:100}, ],

text表示的每列展示的名字,dataIndex则是需要展示的字段,一般我们在生成一个数据表格的时候我们都会在表格头上加几个按钮,用来管理数据表格的增删改,这个功能实现只要用tbr里面放几个按钮,分别给上他们响应的rel属性,方便我们在控制器中查找,实现控制功能,常见的数据表格还会有分页展示,以及搜索框,

bbar:{

xtype:'pagingtoolbar',

store:'core.product.store.ProductStore',

dock:'bottom',

displayInfo:true

}

bbar中放入的就是一个分页的组件,他也需要一个数据集合stroe,dock表示地定位的位置,而搜索框我们一般用一个触发器组件来形成,做一个前台的过滤效果即可。如"->",

'按名称查询:',

{

xtype: 'triggerfield',

triggerCls: Ext.baseCSSPrefix + 'form-search-trigger',

listeners:{

"change":function(_this,_new,_old,_opt){

var _store = _this.ownerCt.ownerCt.getStore();

_store.clearFilter(false);

_store.filter("name",_new); } },

onTriggerClick: function() {

var _store = this.ownerCt.ownerCt.getStore();

_store.clearFilter(false);

_store.filter("name",this.getValue());

}

},

这样简单的搜索功能我们就可以实现了。

2.3 树的形成

定义一个类继承于Ext.tree.Panel.本系统的主界面的树形使用的是本地树,不同过后台生成,直接前台固定数据,生成的固定的树结构,树同样需要数据就有store 的配置以及树的items配置主要配置的就是树的各个节点,本系统每一个小菜单就是

一颗树,通过前面定义的加入新的视图和控制器的方法来加载不同的页面都需要传入树的节点信息。

2.4 数据库的连接

本系统数据库的连接使用的MyBatis框架的数据连接,用配置文件配置数据库连接属性,本次我没有使用外部属性文件,而是直接使用配置的固定参数,先配置一个数据源 dataSource,让他直接指向类

org.springframework.jdbc.datasource.DriverManagerDataSource,配置参数driverClassName的value为com.mysql.jdbc.Driver,

url为jdbc:mysqlL..localhost:3306/lzl?

characterEcoding=utf-8&useUnicode=true

在配置数据库访问账号密码,这样我们就和数据库连接上了。

2.5 系统的运行环境

本系统前端使用mvc模式的ExtJS4.1后台使用springmvc,spring,mybatis整合,使用的服务器是tomcat7.0,在eclipse编译器下运行即可,操做系统 Windows 7,在火狐浏览器下进行测试.

2.6 springmvc工作流程

1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;

2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;

3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)

4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等

数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult 或Error中

5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;

6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;

7. ViewResolver 结合Model和View,来渲染视图

8. 将渲染结果返回给客户端。

2.7 spring依赖注入,控制反转

IoC,即控制反转。他使程序组件或类之间尽量形成一种松耦合结构,开发者在使用类的实例之前,需要先创建对象的实例。但是IoC将创建实例的任务交给IoC容器,这样开发应用代码时只需要直接使用类的实例,这就是IoC。通常用一个好莱坞原则(请不要打电话给我,我会打电话给你。)来比喻这种控制反转的关系。依赖注入有3种类型注入,spring支持2种,setter注入和构造器注入,在项目中我使用的是注解方式的注入,在配置文件中配置了com.lzl包下的类自动注入到容器中,在我们需要用到这些类的时候,我们只需声明该类,然后使用一个@autowired注入想要使用的类,其中控制器我们使用的Controller注解标识为控制器,业务逻辑层我们使用的service注解。这样spring容器就能管理好我们的类。

2.8 spring AOP

3 系统需求分析和总体设计

3.1 系统功能需求

在本系统中用户管理、购物车管理、订单管理、产品展示,商品管理,广告管理六个模块。

分为前台展示项目和后台管理项目。

(1)购物车管理:实现添加商品、取消一个商品、数量修改、清空购物车功能。(2)订单管理:实现提交订单、删除订单、查询订单、订单审核功能。

(3)前台展示:实现产品列表、产品明细功能。

(4)用户管理:实现用户注册、用户信息修改、用户删除、用户查询功能。

(5)商品管理: 实现对商品的添加,对商品信息的修改,对商品的删除。以及按类别查询商品,按名称查询商品功能。

(6) 广告管理: 对主页面广告部分的管理,实现广告的动态化,页面广告信息的更新。

3.2 系统角色及其功能分析

3.2.1 系统中有3个角色:

(1)注册用户

(2)管理员

(3)游客

3.2.2 系统角色的功能

(1)普通用户

网站的普通浏览者(即游客),可以浏览商品和添加本地购物车。

(2)注册用户

普通浏览者只要注册为网站用户后,登录成功后有以下功能:

登录,登出,向购物车中添加商品,查看个人信息,生成并提交订单。添加或修改个人明细资料。

(3)管理员

登录成功后,进入后台项目,对前台展示的动态管理,以及用户商品等管理,对订单的审核。

3.3 总体设计思想概述

本系统是基于B/S架构下的多层结构应用系统。B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。

在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。推荐的分层式结构一般分为三层,从下至上分别为:数据访问(dao)层、业务逻辑层、表示层

总的来说,采用分层结构的设计思想,可以让每个层由一组相关的类或组件构成,共同完成特定的功能。层与层之间存在自上而下的依赖关系,上层组件会依赖下层组件的API,而下层组件则不依赖于上层组件。例如:表述层依赖于业务逻辑层,而业务逻辑层依赖于数据库层。并且每个层对对上层公开API,但具体的实现细节对外透明。当某一层发生变化,只要API不变,不会影响其他层的实现。

在本系统中,使用开源的mysql数据库,持久层用到spring所集成的mybatis 技术,业务逻辑层用普通javabean实现,表述层运用基于springmvc的MVC设计模式(springmvc用来做C层,spring实现V层与C层的解耦以及C层与M层的解耦)。

3.4 数据库设计

图3-1 数据库E-R

sex int 11允许phone varchar155允许

3.5 系统的类设计

3.5.1 DAO类设计

通过这个mybatis获取对应的DAO,然后使用DAO进行数据库操作,每个dao对应一个Mapper配置文件,进行Sql的配置,在本系统中,dao的一般使用都使用了BaseProvice类,根据约定实体用@param(“entity”)标识,分页参数用

@param(“pageNum”)和@param(“pageSize”)标识,这样就能友好的被读取,按照约定还有实体中的其他对象属性要用@ObjectAlt注解标志,集合用@ArrayAlt标志,这样的标识都可以方便我们更好的识别其属性到底是个什么类型,其次做条件查询时,是用entity标识的实体中有不为空的属性且不为空字符串时就会被and连接,保存也是实体中不为空的属性都会进行保存,主键必须为空,数据库进行主键的自动增长

3.5.2 JacksonUtil类设计

本类中实现了一个mapToJson方法,参数为一个Object的对象。返回值为一个String类型的json对象,本类可以将对象或者集合传化为JSON格式的字符串,用的是JackSon Jar包。

3.5.3 ObjectAlt注解类设计

用@Target(ElementType.FIELD)标识表示可以使用在属性上,在使用

@Retention(RetentionPolicy.RUNTIME) 在运行时检测,最后方法中声明一个String value(),本类用来标识实体类中的对象属性。

3.6系统的用例图

添加新用户

如图3-5,购物车管理模块主要包括:添加商品、取消一个商品、数量修改、清空购物车四个功能组成。

图4-1 系统前台功能设计

图4-2 系统后台功能设计

图4-3 系统总体功能设计

图4-4 个别功能设计

5 系统的详细设计

5.1 BaseProvice类

这个类重要是复用型的后台动态SQL语句的生成,在dao层使用@selectkey注解指定type为BaseProvice.class,method为指定的方法,

5.1.1 isString 方法

该方法返回值为一个String ,参数为Field field,Map map,String sql三个,通过field.getType().toString().contains("String"),判断出这个属性为string属性,然后在判断这个属性不为空的字符,这时候我就进行了模糊查询and连接方式的拼接,用传入的sql参数的concat方法拼接“and”

+StringUtil..StringtoCoulm(field.getName(),在拼接like Concat

(‘%’,#{entity,加上field的getName方法拼接属性名称上去,

StringUtil.StringtoCoulm方法是将属性格式化为字段的方法,如mebmerPrice就会格式化成mebmer_price,最后返回sql即可。

5.1.2 isObject 方法

该方法返回值为一个String ,参数为Field field,Map map,String sql三个,通过field的getAnnotation(ObjectAlt.class)方法不为空的话我们就通过 field.get(map.get(‘entity’),得到一个Object的对象,通过

Object对象的getClss().getDeclaredFields(),得到属性的数组,循环遍历属性数组,循环中先设置私有属性可访问,然后通过fields1[j].get(obj),得到这个属性,判断这个属性如果是id的话在进行拼接sql=sql.concat("

AND"+StringUtil.StringtoCoulm(fields1[j].getName())+" =

#{ entity."+field.getName()+"."+fields1[j].getName()+"}");就可以将外键属性的id进行拼接进入,最后返回sql即可。

5.1.3查找单个对象

首先我们在BaseProvice类下建立一个名为findOne返回值为String值参数为一个map的方法,其次通过 map.get("entity").getClass()得到一个map中

@param(“entity”)注解标识为实体的Class对象,然后我们声明一个String类型的字符串,初始化为”select * from ”,通过concat方法用刚刚得到的Class对象的getSimpleName()方法得到类名,约定好lzl_+类名就为数据库表名,这时候就得到了Select * from 表名 ,最后我们在通过concat方法拼接where id=#{entity.id},返回字符串sql。

5.1.4 通过条件查找对象集合

先声明一个名为findList返回值为String参数为Mapmap的方法,通过map.get(“entity”)得到@param(“entity”)注解标识为实体的Class对象,声明一个String类型的字符串,初始化为select * from,通过concat方法拼接

"lzl_"+clazz.getSimpleName()+" WHERE 1=1",得到的sql为 select * from表名where 1=1,这时候我们调用Class对象的getDeclaredFields()方法得到属性的数组fields,对属性数组进行遍历,在循环开头我们需要设置可以访问私有属性,这句代码就是设置访问私有属性,fields[i].setAccessinble(true),然后进行判断这个属性在实体中是否为空fields[i].get(map.get("entity"))!=null,不为空的时候我们对属性的类型进行判断,这时候我们就要用得isString,isInteger ,isObject 方法,最后返回sql。

5.1.5通过条件查找对象集合带分页

这个方法中我们只需要调用上放的findList方法,最后我们将sql

Concat方法拼接 limit #{pageNum},#{pageSize},最后返回sql。

5.1.6 带条件的查询数据总数

这个方法我们也是先调用findList方法得到所有的记录,然后通过sql的replace方法将*替换为count(*),返回sql即可。

5.1.7 增加一条记录的方法

声明一个名为save返回值为String参数为map的方法,首先我们通过

map.get(‘entity’).getClass()得到对象的Class对象,声明二个String字符串,

一个为sql初始化为insert into,sql1初始化为 values (;给sql字符串拼接上表

名,通过sql.concat("lzl_"+clazz.getSimpleName()+" ( "),用class对象的getDeclaredFields()得到所有的属性,遍历属性数组,设置可以访问私有属性,通

过fields[i].getAnnotation(ObjectAlt.class)!=null时,对sql进行

sql=sql.concat(StringUtil.StringtoCoulm(fields[i].getName())+"_id ,");对

sql1进行sql1=sql1.concat(" #{entity."+fields[i].getName()+".id},");然后

continue出去,在判断if(fields[i].getAnnotation(ArrayAlt.class)!=null),在

continue出去,在判断该属性是否是id属性,是的话

sql=sql.concat(StringUtil.StringtoCoulm(fields[i].getName())+","); sql1=sql1.concat(" #{ entity."+fields[i].getName()+"},");最后将sql的最后

一个’,’替换为‘)’sql.substring(0, https://www.sodocs.net/doc/7c5868600.html,stIndexOf(",")).concat(")

");sql1的最后一个‘,’替换为‘)’sql1=sql1.substring(0,

https://www.sodocs.net/doc/7c5868600.html,stIndexOf(",")).concat(")");最后返回 sql.concat(sql1)就得到了增加

语句

5.1.8 根据id修改的方法

5.1.9 根据对象修改的方法

声明一个名为update返回值为String参数为map的方法,声明2个字符串分

别为sql和where 初始化为“update”和“where id=#{entity.id}”,通过

map.get(entity).getClass()得到class对象声明为clazz,给sql拼接表名并加

上set字符串,通过clazz.getDeclareFields()得到所有的属性,设置可以访问私

有属性,判断是否为id属性是的话不拼接,在判断是否是对象,通过

fields[i].getAnnotation(ObjectAlt.class)!=null判断是对象,是对象的话给

sql拼接sql=sql.concat(StringUtil.StringtoCoulm(fields[i].getName())+"_id

= #{entity."+fields[i].getName()+".id}");在continue出去,在通过

fields[i].get( map.get("entity"))!=null判断当前属性值不为空,在拼接以下语

句sql=sql.concat(StringUtil.StringtoCoulm(fields[i].getName())+"=

#{ entity."+fields[i].getName()+"},");最后去除掉字符串的最后一个字符

sql=sql.substring(0,sql.length()-1);返回sql.concat(where)即可

5.1.9 根据id删除的方法

声明一个名为remove 返回值为String参数为map ,先声明一个sql的字符串,

初始化为delete from,通过map.get("entity").getClass()得到Class对象,

然后拼接lzl_"+clazz.getSimpleName() where id=#{id},最后返回sql即可

5.2 主要模块的设计说明与界面

5.2.1用户管理模块

用户管理模块主要包括用户注册,登录,退出、删除、修改

相关主题