- 浏览: 21499566 次
- 性别:
博客专栏
-
跟我学spring3
浏览量:2417797
-
Spring杂谈
浏览量:3008104
-
跟开涛学SpringMVC...
浏览量:5638966
-
Servlet3.1规范翻...
浏览量:259811
-
springmvc杂谈
浏览量:1597057
-
hibernate杂谈
浏览量:250123
-
跟我学Shiro
浏览量:5858171
-
跟我学Nginx+Lua开...
浏览量:701796
-
亿级流量网站架构核心技术
浏览量:784905
文章分类
- 全部博客 (329)
- 跟我学Nginx+Lua开发 (13)
- 跟我学spring (54)
- 跟开涛学SpringMVC (34)
- spring4 (16)
- spring杂谈 (50)
- springmvc杂谈 (22)
- 跟我学Shiro (26)
- shiro杂谈 (3)
- hibernate杂谈 (10)
- java开发常见问题分析 (36)
- 加速Java应用开发 (5)
- Servlet 3.1规范[翻译] (21)
- servlet3.x (2)
- websocket协议[翻译] (14)
- websocket规范[翻译] (1)
- java web (6)
- db (1)
- js & jquery & bootstrap (4)
- 非技术 (4)
- reminder[转载] (23)
- 跟叶子学把妹 (8)
- nginx (2)
- 架构 (19)
- flume架构与源码分析 (4)
最新评论
-
xxx不是你可以惹得:
认真看错误代码,有时候重启电脑就行了 醉了 我把数据库配置写死 ...
第十六章 综合实例——《跟我学Shiro》 -
dagger9527:
holyselina 写道您前面说到能获取调用是的参数数组,我 ...
【第六章】 AOP 之 6.6 通知参数 ——跟我学spring3 -
xxx不是你可以惹得:
Access denied for user 'root'@' ...
第十六章 综合实例——《跟我学Shiro》 -
dagger9527:
只有@AspectJ支持命名切入点,而Schema风格不支持命 ...
【第六章】 AOP 之 6.5 AspectJ切入点语法详解 ——跟我学spring3 -
dagger9527:
支持虽然会迟到,但永远不会缺席!
【第四章】 资源 之 4.3 访问Resource ——跟我学spring3
11.3 实现积分商城层
11.3.1 概述
积分商城是基于通用层之上进行开发,这样我们能减少很多重复的劳动,加快项目开发进度。
11.3.2 实现数据模型层
1、商品表,定义了如商品名称、简介、原需积分、现需积分等,其中是否发布表示只有发布(true)了的商品才会在前台删除,是否已删除表示不会物理删除,商品不应该物理删除,而是逻辑删除,版本属性用于防止并发更新。
package cn.javass.point.model; /** 商品表 */ @Entity @Table(name = "tb_goods") public class GoodsModel implements java.io.Serializable { /** 主键 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", length = 10) private int id; /** 商品名称 */ @Column(name = "name", nullable = false, length = 100) private String name; /** 商品简介 */ @Column(name = "description", nullable = false, length = 100) private String description; /** 原需积分 */ @Column(name = "original_point", nullable = false, length = 10) private int originalPoint; /** 现需积分 */ @Column(name = "now_point", nullable = false, length = 10) private int nowPoint; /** 是否发布,只有发布的在前台显示 */ @Column(name = "published", nullable = false) private boolean published; /** 是否删除,商品不会被物理删除的 */ @Column(name = "is_delete", nullable = false) private boolean deleted; /** 版本 */ @Version @Column(name = "version", nullable = false, length = 10) private int version; //省略getter和setter、hashCode及equals,实现请参考源代码 }
2、商品兑换码表,定义了兑换码、兑换码所属商品(兑换码和商品直接是多对一关系)、购买人、购买时间、是否已经购买(防止一个兑换码多个用户兑换)、版本。
package cn.javass.point.model; import java.util.Date; //省略部分import /** 商品兑换码表 */ @Entity @Table(name = "tb_goods_code") public class GoodsCodeModel implements java.io.Serializable { /** 主键 */ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", length = 10) private int id; /** 所属商品 */ @ManyToOne private GoodsModel goods; /** 兑换码*/ @Column(name = "code", nullable = false, length = 100) private String code; /** 兑换人,实际环境中应该和用户表进行对应*/ @Column(name = "username", nullable = true, length = 100) private String username; /** 兑换时间*/ @Column(name = "exchange_time") private Date exchangeTime; /** 是否已经兑换*/ @Column(name = "exchanged") private boolean exchanged = false; /** 版本 */ @Version @Column(name = "version", nullable = false, length = 10) private int version; //省略getter和setter、hashCode及equals,实现请参考源代码 }
3、商品表及商品兑换码表之间关系,即一个商品有多个兑换码,如图11-10所示:
图11-10商品表及商品兑换码表之间关系
4、 创建数据库及表结构的SQL语句文件(sql/ pointShop_schema.sql):
CREATE DATABASE IF NOT EXISTS `point_shop` DEFAULT CHARACTER SET 'utf8'; USE `point_shop`; DROP TABLE IF EXISTS `tb_goods_code`; DROP TABLE IF EXISTS `tb_goods`; -- ---------------------------- -- Table structure for 商品表 -- ---------------------------- CREATE TABLE `tb_goods` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '商品id', `name` varchar(100) NOT NULL COMMENT '商品名称', `description` varchar(100) NOT NULL COMMENT '商品简介', `original_point` int(10) unsigned NOT NULL COMMENT '原需积分', `now_point` int(10) unsigned NOT NULL COMMENT '现需积分', `published` bool NOT NULL COMMENT '是否发布', `is_delete` bool NOT NULL DEFAULT false COMMENT '是否删除', `version` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '版本', PRIMARY KEY (`id`), INDEX(`name`), INDEX(`published`) )ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品表'; -- ---------------------------- -- Table structure for 商品兑换码表 -- ---------------------------- CREATE TABLE `tb_goods_code` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id', `username` varchar(100) COMMENT '兑换用户', `goods_id` int(10) unsigned NOT NULL COMMENT '所属商品id', `code` varchar(100) NOT NULL COMMENT '积分', `exchange_time` datetime COMMENT '购买时间', `exchanged` bool DEFAULT false COMMENT '是否已经兑换', `version` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '版本', PRIMARY KEY (`id`), FOREIGN KEY (`goods_id`) REFERENCES `tb_goods` (`id`) ON DELETE CASCADE )ENGINE=InnoDB AUTO_INCREMENT=1000000 DEFAULT CHARSET=utf8 COMMENT='商品兑换码表';
Mysql数据库引擎应该使用InnoDB,如果使用MyISM将不支持事务。
11.3.3 实现数据访问层
数据访问层只涉及与底层数据库或文件系统等打交道,不会涉及业务逻辑,一定注意层次边界,不要在数据访问层实现业务逻辑。
商品模块的应该实现如下功能:
- 继承通用数据访问层的CRUD功能;
- 分页查询所有已发布的商品
- 统计所有已发布的商品;
商品兑换码模块的应该实现如下功能:
- 继承通用数据访问层的CRUD功能;
- 根据商品ID分页查询该商品的兑换码
- 根据商品ID统计该商品的兑换码记录数;
- 根据商品ID获取一个还没有兑换的商品兑换码
1、商品及商品兑换码DAO接口定义:
商品及商品兑换码DAO接口定义直接继承IBaseDao,无需在这些接口中定义重复的CRUD方法了,并通过泛型指定数据模型类及主键类型。
package cn.javass.point.dao; //省略import /** 商品模型对象的DAO接口 */ public interface IGoodsDao extends IBaseDao<GoodsModel, Integer> { /** 分页查询所有已发布的商品*/ List<GoodsModel> listAllPublished(int pn); /** 统计所有已发布的商品记录数*/ int countAllPublished(); }
package cn.javass.point.dao; //省略import /** 商品兑换码模型对象的DAO接口 */ public interface IGoodsCodeDao extends IBaseDao<GoodsCodeModel, Integer> { /** 根据商品ID统计该商品的兑换码记录数*/ public int countAllByGoods(int goodsId); /** 根据商品ID查询该商品的兑换码列表*/ public List<GoodsCodeModel> listAllByGoods(int pn, int goodsId); /** 根据商品ID获取一个还没有兑换的商品兑换码 */ public GoodsCodeModel getOneNotExchanged(int goodsId); }
2、 商品及商品兑换码DAO接口实现定义:
DAO接口实现定义都非常简单,对于CRUD实现直接从BaseHibernateDao继承即可,无需再定义重复的CRUD实现了,并通过泛型指定数据模型类及主键类型。
package cn.javass.point.dao.hibernate; //省略import public class GoodsHibernateDao extends BaseHibernateDao<GoodsModel, Integer> implements IGoodsDao { @Override //覆盖掉父类的delete方法,不进行物理删除 public void delete(Integer id) { GoodsModel goods = get(id); goods.setDeleted(true); update(goods); } @Override //覆盖掉父类的getCountAllHql方法,查询不包括逻辑删除的记录 protected String getCountAllHql() { return super.getCountAllHql() + " where deleted=false"; } @Override //覆盖掉父类的getListAllHql方法,查询不包括逻辑删除的记录 protected String getListAllHql() { return super.getListAllHql() + " where deleted=false"; } @Override //统计没有被逻辑删除的且发布的商品数量 public int countAllPublished() { String hql = getCountAllHql() + " and published=true"; Number result = unique(hql); return result.intValue(); } @Override //查询没有被逻辑删除的且发布的商品 public List<GoodsModel> listAllPublished(int pn) { String hql = getListAllHql() + " and published=true"; return list(hql, pn, Constants.DEFAULT_PAGE_SIZE); } }
package cn.javass.point.dao.hibernate; //省略import public class GoodsCodeHibernateDao extends BaseHibernateDao<GoodsCodeModel, Integer> implements IGoodsCodeDao { @Override //根据商品ID查询该商品的兑换码 public List<GoodsCodeModel> listAllByGoods(int pn, int goodsId) { final String hql = getListAllHql() + " where goods.id = ?"; return list(hql, pn, Constants.DEFAULT_PAGE_SIZE , goodsId); } @Override //根据商品ID统计该商品的兑换码数量 public int countAllByGoods(int goodsId) { final String hql = getCountAllHql() + " where goods.id = ?"; Number result = unique(hql, goodsId); return result.intValue(); }
3、Spring DAO层配置文件(resources/cn/javass/point/dao/ applicationContext-hibernate.xml):
DAO配置文件中定义Hibernate的SessionFactory、事务管理器和DAO实现。
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/><!-- 1、指定数据源 --> <property name="annotatedClasses"> <!-- 2、指定注解类 --> <list> <value>cn.javass.point.model.GoodsModel</value> <value>cn.javass.point.model.GoodsCodeModel</value> </list> </property> <property name="hibernateProperties"><!-- 3、指定Hibernate属性 --> <props> <prop key="hibernate.dialect">${hibernate.dialect}</prop> <prop key="hibernate.show_sql">${hibernate.show_sql}</prop> <prop key="hibernate.format_sql">${hibernate.format_sql}</prop> <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> </props> </property> </bean> <bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean>
<bean id="abstractDao" abstract="true" init-method="init"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="goodsDao" class="cn.javass.point.dao.hibernate.GoodsHibernateDao" parent="abstractDao"/> <bean id="goodsCodeDao" class="cn.javass.point.dao.hibernate.GoodsCodeHibernateDao" parent="abstractDao"/>
4、修改替换配置元数据的资源文件(resources/resources.properties),添加Hibernate属性相关:
#Hibernate属性 hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect hibernate.hbm2ddl.auto=none hibernate.show_sql=false hibernate.format_sql=true
11.3.4 实现业务逻辑层
业务逻辑层实现业务逻辑,即系统中最复杂、最核心的功能,不应该在业务逻辑层出现如数据库访问等底层代码,对于这些操作应委托给数据访问层实现,从而保证业务逻辑层的独立性和可复用性,并应该在业务逻辑层组装分页对象。
商品模块应该实现如下功能:
- CURD操作,直接委托给通用业务逻辑层;
- 根据页码查询所有已发布的商品的分页对象,即查询指定页的记录,这是和数据访问层不同的;
商品兑换码模块应该实现如下功能:
- CURD操作,直接委托给通用业务逻辑层;
- 根据页码和商品Id查询查询所有商品兑换码分页对象,即查询指定页的记录;
- 新增指定商品的兑换码,用于对指定商品添加兑换码;
- 购买指定商品兑换码操作,用户根据商品购买该商品的兑换码,如果指定商品的兑换码没有了将抛出没有兑换码异常NotCodeException;
1、商品及商品兑换码Service接口定义:
接口定义时,对于CRUD直接继承IBaseService即可,无需再在这些接口中定义重复的CRUD方法了,并通过泛型指定数据模型类及数据模型的主键。
package cn.javass.point.service; //省略import public interface IGoodsService extends IBaseService<GoodsModel, Integer> { /**根据页码查询所有已发布的商品的分页对象*/ Page<GoodsModel> listAllPublished(int pn); }
package cn.javass.point.service; //省略import public interface IGoodsCodeService extends IBaseService<GoodsCodeModel, Integer> { /** 根据页码和商品Id查询查询所有商品兑换码分页对象*/ public Page<GoodsCodeModel> listAllByGoods(int pn, int goodsId); /** 新增指定商品的兑换码*/ public void save(int goodsId, String[] codes); /** 购买指定商品兑换码 */ GoodsCodeModel buy(String username, int goodsId) throws NotCodeException ; }
2、NotCodeException异常定义,表示指定商品的兑换码已经全部被兑换了,没有剩余的兑换码了:
package cn.javass.point.exception; /** 购买失败异常,表示没有足够的兑换码 */ public class NotCodeException extends RuntimeException { }
NotCodeException异常类实现RuntimeException,当需要更多信息时可以在异常中定义,异常比硬编码错误代码(如-1表示没有足够的兑换码)更好理解。
3、商品及商品兑换码Service接口实现定义:
接口实现时,CRUD实现直接从BaseServcice继承即可,无需再在这些专有实现中定义重复的CRUD实现了,并通过泛型指定数据模型类及数据模型的主键。
package cn.javass.point.service.impl; //省略import public class GoodsServiceImpl extends BaseServiceImpl<GoodsModel, Integer> implements IGoodsService { @Override public Page<GoodsModel> listAllPublished(int pn) { int count = getGoodsDao().countAllPublished(); List<GoodsModel> items = getGoodsDao().listAllPublished(pn); return PageUtil.getPage(count, pn, items, Constants.DEFAULT_PAGE_SIZE); } IGoodsDao getGoodsDao() {//将通用DAO转型 return (IGoodsDao) getDao(); } }
package cn.javass.point.service.impl; //省略import public class GoodsCodeServiceImpl extends BaseServiceImpl<GoodsCodeModel, Integer> implements IGoodsCodeService { private IGoodsService goodsService; public void setGoodsService(IGoodsService goodsService) {//注入IGoodsService this.goodsService = goodsService; } private IGoodsCodeDao getGoodsCodeDao() {//将注入的通用DAO转型 return (IGoodsCodeDao) getDao(); } @Override public Page<GoodsCodeModel> listAllByGoods(int pn, int goodsId) { Integer count = getGoodsCodeDao().countAllByGoods(goodsId); List<GoodsCodeModel> items = getGoodsCodeDao().listAllByGoods(pn, goodsId); return PageUtil.getPage(count, pn, items, Constants.DEFAULT_PAGE_SIZE); } @Override public void save(int goodsId, String[] codes) { GoodsModel goods = goodsService.get(goodsId); for(String code : codes) { if(StringUtils.hasText(code)) { GoodsCodeModel goodsCode = new GoodsCodeModel(); goodsCode.setCode(code); goodsCode.setGoods(goods); save(goodsCode); } } } @Override public GoodsCodeModel buy(String username, int goodsId) throws NotCodeException { //1、实际实现时要验证用户积分是否充足 //2、其他逻辑判断 //3、实际实现时要记录交易记录开始 GoodsCodeModel goodsCode = getGoodsCodeDao().getOneNotExchanged(goodsId); if(goodsCode == null) { //3、实际实现时要记录交易记录失败 throw new NotCodeException(); //目前只抛出一个异常,还可能比如并发购买情况 } goodsCode.setExchanged(true); goodsCode.setExchangeTime(new Date()); goodsCode.setUsername(username); save(goodsCode); //3、实际实现时要记录交易记录成功 return goodsCode; } }
save方法和buy方法实现并不是最优的,save方法中如果兑换码有上千个怎么办?这时就需要批处理了,通过批处理比如20条一提交数据库来提高性能。buy方法就要考虑多个用户同时购买同一个兑换码如何处理?
交易历史一定要记录,从交易开始到交易结束(不管成功与否)一定要记录用于当客户投诉时查询相应数据。
4、Spring Service层配置文件(resources/cn/javass/point/service/ applicationContext-service.xml):
Service层配置文件定义了事务和Service实现。
<tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="create*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="del*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="buy*" propagation="REQUIRED" /> <tx:method name="count*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="list*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice>
<aop:config> <aop:pointcut id="txPointcut" expression="execution(* cn.javass.point.service.*.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /> </aop:config> <bean id="goodsService" class="cn.javass.point.service.impl.GoodsServiceImpl"> <property name="dao" ref="goodsDao"/> </bean> <bean id="goodsCodeService" class="cn.javass.point.service.impl.GoodsCodeServiceImpl"> <property name="dao" ref="goodsCodeDao"/> <property name="goodsService" ref="goodsService"/> </bean>
11.3.5 实现表现层
表现层显示页面展示和交互,应该支持多种视图技术(如JSP、Velocity),表现层实现不应该实现诸如业务逻辑层功能,只负责调用业务逻辑层查找数据模型并委托给相应的视图进行展示数据模型。
积分商城分为前台和后台,前台负责与客户进行交互,如购买商品;后台是负责商品及商品兑换码维护的,只应该管理员有权限操作。
后台模块:
- 商品管理模块:负责商品的维护,包括列表、新增、修改、删除、查询所有商品兑换码功能;
- 商品兑换码管理模块:包括列表、新增、删除所有兑换码操作;
前台模块:只有已发布商品展示,用户购买指定商品时,如果购买成功则给用户发送兑换码,购买失败给用户错误提示。
表现层Action实现时一般使用如下规约编程:
- Action方法定义:使用如list方法表示展示列表,doAdd方法表示去新增页面,add方法表示提交新增页面的结果并委托给Service层进行处理;
- 结果定义:如使用“list”结果表示到展示列表页面,“add”结果去新增页面等等;
- 参数设置:一般使用如“model”表示数据模型,使用“page”表示分页对象。
1、集成Struts2和Spring配置:
1.1、Spring Action配置文件:即Action将从Spring容器中获取,前台和后台配置文件应该分开以便好管理;
- 后台Action配置文件resources/cn/javass/web/pointShop-admin-servlet.xml;
- 前台Action配置文件resources/cn/javass/web/pointShop-front-servlet.xml;
1.2、Struts配置文件定义(resources/struts.xml):
为了提高开发效率和采用规约编程,我们将使用模式匹配通配符来定义action。对于管理后台和前台应该分开,URL模式将类似于/{module}/{action}/{method}.action:
- module即模块名如admin,action即action前缀名,如后台的“GoodsAction”可以使用“goods”,method即Action中的方法名如“list”。
- 可以在Struts配置文件中使用{1}访问第一个通配符匹配的结果,以此类推;
- Reuslt也采用规约编程,即只有符合规律的放置jsp文件才会匹配到,如Result为“/WEB-INF/jsp/admin/{1}/list.jsp”,而URL为/goods/list.action 结果将为“/WEB-INF/jsp/admin/goods/list.jsp”。
<package name="admin" extends="custom-default" namespace="/admin"> <action name="*/*" class="/admin/{1}Action" method="{2}"> <result name="redirect" type="redirect">/admin/{1}/list.action</result> <result name="list">/WEB-INF/jsp/admin/{1}/list.jsp</result> <result name="add">/WEB-INF/jsp/admin/{1}/add.jsp</result> </action> </package>
在此我们继承了“custom-default”包来支持action名字中允许“/”。
如“/admin/goods/list.action”将调用cn.javass.point.web.admin.action.GoodsAction的list方法。
<package name="front" extends="custom-default"> <action name="*/*" class="/front/{1}Action" method="{2}"> <result name="redirect" type="redirect">/{1}/list.action</result> <result name="list">/WEB-INF/jsp/front/{1}/list.jsp</result> <result name="add">/WEB-INF/jsp/front/{1}/add.jsp</result> <result name="buyResult">/WEB-INF/jsp/front/{1}/buyResult.jsp</result> </action> </package>
如“/goods/list.action”将调用cn.javass.point.web.front.action.GoodsAction的list方法。
1.3、web.xml配置:将Spring配置文件加上;
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:applicationContext-resources.xml, classpath:cn/javass/point/dao/applicationContext-hibernate.xml, classpath:cn/javass/point/service/applicationContext-service.xml, classpath:cn/javass/point/web/pointShop-admin-servlet.xml, classpath:cn/javass/point/web/pointShop-front-servlet.xml </param-value> </context-param>
2、后台商品管理模块
商品管理模块实现商品的CRUD,本示例只演示新增,删除和更新由于篇幅问题留作练习。
2.1、Action实现
package cn.javass.point.web.admin.action; //省略import public class GoodsAction extends BaseAction { public String list() {//列表、展示所有商品(包括未发布的) getValueStack().set(PAGE, goodsService.listAll(getPn())); return LIST; } public String doAdd() {//到新增页面 goods = new GoodsModel(); getValueStack().set(MODEL, goods); return ADD; } public String add() {//保存新增模型对象 goodsService.save(goods); return REDIRECT; } //字段驱动数据填充 private int id = -1; //前台提交的商品ID private GoodsModel goods; //前台提交的商品模型对象 //省略字段驱动数据的getter和setter //依赖注入Service private IGoodsService goodsService; //省略依赖注入的getter和setter }
2.2、Spring配置文件定义(resources/cn/javass/web/pointShop-admin-servlet.xml):
<bean name="/admin/goodsAction" class="cn.javass.point.web.admin.action.GoodsAction" scope="prototype"> <property name="goodsService" ref="goodsService"/> </bean>
2.3、JSP实现商品列表页面(WEB-INF/jsp/admin/goods/list.jsp)
查询所有商品,通过迭代“page.items”(Page对象的items属性中存放着分页列表数据)来显示商品列表,在最后应该有分页标签(请参考源代码,示例无),如类似于“<my:page url="${ctx}/admin/goods/list.action"/>”来定义分页元素。
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="商品管理-商品列表"/> </jsp:include> <a href="${ctx}/admin/goods/doAdd.action">新增</a><br/> <table border="1"> <tr> <th>ID</th> <th>商品名称</th> <th>商品描述</th> <th>原需积分</th> <th>现需积分</th> <th>是否已发布</th> <th></th> <th></th> <th></th> </tr> <s:iterator value="page.items"> <tr> <td><a href="${ctx}/admin/goods/toUpdate.action?id=<s:property value='id'/>"><s:property value="id"/></a></td> <td><s:property value="name"/></td> <td><s:property value="description"/></td> <td><s:property value="originalPoint"/></td> <td><s:property value="nowPoint"/></td> <td><s:property value="published"/></td> <td>更新</td> <td>删除</td> <td><a href="${ctx}/admin/goodsCode/list.action?goodsId=<s:property value='id'/>">查看Code码</a></td> </tr> </s:iterator> </table> <jsp:include page="../../common/inc/footer.jsp"/>
右击“pointShop”项目选择【Run As】>【Run On Server】启动Tomcat服务器,在浏览器中输入“http://localhost:8080/pointShop/admin/goods/list.action”将显示图11-11界面。
图11-11 后台商品列表页面
2.4、JSP实现商品新增页面(WEB-INF/jsp/admin/goods/add.jsp)
表单提交到/admin/goods/add.action即cn.javass.point.web.admin.action.GoodsAction的add方法。并将参数绑定到goods属性上,在此我们没有进行数据验证,在实际项目中页面中和Action中都要进行数据验证。
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="商品管理-新增"/> </jsp:include> <s:fielderror cssStyle="color:red"/> <s:form action="/admin/goods/add.action" method="POST" acceptcharset="UTF-8" > <s:token/> <table border="1"> <s:hidden name="goods.id" value="%{model.id}"/> <s:hidden name="goods.version" value="%{model.version}"/> <tr> <s:textfield label="商品名称" name="goods.name" value="%{model.name}" required="true"/> </tr> <tr> <s:textarea label="商品简介" name="goods.description" value="%{model.description}" required="true" cols="20" rows="3"/> </tr> <tr> <s:textfield label="原需积分" name="goods.originalPoint" value="%{model.originalPoint}" required="true"/> </tr> <tr> <s:textfield label="现需积分" name="goods.nowPoint" value="%{model.nowPoint}" required="true"/> </tr> <tr> <s:radio label="是否发布" name="goods.published" list="#{true:'发布',false:'不发布'}" value="%{model.published}" /> </tr> <tr> <td><input name="submit" type="submit" value="新增"/></td> <td> <input name="cancel" type="button" onclick="javascript:window.location.href='${ctx}/admin/goods/list.action'" value="取消"/> </td> </tr> </table> </s:form> <jsp:include page="../../common/inc/footer.jsp"/>
右击“pointShop”选择【Run As】>【Run On Server】启动Tomcat服务器,在商品列表页面单间【新增】按钮将显示图11-11界面。
图11-12 后台商品新增页面
3、后台兑换码管理
提供根据商品ID查询兑换码列表及新增兑换码操作,兑换码通过文本框输入多个,使用换行分割。
3.1、Action实现
package cn.javass.point.web.admin.action; //省略import public class GoodsCodeAction extends BaseAction { public String list() { getValueStack().set(MODEL, goodsService.get(goodsId)); getValueStack().set(PAGE, goodsCodeService.listAllByGoods(getPn(), goodsId)); return LIST; } public String doAdd() { getValueStack().set(MODEL, goodsService.get(goodsId)); return ADD; } public String add() { String[] codes = splitCodes(); goodsCodeService.save(goodsId, codes); return list(); } private String[] splitCodes() {//将根据换行分割code码 if(codes == null) { return new String[0]; } return codes.split("\r"); //简单起见不考虑“\n” } //字段驱动数据填充 private int id = -1; //前台提交的商品兑换码ID private int goodsId = -1; //前台提交的商品ID private String codes;//前台提交的兑换码,由换行分割 private GoodsCodeModel goodsCode; //前台提交的商品兑换码模型对象 //省略字段驱动数据的getter和setter //依赖注入Service private IGoodsCodeService goodsCodeService; private IGoodsService goodsService; //省略依赖注入的getter和setter }
3.2、Spring配置文件定义(resources/cn/javass/web/pointShop-admin-servlet.xml):
<bean name="/admin/goodsCodeAction" class="cn.javass.point.web.admin.action.GoodsCodeAction" scope="prototype"> <property name="goodsService" ref="goodsService"/> <property name="goodsCodeService" ref="goodsCodeService"/> </bean>
3.3、JSP实现商品兑换码列表页面(WEB-INF/jsp/admin/goodsCode/list.jsp)
商品兑换码列表页面时将展示相应商品的兑换码。
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="商品管理-商品Code码列表"/> </jsp:include> <a href="${ctx}/admin/goodsCode/doAdd.action?goodsId=${model.id}">新增</a>| <a href="${ctx}/admin/goods/list.action">返回商品列表</a><br/> <table border="1"> <tr> <th>ID</th> <th>所属商品</th> <th>兑换码</th> <th>购买人</th> <th>兑换时间</th> <th>是否已经兑换</th> <th></th> </tr> <s:iterator value="page.items"> <tr> <td><s:property value="id"/></td> <td><s:property value="goods.name"/></td> <td><s:property value="code"/></td> <td><s:property value="username"/></td> <td><s:date name="exchangeTime" format="yyyy-MM-dd"/></td> <td><s:property value="exchanged"/></td> <td>删除</td> </tr> </s:iterator> </table> <jsp:include page="../../common/inc/footer.jsp"/>
右击“pointShop”选择【Run As】>【Run On Server】启动Web服务器,在浏览器中输入“http://localhost:8080/pointShop/admin/goods/list.action”,然后在指定商品后边点击【查看兑换码】将显示图11-15界面。
图11-15 商品兑换码列表
3.4、JSP实现商品兑换码新增页面(WEB-INF/jsp/admin/goodsCode/add.jsp)
用于新增指定商品的兑换码。
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="用户管理-新增"/> </jsp:include> <s:fielderror cssStyle="color:red"/> <s:form action="/admin/goodsCode/add.action" method="POST" acceptcharset="UTF-8"> <s:token/> <s:hidden name="goodsId" value="%{model.id}" /> <table border="1"> <tr> <s:textfield label="所属商品" name="model.name" readonly="true"/> </tr> <tr> <s:textarea label="code码" name="codes" cols="20" rows="3"/> </tr> <tr> <td><input name="submit" type="submit" value="新增"/></td> <td><input name="cancel" type="button" onclick="javascript:window.location.href='${ctx}/admin/goodsCode/list.action?goodsId=<s:property value='%{model.id}'/>'" value="取消"/></td> </tr> </table> </s:form> <jsp:include page="../../common/inc/footer.jsp"/>
右击“pointShop”选择【Run As】>【Run On Server】启动Tomcat服务器,在商品兑换码列表中单击【新增】按钮将显示图11-16界面。
图11-16 兑换码新增页面
4、前台商品展示及购买模块:
前台商品展示提供商品展示及购买页面,购买时应考虑是否有足够兑换码等,此处错误消息使用硬编码,应该考虑使用国际化支持,请参考学习国际化。
4.1、Action实现
package cn.javass.point.web.front.action; //省略import public class GoodsAction extends BaseAction { private static final String BUY_RESULT = "buyResult"; public String list() { getValueStack().set(PAGE, goodsService.listAllPublished(getPn())); return LIST; } public String buy() { String username = "test"; GoodsCodeModel goodsCode = null; try { goodsCode = goodsCodeService.buy(username, goodsId); } catch (NotCodeException e) { this.addActionError("没有足够的兑换码了"); return BUY_RESULT; } catch (Exception e) { e.printStackTrace(); this.addActionError("未知错误"); return BUY_RESULT; } this.addActionMessage("购买成功,您的兑换码为 :"+ goodsCode.getCode()); getValueStack().set(MODEL, goodsCode); return BUY_RESULT; } //字段驱动数据填充 private int goodsId; //省略字段驱动数据的getter和setter //依赖注入Service IGoodsService goodsService; IGoodsCodeService goodsCodeService; //省略依赖注入的getter和setter }
4.2、Spring配置文件定义(resources/cn/javass/web/pointShop-front-servlet.xml):
<bean name="/front/goodsAction" class="cn.javass.point.web.front.action.GoodsAction" scope="prototype"> <property name="goodsService" ref="goodsService"/> <property name="goodsCodeService" ref="goodsCodeService"/> </bean>
4.3、JSP实现前台商品展示及购买页面(WEB-INF/jsp/ goods/list.jsp)
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="积分商城-商品列表"/> </jsp:include> <s:iterator value="page.items" status="status"> <s:property value="#status.index + 1"/>.<s:property value="name"/> <a href="${ctx}/goods/buy.action?goodsId=<s:property value='id'/>">【购买】</a><br/> 描述:<s:property value="description"/><br/> <s>需要积分<s:property value="originalPoint"/></s> 现需积分:<b><s:property value="nowPoint"/></b><br/> </s:iterator> <jsp:include page="../../common/inc/footer.jsp"/>
右击“pointShop”选择【Run As】>【Run On Server】启动Web服务器,在浏览器中输入http://localhost:8080/pointShop/goods/list.action将显示图11-17界面。
图11-17 前台商品展示即购买页面
在前台商品展示即购买页面中点击购买,如果库存中还有兑换码,将购买成功,否则购买失败。
4.3、商品购买结果页面(WEB-INF/jsp/admin/goods/buyResult.jsp)
购买成功将通过“<s:actionmessage/>”标签显示成功信息并将兑换码显示给用户,购买失败将通过“<s:actionerror/>”标签提示如积分不足或兑换码没有了等错误信息。
<%@ page language="java" pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%> <%@ include file="../../common/inc/tld.jsp"%> <jsp:include page="../../common/inc/header.jsp"> <jsp:param name="title" value="积分商城-购买结果"/> </jsp:include> <s:actionerror/> <s:actionmessage/> <jsp:include page="../../common/inc/footer.jsp"/>
在商品展示及购买列表购买成功或失败将显示图11-18或图11-19界面。
图11-18 购买成功页面
图11-19 购买失败页面
到此SSH集成已经结束,集成SSH是非常简单的,但开发流程及开发思想是关键。
我们整个开发过程是首先抽象和提取通用的模块和代码,这样可以复用减少开发时间,其次是基于通用层开发不可预测部分(即可变部分),因为每个项目的功能是不一样的。在开发过程中还集中将重复内容提取到一处这样方便以后修改。
原创内容,转载请注明私塾在线【http://sishuok.com/forum/blogPost/list/2516.html】
发表评论
-
第十九章 动态URL权限控制——《跟我学Shiro》
2014-03-28 22:51 0用过Spring Security的朋友应该比较熟悉对URL ... -
第十九章 动态URL权限控制——《跟我学Shiro》
2014-03-28 22:51 0用过Spring Security的朋友应该比较熟悉对URL ... -
在应用层通过spring解决数据库读写分离
2012-11-09 07:28 3如何配置mysql数据库的主从? 单机配置mys ... -
跟我学spring3系列 word原版 下载
2012-11-03 20:39 122172《跟我学spring3系列》自发布以来得到大家的认可,非 ... -
跟我学spring3 电子书下载(完)
2012-05-03 14:23 52707感谢iteye各位网友对我的支持,在此谢过了! ... -
跟我学spring3 目录贴及电子书下载
2012-04-10 19:00 390402扫一扫,关注我的公众号 购买地址 ... -
【第十三章】 测试 之 13.3 集成测试 ——跟我学spring3
2012-03-30 07:11 2748713.3 集成测试 13.3.1 ... -
【第十三章】 测试 之 13.1 概述 13.2 单元测试 ——跟我学spring3
2012-03-28 07:46 2360313.1 概述 13.1.1 测 ... -
【第十二章】零配置 之 12.5 综合示例-积分商城 ——跟我学spring3
2012-03-27 15:13 2078412.5 综合示例 12.5.1 概述 在第十一 ... -
【第十二章】零配置 之 12.4 基于Java类定义Bean配置元数据 ——跟我学spring3
2012-03-26 08:26 2989312.4 基于Java类定义Bean配置元数据 12 ... -
【第十二章】零配置 之 12.4 基于Java类定义Bean配置元数据 ——跟我学spring3
2012-03-26 08:00 56712.4 基于Java类定义Bean配置元数据 12 ... -
spring培训PPT(欢迎下载)
2012-03-24 21:55 45java私塾的 spring培训的PPT 欢迎大家下载。 包括 ... -
java私塾的spring培训PPT(欢迎下载)
2012-03-22 12:41 2973java私塾的 spring培训的PPT 欢迎大家下载。 ... -
【第十二章】零配置 之 12.3 注解实现Bean定义 ——跟我学spring3
2012-03-22 08:00 2663612.3 注解实现Bean定 ... -
【第十二章】零配置 之 12.2 注解实现Bean依赖注入 ——跟我学spring3
2012-03-19 08:00 3314112.2 注解实现Bean依赖注入 12.2.1 ... -
【第十二章】零配置 之 12.1 概述 ——跟我学spring3
2012-03-19 07:59 2027912.1 概述 12.1.1 什 ... -
【第十一章】 SSH集成开发积分商城 之 11.2 实现通用层 ——跟我学spring3
2012-03-14 08:08 1910811.2 实现通用层 11.2 ... -
【第十一章】 SSH集成开发积分商城 之 11.1 概述 ——跟我学spring3
2012-03-13 16:37 1939511.1 概述 11.1.1 功能概述 ... -
【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我学spring3
2012-03-13 08:46 12579先进行通用配置, 【第十章】集成其它Web框架 之 1 ... -
【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我学spring3
2012-03-12 08:16 12916先进行通用配置, 【第十章】集成其它Web框架 之 1 ...
相关推荐
【Spring3 SSH集成开发】 Spring、Struts2和Hibernate(SSH)是Java Web开发中非常流行的三大框架。它们各自负责应用程序的不同层面:Spring提供依赖注入和面向切面编程,Struts2处理MVC模式,而Hibernate则专注于...
【第十一章】SSH集成开发积分商城。SSH即Spring + Struts + Hibernate的组合,是一种常用的Web开发架构。11.1节概述SSH集成开发积分商城,11.2节讨论如何实现通用层,11.3节探讨如何实现积分商城层。 【第十二章】...
【第十一章】 SSH集成开发积分商城: 1. **11.1 概述**:SSH指的是Spring、Struts2和Hibernate的组合,本章将这些技术整合到一个积分商城的实例中,演示了SSH框架在实际项目中的应用。 2. **11.2 实现通用层**:这...
《跟我学Spring3》这本书详细介绍了Spring框架与各种ORM(对象关系映射)框架的集成,以及Spring的事务管理和Web框架集成。以下是其中关键知识点的深入解析: **8. ORM支持** 1. **8.1 概述**:ORM允许开发者以面向...
SSH集成开发是Java Web开发中的一个经典组合,它由Spring、Struts2和Hibernate三个开源框架组成,分别负责控制层、表现层和持久层的管理。这个集成项目旨在提供一个全面的解决方案,使得开发者能够更高效地构建企业...
4. **第十一章:SSH集成开发积分商城** - **11.1 概述**:这一章以一个具体的积分商城项目为例,介绍SSH(Spring、Struts2和Hibernate)的集成开发过程。 - **11.2 实现通用层**:讲解了如何设计和实现通用的服务...
SSH集成是Java开发中一种常见的技术栈组合,主要包括Spring、Hibernate和Struts(或Spring MVC)这三个框架。在这个项目中,SSH被用来构建一个用户管理系统,实现了用户的基本操作以及权限控制功能。以下是对这些...
【网上商城——SSH电子商城】项目是一个典型的Java企业级应用示例,主要采用了Spring、Struts和Hibernate这三大框架,也被称为SSH框架。这个项目旨在提供一个完整的网上购物平台的实现,涵盖了电子商务系统中的关键...
SSH集成开发宝典是一本深度探讨Java Web开发中三大框架——Struts、Spring和Hibernate集成应用的权威指南。这本书旨在帮助开发者从基础到高级全面掌握SSH框架的使用,提升开发效率,实现高质量的Web应用程序。 ...
### SSH(Struts+Hibernate+Spring)集成开发步骤详解 #### 一、SSH框架简介 SSH框架是指由Struts、Hibernate以及Spring三个开源框架组成的Java Web应用开发模式。这三个框架分别负责Web层、持久层和业务逻辑层,...
SSH2(Struts2 + Spring + Hibernate2)是一种常见的Java Web开发框架组合,它整合了三个强大的开源项目,用于构建高效、可维护的企业级应用程序。在这个"SSH2实现的商城系统"中,我们主要探讨以下几个核心知识点: ...
SSH是Java开发中的一种经典企业级应用框架组合,由Struts、Spring和Hibernate三个开源框架组成。这个压缩包“ssh集成开发jar包”包含了这三个框架的核心库,方便开发者在项目中进行快速集成和开发。 **Struts框架**...
SSH集成是Java开发中一种常见的框架整合方式,它包含了Spring、Struts和Hibernate这三个开源框架。这三者分别负责不同的职责:Spring作为整体的应用管理框架,Struts处理MVC(模型-视图-控制器)架构,而Hibernate则...
Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单...
在Java开发领域,SSH(Spring、Struts2、Hibernate)是一个经典的开源框架组合,用于构建高效、可维护的企业级Web应用程序。这些框架分别负责不同层面的任务:Spring作为基础架构框架,提供依赖注入和AOP(面向切面...
SSH集成是Java开发中一种常见的技术栈组合,包括Spring、Struts和Hibernate,它们分别负责应用的依赖注入、MVC框架和对象关系映射。在这个例子中,SSH被用来构建一个积分管理系统,其中Spring2.5、Struts2和...
SSH集成框架,全称为Spring、Struts和Hibernate的组合,是Java Web开发中常见的三大开源框架的集成。这个框架组合提供了完整的MVC(Model-View-Controller)设计模式支持,帮助开发者构建高效、可维护的Web应用。接...