SSH网上商城
1.1 前台需求分析:
1.1.1 用户模块:
注册:
1.前台JS校验:
2.使用AJAX完成对用户名异步校验:
3.后台Struts2校验:
4.验证码:
5.发送激活邮件:
6.将用户信息存入到数据库:
激活:
1.点击链接完成激活:
* 根据激活码,查询数据库中是否有该用户:
* 如果有:激活.(将激活码字段清空.)
* 修改用户的状态:
登录:
1.输入用户名和密码:(数据校验.)
2.用户名和密码都正确同时用户状态必须是激活状态:
退出:
1.销毁session:
1.1.2 一级分类模块:
查询一级分类:
1.查询一级分类.
* 将一级分类存入到session范围.(每个页面中都有一级分类的数据)
查询某个一级分类:
1.查询所有一级分类:
* 同时查询到每个一级分类下所属的二级分类
1.1.3 商品模块:
查询热门商品:
1.查询热门商品:(限制个数10个)
查询最新商品:
1.查询最新商品:(限制个数10个)
查询某个分类商品:
1.根据分类的ID进行查询商品:
查询某个二级分类商品:
1.根据二级分类的ID进行查询商品:
查询某个商品信息:
1.根据商品ID进行查询商品:
1.1.4 购物模块:
添加到购物车:
1.将商品信息添加到购物车中:
从购物车中移除商品:
1.将商品信息从购物车中移除:
清空购物车:
1.将所有的商品信息从购物车中移除:
1.1.5 订单模块:
生成订单:
1.将购物车中的信息存入到数据库(生成订单).
* 清空购物车:
为订单付款:
1.在线支付功能:
2.修改订单状态:
3.修改订单的信息:(收货人,联系方式,送货地址)
查询我的订单:
1.根据用户ID查询订单.
查询某个订单详情:
1.根据订单ID进行查询:
1.2 后台需求分析:
1.2.1 用户模块:
添加用户:
添加用户到数据库
修改用户:
修改用户到数据库
删除用户:
删除用户
查询用户:
查询用户(带分页)
1.2.2 一级分类:
添加一级分类:
添加一级分类:
修改一级分类:
修改一级分类
删除一级分类:
删除一级分类:
* 级联删除二级分类:
查询一级分类:
查询一级分类:
1.2.3 二级分类:
添加二级分类:
二级分类需要有所属一级分类:
修改二级分类:
修改二级分类所属的一级分类:
删除二级分类:
删除二级分类:
查询所有二级分类:
查询二级分类(带分页)
1.2.4 商品模块:
添加商品:
1.添加商品所属二级分类:
2.上传商品图片:
修改商品:
1.修改商品二级分类:
2.修改商品图片:
删除商品:
1.删除商品:
查询商品:
1.商品查询:(带分页)
1.2.5 订单模块:
查询订单:
查询所有订单:(带分页)
* 异步加载订单项:
1.3 页面设计:
使用静态页面就OK
1.4 数据库设计:
用户表:
* 用户ID
* 用户名:
* 密码:
* 真实姓名:
* 邮箱:
* 地址:
* 电话:
* 用户状态: 0未激活 1已经激活
* 激活码:
一级分类:
* 一级分类ID
* 一级分类名称
二级分类:
* 二级分类ID:
* 二级分类名称:
* 一级分类ID(外键指向一级分类主键ID)
商品表:
* 商品ID:
* 商品名称:
* 商品商城价格:
* 商品市场价格:
* 商品描述:
* 商品图片:(路径)
* 二级分类ID(外键指向二级分类主键ID)
订单表:
* 订单ID
* 订单时间:
* 订单金额:
* 订单状态:
* 订单地址:
* 订单电话:
* 订单收货人:
* 用户ID(外键指向用户表的主键ID)
订单项表:(需要参与到业务逻辑中)
* 主键ID
* 商品ID
* 订单ID
* 数量
* 小计
后台用户表:
* 用户名:
* 密码:
1.5 编码实现:
1.5.1 搭建开发环境:
SSH整合:
1.创建一个web工程:
2.引入jar包和配置文件:
* struts2:
* jar包:
struts-2.3.15.3appsstruts2-blank.warWEB-INFlib*.jar
struts-2.3.15.3libstruts2-json-plugin-2.3.15.3.jar
struts-2.3.15.3libstruts2-spring-plugin-2.3.15.3.jar
* 配置文件:
* web.xml
<!-- 配置Struts2的核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
* struts.xml
* Spring:
* jar包:
Spring3.2 开发最基本jar包
spring-beans-3.2.0.RELEASE.jar
spring-context-3.2.0.RELEASE.jar
spring-core-3.2.0.RELEASE.jar
spring-expression-3.2.0.RELEASE.jar
com.springsource.org.apache.commons.logging-1.1.1.jar
com.springsource.org.apache.log4j-1.2.15.jar
AOP开发
spring-aop-3.2.0.RELEASE.jar
spring-aspects-3.2.0.RELEASE.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
Spring Jdbc开发
spring-jdbc-3.2.0.RELEASE.jar
spring-tx-3.2.0.RELEASE.jar
Spring事务管理
spring-tx-3.2.0.RELEASE.jar
Spring整合其他ORM框架
spring-orm-3.2.0.RELEASE.jar
Spring在web中使用
spring-web-3.2.0.RELEASE.jar
Spring整合Junit测试
spring-test-3.2.0.RELEASE.jar
* 配置文件:
* web.xml
<!-- 配置Spring的核心监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
* applicationContext.xml
* log4j.properties
* Hibernate:
* jar包:
* hibernate-distribution-3.6.10.Finalhibernate3.jar
* hibernate-distribution-3.6.10.Finallib equired*.jar
* hibernate-distribution-3.6.10.Finallibjpa*.jar
* slf4j-log4j整合的jar包 :
* 数据库驱动:
* 连接池:(c3p0连接池)
* 配置文件:
* 没有hibernate的核心配置文件的方式整合:
* 映射文件:
3.配置基本配置信息:
* C3P0连接池:
* 引入外部属性文件:
* jdbc.properties
* 配置连接池:
<!-- 配置连接池: -->
<!-- 引入外部属性文件 -->
<context:property-placeholderlocation="classpath:jdbc.properties"/>
<!-- 配置C3P0连接池: -->
<beanid="dataSource"class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass"value="${jdbc.driver}"/>
<property name="jdbcUrl"value="${jdbc.url}"/>
<property name="user"value="${jdbc.user}"/>
<property name="password"value="${jdbc.password}"/>
</bean>
* Hibernate相关信息:
<!-- Hibernate的相关信息 -->
<bean id="sessionFactory"class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- 注入连接池 -->
<property name="dataSource"ref="dataSource"/>
<!-- 配置Hibernate的其他的属性 -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<propkey="hibernate.format_sql">true</prop>
<propkey="hibernate.connection.autocommit">false</prop>
<propkey="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<!-- 配置Hibernate的映射文件 -->
</bean>
* 事务管理:
<!-- 事务管理: -->
<!-- 事务管理器 -->
<beanid="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 开启注解事务 -->
<tx:annotation-driventransaction-manager="transactionManager"/>
1.5.2 引入页面:
1.引入静态页面:
* 在WEB-INF/jsp/
* 将静态页面复制到jsp下.
* 将css/js 放到 WebRoot下.
1.5.3 访问首页:
建包的格式:
* cn.itcast.shop.index
* action
* cn.itcast.shop.user
* action
* service
* dao
* vo
1.编写Action:
* IndexAction
2.改造JSP
* 将css和image的相对路径改变成绝对路径 :
* ./css 替换成${pageContext.request.contextPath}/css
3.配置Action
* 配置applicationContext.xml
<!-- 首页访问的Action -->
<bean id="indexAction"class="cn.itcast.shop.index.action.IndexAction" scope="prototype">
</bean>
* 配置struts.xml
<!-- 配置首页访问的Action -->
<action name="index" class="indexAction">
<resultname="index">/WEB-INF/jsp/index.jsp</result>
</action>
1.5.4 用户模块:注册
跳转到注册页面:
1.点击注册链接(添加到一个Action中,从Action中完成页面转向).
* 修改注册的访问路径:
${ pageContext.request.contextPath }/user_registPage.action
* 编写Action:
* 配置Action:
* 配置applicationContext.xml
<!-- 用户模块的Action -->
<beanid="userAction"class="cn.itcast.shop.user.action.UserAction"scope="prototype">
</bean>
* 配置struts.xml
<!-- 配置用户模块的Action -->
<action name="user_*" class="userAction"method="{1}">
<resultname="registPage">/WEB-INF/jsp/regist.jsp</result>
</action>
* 修改regist.jsp:
* ./css 替换成${pageContext.request.contextPath}/css
用户注册校验:
表创建:
CREATE TABLE `user` (
`uid` int(11) NOT NULLAUTO_INCREMENT,
`username` varchar(255)DEFAULT NULL,
`password` varchar(255)DEFAULT NULL,
`name` varchar(255) DEFAULTNULL,
`email` varchar(255) DEFAULTNULL,
`phone` varchar(255) DEFAULTNULL,
`addr` varchar(255) DEFAULTNULL,
`state` int(11) DEFAULTNULL,
`code` varchar(64) DEFAULTNULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
前台校验:
* JS校验:
* 事件触发:onsubmit
* 校验:
function checkForm(){
// 校验用户名:
// 获得用户名文本框的值:
var username = document.getElementById("username").value;
if(username == null || username == ''){
alert("用户名不能为空!");
return false;
}
// 校验密码:
// 获得密码框的值:
var password =document.getElementById("password").value;
if(password == null || password == ''){
alert("密码不能为空!");
return false;
}
// 校验确认密码:
var repassword =document.getElementById("repassword").value;
if(repassword != password){
alert("两次密码输入不一致!");
return false;
}
}
使用AJAX完成用户名是否存在异步校验:
1.事件触发:
* onblur
2.编写AJAX代码:
* 项Action中提交:传递username参数
3.编写Action
* 接收username:模型驱动接收.
* 编写实体类
* User
* User.hbm.xml
* 配置到Spring中.
4.编写DAO
* 继承HibernateDaoSupport
* 在配置中注入sessionFactory
5.编写Service:
* 注入UserDao
* 事务管理:
用户注册:后台数据校验:
1.在Action所在包下创建一个校验的xml.
* 创建一个与Action类名-validation.xml(针对所有方法进行校验,只需要针对regist方法进行校验)
* UserAction-user_regist-validation.xml
<validators>
<!-- 校验用户名 -->
<fieldname="username">
<field-validator type="requiredstring">
<message>用户名不能为空!</message>
</field-validator>
</field>
<!-- 校验用户名 -->
<fieldname="password">
<field-validator type="requiredstring">
<message>密码不能为空!</message>
</field-validator>
</field>
<!-- 校验邮箱 -->
<fieldname="email">
<field-validator type="email">
<message>邮箱格式不正确!</message>
</field-validator>
</field>
</validators>
2.配置INPUT逻辑视图:
用户注册:
1.将数据保存到数据库 :
* 完善user对象.
2.发送激活邮件:
* 电子邮箱:
* 邮件服务器:
* 邮件协议:
* smtp :发送邮件协议
* pop :接收邮件协议
* 邮箱发送全过程:
* 搭建邮箱服务器:
* 安装邮箱服务器:
* 修改域名:
* 工具---->服务器设置---->shop.com
* 注册账号:
* 账号---->新建账号
* 安装客户端软件:(接收和发送邮件.)
* outlook 和 foxmail
* 安装foxmail:
* 配置:
* 配置发送邮件服务器:
* localhost
* 配置接收邮件服务器:
* localhost
* 编码实现发送邮件:
* 复制mail.jar和activation.jar
* 删除EE5.0中自带发送邮件jar包:
* windows---->preferences--->lib
* 编写代码完成发送邮件:
1.5.5 用户激活:
1.在邮箱客户端中点击激活链接:
* 根据传递激活码进行用户查询.
* 如果用户不为空:
* 修改用户状态 改为1
* 如果用户为空:
* 激活码被篡改了.
1.5.6 用户登录:
跳转到登录页面:
1.修改登录链接:
* 改为action路径:
* 编写Action中方法:
* 转向:
用户登录:
1.接收用户名和密码:(模型驱动会自动接收)
2.调用userService进行查询:
* 用户名和密码及状态.
* 查询到:登录成功:
* 将用户的信息存入到session
* 跳转到首页
* 没查询到:登录失败:
* 跳转回登录页面:
1.5.7 用户退出:
点击退出的链接:
* 提交到Action---销毁session
* 页面跳转(首页)
1.5.8 验证码程序:(注册)
1.编写Action:
* 验证码Action:
* 完成配置:
2.在页面中写<img src=”验证码Action路径”>
3.编写JS,看不清换一张
4.提交到Action,在Action中进行比较.
* 如果一致提交成功
* 如果不一致回到注册页面
1.5.9 首页上的一级分类的查询:
1.创建一级分类的表:
CREATE TABLE `category`(
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`cid`)
) ENGINE=InnoDBAUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
2.建包及相应的类:
* cn.itcast.shop.category
* action
* service
* CategoryService:业务层对象
* dao
* CategoryDao:持久层对象
* vo
* Category:实体对象
* Category.hbm.xml:映射文件
3.对Service和DAO进行配置:
* 在DAO中注入sessionFactory
* 在Service中注入DAO
4.需要在IndexAction中注入一级分类的Service.
* Action-----Service------Dao
* 将一级分类的数据显示到页面:
* 将一级分类的数据存入到session范围.
1.5.10 首页上热门商品显示:
1.建表:
创建二级分类的表:
CREATE TABLE `categorysecond` (
`csid` int(11) NOT NULLAUTO_INCREMENT,
`csname` varchar(255)DEFAULT NULL,
`cid` int(11) DEFAULT NULL,
PRIMARY KEY (`csid`),
KEY `FK936FCAF21DB1FD15`(`cid`),
CONSTRAINT`FK936FCAF21DB1FD15` FOREIGN KEY (`cid`) REFERENCES `category` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
创建商品表:
CREATE TABLE `product` (
`pid` int(11) NOT NULLAUTO_INCREMENT,
`pname` varchar(255) DEFAULTNULL,
`market_price` doubleDEFAULT NULL,
`shop_price` double DEFAULTNULL,
`image` varchar(255) DEFAULTNULL,
`num` int(11) DEFAULT NULL,
`pdesc` varchar(255) DEFAULTNULL,
`is_hot` int(11) DEFAULTNULL,
`pdate` datetime DEFAULTNULL,
`csid` int(11) DEFAULT NULL,
PRIMARY KEY (`pid`),
KEY `FKED8DCCEFB9B74E02`(`csid`),
CONSTRAINT`FKED8DCCEFB9B74E02` FOREIGN KEY (`csid`) REFERENCES `categorysecond` (`csid`)
) ENGINE=InnoDB AUTO_INCREMENT=74 DEFAULT CHARSET=utf8;
2.创建包及类
* cn.itcast.shop.product
* action
* ProductAction
* service
* ProductService
* dao
* ProductDao
* vo
* Product
* Product.hbm.xml
3.将Service和Dao完成配置:
4.Action-----ProductService------>ProductDao
* 查询热门商品:
* is_hot: 0 :不是热门 1:是热门.
* 查询带有个数:
* 分页查询:
* 将查询到数据保存到值栈中.
1.5.11 首页上最新商品显示:
1.Action-----ProductService------>ProductDao
* 查询最新商品:
* 按商品上传日期倒序进行排序 只显示10个.
* 将查询到记录保存到值栈中:
1.5.12 首页上点击商品显示商品详情:
1.点击商品链接:
* 传递商品id.
2.编写Action:
* 编写Action类,继承ActionSupport实现模型驱动接口.
* 编写一个执行的方法.
3.配置Action:
* 在applicationContext.xml中配置Action
* 在struts.xml中配置Action
4.在Action中调用Service完成根据ID进行查询的方法:
* 注入ProductService.
* 完成查询
5.在页面上显示相应数据 :
* 页面转向
* 修改页面
* 显示数据
1.5.13 首页上点击一级分类,查询商品列表:(左侧一级分类和二级分类关联查询)
1.创建二级分类的包及类:
* cn.itcast.shop.categorysecond
* action
* CategoryAction
* service
* CategoryService
* dao
* CategoryDao
* vo
* CategorySecond
* CategorySecond.hbm.xml
2.配置一级分类和二级分类的关联关系:
* Category.xml
<!-- 配置二级分类的集合 -->
<set name="categorySeconds">
<keycolumn="cid"/>
<one-to-manyclass="cn.itcast.shop.categorysecond.vo.CategorySecond"/>
</set>
* CategorySecond.xml
<many-to-one name="category"class="cn.itcast.shop.category.vo.Category"column="cid"></many-to-one>
3.点击一级分类的链接:
* 传递一级分类的id.
4.编写Action:
* 接收cid:
* 编写一个执行的方法:直接返回字符串(页面)
* 显示左侧分类
* 关联查找:(直接session中获得一级分类的数据(需要配置一级分类上二级分类的集合lazy=”false”))
1.5.14 首页上点击一级分类,查询商品列表:(显示商品列表)
1.查询商品,带有分页显示商品.
* 回到商品列表页面:
* 商品集合,当前页数,总页数(总记录数),每页显示记录数.( 将后台这些数据 带到页面上,首选 值栈. )
* 将这些数据封装到一个分页类中.(最后将分页类保存到值栈中就OK).
2.封装一个PageBean.
3.完成查询:
* 传递当前页数:
* 调用Service完成查询.
4.配置二级分类和商品关联关系:
1.5.15 商品分类页面根据二级分类ID查询商品:
1.点击二级分类链接:
* 传递csid
* 传递page=1
2.编写Action :
* 接收csid:
* 接收page
3.调用Service完成查询:
* 封装成PageBean
4.在页面中进行显示:
1.5.16 将商品添加到购物车:
1.封装一个购物车对象:
* Cart:购物车对象:
* CartItem的集合:(选择Map集合,移除购物车时候比较方便.)
* total:总计:
* 功能:
* 将购物项添加到购物车:
* 从购物车中移除购物项:
* 清空购物车:
public class Cart {
// 购物车属性
// 购物项集合:Map的key就是商品pid,value:购物项
private Map<Integer,CartItem> map = new LinkedHashMap<Integer, CartItem>();
// Cart对象中有一个叫cartItems属性.
publicCollection<CartItem> getCartItems(){
return map.values();
}
// 购物总计:
private double total;
public void setTotal(doubletotal) {
this.total = total;
}
// 购物车的功能:
// 1.将购物项添加到购物车
public void addCart(CartItemcartItem) {
// 判断购物车中是否已经存在该购物项:
/*
* * 如果存在:
* * 数量增加
* * 总计 = 总计 + 购物项小计
* * 如果不存在:
* * 向map中添加购物项
* * 总计 = 总计 + 购物项小计
*/
// 获得商品id.
Integer pid = cartItem.getProduct().getPid();
// 判断购物车中是否已经存在该购物项:
if(map.containsKey(pid)){
// 存在
CartItem _cartItem =map.get(pid);// 获得购物车中原来的购物项
_cartItem.setCount(_cartItem.getCount()+cartItem.getCount());
}else{
// 不存在
map.put(pid, cartItem);
}
// 设置总计的值
total += cartItem.getSubtotal();
}
// 2.从购物车移除购物项
public void removeCart(Integerpid) {
// 将购物项移除购物车:
CartItem cartItem = map.remove(pid);
// 总计 = 总计 -移除的购物项小计:
total -= cartItem.getSubtotal();
}
// 3.清空购物车
public void clearCart() {
// 将所有购物项清空
map.clear();
// 将总计设置为0
total = 0;
}
}
* CartItem:购物项对象:
* Product:商品信息.
* count:购买某种商品数量:
* subtotal:购买某种商品的小计:
public class CartItem {
private Product product; // 购物项中商品信息
private int count; // 购买某种商品数量
private double subtotal; // 购买某种商品小计
public Product getProduct() {
return product;
}
public void setProduct(Productproduct) {
this.product = product;
}
public int getCount() {
return count;
}
public void setCount(intcount) {
this.count = count;
}
// 小计自动计算的.
public double getSubtotal() {
return count * product.getShop_price();
}
/*public voidsetSubtotal(double subtotal) {
this.subtotal = subtotal;
}
*/
}
2.跳转到购物车页面:
* 点击加入购物车链接:
* 提交表单
* pid
* 数量
* 完成页面转向:
3.添加到购物车:
* 在Action中:
* 根据pid查询.
* 将商品记录封装到CartItem中.
* 获得Cart的方法.
* 调用Cart中addCart(CartItem cartItem);完成添加到购物车操作.
4.清空购物车:
* 在Action中:
* 获得购物车
* 调用购物车中clearCart();方法完成清空.
* 判断,如果购物车为空不显示.
5.从购物车中移除购物项:
* 点击购物车页面中删除链接
* 传递一个pid.
* Action中:
* 获得购物车
* 调用购物车中removeCart(Integerpid);
6.点击我的购物车:
* 跳转到购物车页面: