SSH实战 · 唯唯乐购项目(上)

前台需求分析
一:用户模块
  1. 注册
    • 前台JS校验
    • 使用AJAX完成对用户名(邮箱)的异步校验
    • 后台Struts2校验
    • 验证码
    • 发送激活邮件
    • 将用户信息存入到数据库
  2. 激活
    • 点击激活邮件中的链接完成激活
      • 根据激活码,查询数据库中是否有该用户;
      • 如果有则激活,否则不激活;
  3. 登录
    • 输入用户名、密码、验证码(前台,后台数据校验)
    • 用户名、密码都正确同时用户状态必须是激活状态
  4. 退出
    • 销毁session。
 
二:一级分类模块
  1. 查询一级分类
    • 将一级分类存入session中(每个页面都一样的数据)
  2. 查询某个一级分类
    • 查询所有一级分类,同时查询到该一级分类下的所有二级分类
    • 查询该分类下所有的商品,带分页显示
三:商品模块
  1. 查询热门商品
    • 查询热门商品:限制查10个
  2. 查询最新商品
    • 查询最新商品:限制查10个
  3. 查询某个分类商品
    • 根据分类的ID进行查询商品
  4. 查询某个二级分类商品
    • 根据二级分类的ID进行查询商品
  5. 查询某个商品信息
    • 根据商品ID进行查询商品
 
四:购物模块
  1. 添加到购物车
    • 将商品添加到购物车
  2. 从购物车中移除商品
    • 将商品从购物车中移除
  3. 清空购物车
    • 将所有的商品信息从购物车中移除
 
五:订单模块
  1. 生成订单
    • 将购物车中的信息存入到数据库(生成订单)
      • 清空购物车
  2. 为订单付款
    • 在线支付功能
    • 修改订单状态
    • 修改订单信息(收货地址,联系方式,收货人等)
  3. 查询我的订单
    • 根据用户ID查询订单
  4. 查询某个订单详情
    • 根据订单ID查询订单
 
后台需求分析
一:用户模块
  1. 添加用户     ·   后台只添加管理员用户
  2. 删除用户
  3. 查询用户
  4. 修改用户
二:一级分类
  1. 添加一级分类
  2. 删除一级分类
    • 级联删除一级分类下的所有二级分类
  3. 修改一级分类
    • 级联修改一级分类下的所有二级分类
  4. 查询一级分类
    • 分页查询
三:二级分类
  1. 添加二级分类
    • 选择所属的一级分类进行添加
  2. 删除二级分类
    • 删除二级分类下的所有商品
  3. 修改二级分类
  4. 查询二级分类
    • 分页查询
 
五:商品模块
  1. 添加商品
    • 选择商品所属二级分类进行添加
    • 上传商品图片
  2. 修改商品
    • 修改商品二级分类
    • 修改商品图片
  3. 删除商品
  4. 查询商品
    • 商品查询(带分页)
 
六:订单模块
  1. 查询订单
    • 查询所有订单(带分页)
      • 异步加载所有订单
 
页面设计
完成前台静态页面的设计。
数据库设计
 
原则:至少一个模块一张表。
用户表:
    • 用户ID
    • 用户名
    • 密码
    • 真实姓名
    • 邮箱
    • 细致
    • 电话
    • 用户状态:0--激活;1--未激活
    • 激活码
sql语句:
CREATE TABLE `user` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `addrress` varchar(255) DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  `code` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
 
 一级分类表:
    • 一级分类ID
    • 一级分类名称
CREATE TABLE `category` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
 
二级分类表:
    • 二级分类ID
    • 二级分类名称
    • 一级分类ID(外键指向一级分类主键ID)
CREATE TABLE `categorysecond` (
  `csid` int(11) NOT NULL AUTO_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=71 DEFAULT CHARSET=utf8;
 
商品表:
    • 商品ID
    • 商品名称
    • 商品商城价格
    • 商品描述
    • 商品市场价格
    • 商品描述
    • 商品图片(路径)
    • 二级分类ID(外键指向二级分类主键ID )   
CREATE TABLE `product` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) DEFAULT NULL,
  `market_price` double DEFAULT NULL,
  `shop_price` double DEFAULT NULL,
  `image` varchar(255) DEFAULT NULL,
  `pdesc` varchar(255) DEFAULT NULL,
  `is_hot` int(11) DEFAULT NULL,
  `pdate` datetime DEFAULT NULL,
  `csid` int(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `FKED8DCCEFB9B74E02` (`csid`),
  CONSTRAINT `FKED8DCCEFB9B74E02` FOREIGN KEY (`csid`) REFERENCES `categorysecond` (`csid`)
) ENGINE=InnoDB AUTO_INCREMENT=86 DEFAULT CHARSET=utf8;
 
订单表:
    • 订单ID
    • 订单时间
    • 订单金额
    • 订单状态
    • 订单地址
    • 订单电话
    • 订单收货人
    • 用户ID(外键指向用户表的主键ID)
CREATE TABLE `orders` (
  `oid` int(11) NOT NULL AUTO_INCREMENT,
  `total` double DEFAULT NULL,
  `ordertime` datetime DEFAULT NULL,
  `state` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `addr` varchar(50) DEFAULT NULL,
  `uid` int(11) DEFAULT NULL,
  PRIMARY KEY (`oid`),
  KEY `FKC3DF62E5AA3D9C7` (`uid`),
  CONSTRAINT `FKC3DF62E5AA3D9C7` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=9004 DEFAULT CHARSET=utf8;
 
 
订单项表:(需要参与业务逻辑中)
    • 主键ID
    • 商品ID(指向)
    • 订单ID()
    • 数量
    • 小计
CREATE TABLE `orderitem` (
  `itemid` int(11) NOT NULL AUTO_INCREMENT,
  `count` int(11) DEFAULT NULL,
  `subtotal` double DEFAULT NULL,
  `pid` int(11) DEFAULT NULL,
  `oid` int(11) DEFAULT NULL,
  PRIMARY KEY (`itemid`),
  KEY `FKE8B2AB6166C01961` (`oid`),
  KEY `FKE8B2AB6171DB7AE4` (`pid`),
  KEY `FKE8B2AB6140ACF87A` (`oid`),
  CONSTRAINT `FKE8B2AB6140ACF87A` FOREIGN KEY (`oid`) REFERENCES `orders` (`oid`),
  CONSTRAINT `FKE8B2AB6171DB7AE4` FOREIGN KEY (`pid`) REFERENCES `product` (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;
 
 
后台用户表:
    • 用户名
    • 密码
 
表关系分析图
其中 : 订单项表是商品表和订单表之间多对多关系产生的中间表。
 
 编码实现
一:SSH整合
  1. 参考之前得SSH项目实战  ·  项目环境搭建——http://www.cnblogs.com/panweiwei/p/6212609.html。
 

  2. 引入前端页面 ---- 页面都放到WebRoot/WEB-INF下。

    • 引入静态页面
      • 将HTML静态页面都复制到WebRoot/WEB-INF/jsp目录下.
      • 将JS、CSS文件分别复制到WebRoot/js、WebRoot/css目录下.
 

  3. 访问首页

    • 创建包的格式:
* cn.itcast.shop.index
* action
* cn.itcast.shop.user
* action
* service
* dao
* vo
    • 编写Action
      • IndexAction
    • 改造jsp和文件路径
      • 将html静态页面改为jsp页面文件
      • 将jsp中的css、js、图片路径改为绝对路径(${pageContext.request.contextPath} )
    • 配置Action
      • 配置applicationContext.xml
 <!-- 首页访问的Action 注意:千万不要忘记scope-->
 <bean id="indexAction" class="cn.itcast.shop.index.action.IndexAction" scope="prototype"></bean>
      • 配置struts.xml
 <!-- 配置首页访问的Action -->
 <action name="index" class="indexAction">
     <result name="index">/WEB-INF/jsp/index.jsp</result>
 </action>
 
用户模块:注册
一:改装页面 
  1. 将页面中能共用的菜单、头部区域提出来(新建一个head.jsp)
  2. 在原来网页的头部处将head.jsp包入就好:
          <@% include file="head.jsp" %>
 
二:跳转到注册界面
  1. 点击注册链接进行跳转(添加到一个Action中,从Action中完成页面转向)
    • 修改注册的访问路径
                         ${pageContext.request.contextPath}/user_registePage.action
    • 编写Action
    • 配置applicationContext.xml
<!-- 用户模块的Action -->
<bean id="userAction" class="cn.itcast.shop.user.action.UserAction" scope="prototype"></bean>
    • 配置struts.xml
     <!-- 配置用户模块的Action -->
     <action name="user_*" class="userAction" method="{1}">
         <result name="registPage">/WEB-INF/jsp/regist.jsp</result>
     </action>
    • 修改register.jsp页面:
      • 替换css、图片的路径
                     ./css 替换成 ${pageContext.request.contextPath}/css
                    ./images 替换成 ${pageContext.request.contextPath}/images
      • 包含head.jsp。当然了,原页面中相应的内容删掉
<@% include file="head.jsp" %>
  1. 用户注册校验
       2.1 前台校验:页面中凡是涉及到提交表单的都要进行验证。
    • 统一字段名的name、id(与数据库表中字段、实体类中的字段对应);
    • 加 JS。
    • AJAX异步校验:验证数据库中是否已存在输入的用户名
      • 事件触发:onblur
      • 编写AJAX代码:向action中提交:传递username参数
      • 编写antion:

*  接收username:模型驱动接收                          

*  编写实体类:User;                          

*  映射文件:User.hbm.xml;                           

*  将实体类与映射文件配置到spring中。

      • 编写DAO

                         *  继承HibernateDaoSupport;

            • 在配置中注入sessionFactory  
      • 编写Service

                         *  注入UserDao;                            

          *  配置事务管理;   

       2.2 后台数据校验
    • 在Action所在包下创建一个校验的xml
      • 创建一个与Action类名-validation.xml(只针对register方法进行校验)
      • UserAction-user_regist-validation.xml
  <!DOCTYPE validators PUBLIC
          "-//Apache Struts//XWork Validator 1.0.3//EN"
          "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> 
  <validators>
 <!-- 校验用户名 -->
 <field name="username">
     <field-validator type="requiredstring">
         <message>用户名不能为空!</message>
     </field-validator>
 </field>
 
 <!-- 校验用户名 -->
 <field name="password">
     <field-validator type="requiredstring">
         <message>密码不能为空!</message>
     </field-validator>
 </field>
 
 <!-- 校验邮箱 -->
 <field name="email">
     <field-validator type="email">
         <message>邮箱格式不正确!</message>
     </field-validator>
 </field>
   </validators>
    • 在struts.xml中配置INPUT逻辑视图
         <!-- 配置用户模块的Action -->
          <action name="user_*" class="userAction" method="{1}">
              <result name="registPage">/WEB-INF/jsp/register.jsp</result>
              <result name="input">/WEB-INF/jsp/register.jsp</result>
          </action>
    • 在register.jsp页面先引入struts标签
               <%@ taglib uri="/struts-tags" prefix="s"%>
    • 在相应的位置回显错误提示信息。如密码验证提示如下:
  <span><s:fielderror fieldName="password"/></span>
 
  1. 用户注册
    • 将数据保存到数据库
      • 完善user对象
                     *  用户状态默认为0(未激活状态);
                     *  激活码采用工具类(UUID)生成(32位激活码);
    • 发送激活邮件
      • 电子邮箱:邮件服务器上的一块空间;
      • 邮件服务器:类比于web服务器(tomcat),有相应的服务器软件;
      • 邮件协议:大公司发送和接收服务器分开,也可以都用一个服务器。
                           SMTP:简单的邮件发送协议;
                           POP3:接收邮件的一个协议;
      • 邮件发送的全过程:理论上需要联网,但是通过搭建在本地的服务器,可以在本地进行邮件的发送。
      • 搭建邮箱服务器:
        • 安装邮箱服务器(易邮邮箱服务器,就按默认的安装在C盘)
        • 修改域名:工具-->服务器设置-->单域名改为:shop.com
        • 注册几个内部账号:账号-->新建账号。密码设为55555
        • 注册一个商城官方账号:service    密码:55555
      • 安装邮件客户端软件(可以接发邮件):避免了网页版session的过期离线问题。
        • 流行的有软件有:outlook(微软收费)、foxmail(免费,选用foxmail)
        • 配置
                              * 配置发送邮件服务器:localhost
                              * 配置接收邮件服务器:localhost
      • 编码实现邮件发送
 
  1. 用户激活
    • 在邮箱客户端中点击激活链接:
      • 根据链接中传递的激活码进行查询
                         * 如果用户不为空:修改用户状态:0  -->  1,向前台传递激活成功消息。
                         * 如果用户为空:激活码失效或被篡改,向前台传递激活失败消息。
 
  1. 用户登录
    • 登录页面跳转链接
      • 将html编写为login.jsp,并更换引用路径以及菜单头文件
      • 修改页面上的登录链接为${pageContext.request.contextPath}/user_loginPage.action
      • 编写Action中的方法
      • struts.xml中配置页面转向
    • 登录功能实现
      • 添加login.jsp中的表单action
      • 接收用户输入的用户名、密码——模型驱动会自动接收;
      • 调用userService,进行查询——参数:用户名、密码、用户状态。
      • 登录成功:跳转到首页,并将用户信息显示在首页。
      • 登录失败:跳转回登录页面,并将错误信息显示在登录页面。
  2. 用户退出
    • 给链接加action的路径,点击退出链接
      • 销毁session
//销毁session
ServletActionContext.getRequest().getSession().invalidate();
      • 页面跳转
  1. 验证码
    • com.weiwei.shopping.user下编写单独的验证码Action类;
    • 在spring、struts配置文件中完成配置;
             applicationContext.xml 中:
      <!-- 配置验证码Action -->
      <bean id="checkImgAction" class="com.weiwei.shopping.user.action.CheckImgAction" scope="prototype"></bean>
             struts.xml 中:
          <!-- 验证码Action -->
          <action name="checkImg" class="checkImgAction"></action>
    • 页面中需要的位置显示验证码
          <img id="rightcode" class="captchaImage" src="${pageContext.request.contextPath}/checkImg.action" title="点击更换验证码" onclick="ChangeCodeImg()" />
    • 编写JS,点击刷新验证码
/*点击更换验证码图片*/
function ChangeCodeImg(){
     /*取到验证码图片*/
     var codeImg = document.getElementById("rightcode");
     /*由于浏览器的缓存,所以需要加上时间戳*/
     codeImg.src = "${pageContext.request.contextPath}/checkImg.action?" + new Date().getTime();
}
    • 提交到action,在action中进行比较,表单输入的与session中的验证码不相等则相应请求不提交。
/*判断验证码,验证码正确则提交,否则不提交*/
//从session中获取正确的验证码
String rightcode = (String) ServletActionContext.getRequest().getSession().getAttribute("checkcode");
//与表单提交的验证码比较
if(!formcode.equalsIgnoreCase(rightcode)){
      //不相等
      this.addActionError("验证码输入错误!");
      return "loginPage";
}
User existUser = userService.checkLogin(user);
if(existUser == null){
      //登录失败
      this.addActionError("查无此人,登录失败!");
      return "login";
} else{
      //登录成功
      //将用户的信息存到session中,在进行页面的跳转
      ServletActionContext.getRequest().getSession().setAttribute("existUser", existUser);
      this.addActionMessage("登录成功!");
      return "loginPage";
}
 
原文地址:https://www.cnblogs.com/panweiwei/p/6245697.html