一直没做过SSH(Struts2+Spring+Hibernate)的实际项目,只是三个框架学的还熟练,但整合起来使用就不知道了。所以前段时间在网上找了一套SSH实际项目的视频来学习(确切的说是买的...),一直没时间来总结,得到的经验主要是SSH的整合及配置,更多的则是SSH之外的一些经验,比如代码的书写及规范上就给了我很大的启发,很多经验只有从实际项目中才能得到。总体来说,SSH整合起来使用不是很难,配置文件也基本是固定的模式。

先看下项目截图

1.首页

2.商品详细

3.购物车

4.订单管理

5.用户注册

6.后台管理系统首页【后台系统使用的是easyui】

7.管理用户

8.项目工程结构

*******************************************************************************************************************************************************************

*******************************************************************************************************************************************************************

经验总结

一.首先说说这个项目

1.之前做过的项目大多只有后台系统,没有前端,不过学了这个系统之后,其实前端也不难,前端页面主要由专门的人员做好后,你只需要把数据显示到上面就行了,然后你可能还需要写一些js的代码。

然后说说前端页面,前端页面把一些公共的部分提取出来,其它页面只需引入即可。公共部分如顶部,底部:

通用页面放到一个文件夹里:

在页面引入即可:

2.系统不变的数据在系统启动时就缓存到application中。

比如首页商品分类,导航栏内容等,这些数据基本是不会变的,可以在系统启动时就加载出来。就需要写一个监听器类,在服务启动时,将数据库中的数据加载进内存,并将其赋值给一个属性名,其它的 Servlet 就可以通过 getAttribute 进行属性值的访问

3.导航,如下图。以前我写类似的导航代码时一般是用js判断各个层级,然后拼凑出一个导航来。然而作者是在服务端生成导航代码,他将生成导航的方法写到一个工具类中,每次访问哪个页面的时候,直接生成这段导航代码,然后返回到前端。这种做法不仅提高了开发效率,也提高了代码的重用性,好!

导航工具类:

 package com.lizhou.tools;

 import java.util.List;

 /**
* 导航工具类
* @author Administrator
*
*/
public class NavTool { /**
* 生成一级导航
* @param subName
* @return
*/
public static String genNavCode(String subName){
StringBuffer navCode=new StringBuffer();
navCode.append("您现在的位置:");
navCode.append("<a href='index.jsp'>首页</a>&nbsp;");
navCode.append("&gt; ");
navCode.append(subName);
return navCode.toString();
} /**
* 生成多级导航
* @param hrefList 导航标签链接的集合
* @return
*/
public static String genNavCode(List<String> hrefList){
StringBuffer navCode=new StringBuffer();
navCode.append("您现在的位置:");
navCode.append("<a href='index.jsp'>首页</a>&nbsp;");
navCode.append("&gt; ");
for(String href : hrefList){
navCode.append(href);
navCode.append("&gt; ");
}
String nav = navCode.substring(0, navCode.lastIndexOf("&gt; "));
return nav;
}
}

二、说一说使用SSH开发的感受

之前做一些完整的项目时一直使用的是JDBC+Servlet+Jsp,然后还有就是DBUtils等一些包来简化一些工作量。我会将mysql的一些操作封装成一个工具类,会写一个BaseDao来操作数据库,BaseDao能解决简单的增删改查功能,但要解决一些比较复杂的,比如涉及到级联的时候,可能就不适用了,需要重新写个类来实现相关的功能。自己设计好bean类后,还需要去设计表结构,而如果类有改动,则需要重新设计表,复杂的时候可能设计到几张表,如果有外键关系的话更恼火......

使用SSH的话,首先来说你需要设计好类结构,然后加上注解或者声明式配置好,hibernate会自动生成表结构,而如果类有改动,表结构也会自动更改,这算是大大节省了开发时间了。然后,hibernate只需要一个BaseDao就基本能解决所有的数据操作,因为hibernate支持泛型。还有传数据和参数的问题,我们只需在action里写一个字段即可,省了很多代码。

总的来说,使用SSH框架,我们只需要关心业务逻辑的实现即可,其它的很多问题不必担心。不过我在想我是不是离底层越来越远了......我个人还是挺喜欢写原生代码的...不喜欢框架。

三、代码上得到的一些经验

1.一类操作写到一个方法里:比如,根据产品名称查询,根据产品类别查询,模糊查询,查询所有等操作本属于一个操作:查询产品。在以前,我可能会分别写几个方法来查询,getByProductName(String name), getByProductType(String type), getProductList(),然而这些方法只是sql语句不一样而已,代码非常冗余。这些参数本就是产品这个类的字段,所以完全可以将这些查询参数封装到一个Product对象里,在一个方法里每个条件一个判断语句,然后拼凑Sql语句即可:getProductList(User user).

比如下面这个service里查询产品的操作:使用一个集合来装参数,根据条件拼SQL语句。这样减少了代码,逻辑性也更强了,维护也方便。

 public List<Product> getProductList(Product product, PageBean pageBean) {
StringBuffer sbHQL = new StringBuffer("FROM Product ");
//存放参数
List<Object> param = new LinkedList<Object>();
if(product != null){
//获取特价商品
if(product.getSpecialPrice() == 1){
sbHQL.append("AND specialPrice=1 ORDER BY specialPriceTime DESC ");
}
//获取热卖商品
if(product.getHot() == 1){
sbHQL.append("AND hot=1 ORDER BY hotTime DESC ");
}
//获取大类下的商品
if(product.getBigType() != null){
//添加参数
param.add(product.getBigType().getId());
sbHQL.append("AND bigType.id=? ");
}
//获取大类下的某个小类商品
if(product.getSmallType() != null){
//添加参数
param.add(product.getSmallType().getId());
sbHQL.append("AND smallType.id=? ");
}
//模糊搜索
if(!StringTool.isEmpty(product.getName())){
//添加参数
param.add("%"+product.getName()+"%");
sbHQL.append("AND name like ?");
}
}
String hql = sbHQL.toString().replaceFirst("AND", "WHERE");
//是否分页
if(pageBean != null){
return baseDao.find(hql, param, pageBean);
} else{
return baseDao.find(hql, param);
}
}

2.关于json的一个技巧:可以写一个处理器来转换JSON中的一些对象。比如产品有一个日期属性,类型为java.util.Date。如果不重新处理这个日期,

首先看一下应用场景:

 /**
* 查询产品集合
* @return
* @throws Exception
*/
public String list() throws Exception{
//分页对象
PageBean pageBean = new PageBean(page, Integer.parseInt(rows));
//根据查询条件和分页对象查询产品集合
List<Product> productList = productService.getProductList(product, pageBean);
//产品总记录数
long total = productService.getProductCount(searchProduct); //JSON配置
JsonConfig config = new JsonConfig();
//过滤掉的属性
config.setExcludes(new String[]{"orderProductList"});
JSONArray rows = JSONArray.fromObject(productList, config);
JSONObject result = new JSONObject();
result.put("rows", rows);
result.put("total", total);
//返回json字符串
ResponseTool.write(ServletActionContext.getResponse(), result);
System.out.println(result.toString());
return null;
}

这里没有对产品的日期做处理,输出如下结果:"hotTime":{"date":1,"day":3,"hours":0,"minutes":0,"month":0,"nanos":0,"seconds":0,"time":1388505600000,"timezoneOffset":-480,"year":114}

可以看到把Date类型直接按对象来解析了,这不是我们想要的。在以前我的处理办法是在Product里再添加一个String类型的日期字段,这种方法虽然可行,但其实不符合程序设计,用起来着实不爽O(∩_∩)O哈哈~。

然后这次学到了,可以写一个处理器类,该类需要实现JSON的一个接口:net.sf.json.processors.JsonValueProcessor

实现类如下:

 package com.lizhou.tools;

 import java.text.SimpleDateFormat;

 import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor; /**
* json-lib 日期处理类
* @author bojiangzhou
*
*/
public class DateJsonValueProcessor implements JsonValueProcessor{ /**
* 日期格式
*/
private String format; public DateJsonValueProcessor(String format){
this.format = format;
} public Object processArrayValue(Object value, JsonConfig jsonConfig) {
// TODO Auto-generated method stub
return null;
}
    
public Object processObjectValue(String key, Object value, JsonConfig jsonConfig) {
if(value == null)
{
return "";
}
if(value instanceof java.sql.Timestamp)
{
String str = new SimpleDateFormat(format).format((java.sql.Timestamp)value);
return str;
}
if (value instanceof java.util.Date)
{
String str = new SimpleDateFormat(format).format((java.util.Date) value);
return str;
} return value.toString();
} }

然后只需注册该处理器即可:config.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd"));

 /**
* 查询产品集合
* @return
* @throws Exception
*/
public String list() throws Exception{
//分页对象
PageBean pageBean = new PageBean(page, Integer.parseInt(rows));
//根据查询条件和分页对象查询产品集合
List<Product> productList = productService.getProductList(product, pageBean);
//产品总记录数
long total = productService.getProductCount(searchProduct); //JSON配置
JsonConfig config = new JsonConfig();
//过滤掉的属性
config.setExcludes(new String[]{"orderProductList"});
18 //注册日期处理器
19 config.registerJsonValueProcessor(java.util.Date.class, new DateJsonValueProcessor("yyyy-MM-dd"));
JSONArray rows = JSONArray.fromObject(productList, config);
JSONObject result = new JSONObject();
result.put("rows", rows);
result.put("total", total);
//返回json字符串
ResponseTool.write(ServletActionContext.getResponse(), result);
System.out.println(result.toString());
return null;
}

输出结果:"hotTime":"2014-01-01"

同样的,也可以实现其它级联对象处理器,比如产品里有个BigType(大类别,有id,name,remark,productList),但我在显示产品列表时只需要大类别的名称和id,这时就可以写一个对象处理器。

如下:

 package com.lizhou.tools;

 import java.beans.PropertyDescriptor;
import java.lang.reflect.Method; import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;
import net.sf.json.processors.JsonValueProcessor; /**
* 解决对象级联问题
* @author Administrator
*
*/
public class ObjectJsonValueProcessor implements JsonValueProcessor{ /**
* 保留的字段
*/
private String[] properties; /**
* 处理类型
*/
private Class<?> clazz; /**
* 构造方法
* @param properties
* @param clazz
*/
public ObjectJsonValueProcessor(String[] properties,Class<?> clazz){
this.properties = properties;
this.clazz =clazz;
} public Object processArrayValue(Object arg0, JsonConfig arg1) {
// TODO Auto-generated method stub
return null;
} public Object processObjectValue(String key, Object value, JsonConfig jsonConfig) {
PropertyDescriptor pd = null;
Method method = null;
StringBuffer json = new StringBuffer("{");
try{
for(int i=0;i<properties.length;i++){
pd = new PropertyDescriptor(properties[i], clazz);
method = pd.getReadMethod();
String v = String.valueOf(method.invoke(value));
json.append("'"+properties[i]+"':'"+v+"'");
json.append(i != properties.length-1?",":"");
}
json.append("}");
}catch (Exception e) {
e.printStackTrace();
}
return JSONObject.fromObject(json.toString());
} }

同样,注册该处理器即可:

 config.registerJsonValueProcessor(ProductBigType.class, new ObjectJsonValueProcessor(new String[]{"name", "id"}, ProductBigType.class));
config.registerJsonValueProcessor(ProductSmallType.class, new ObjectJsonValueProcessor(new String[]{"name", "id"}, ProductSmallType.class));

*******************************************************************************************************************************************************************

*******************************************************************************************************************************************************************

总的来说就是这些,还有些比较细节的忘了,最大的收获就是经验还是得从实际项目中来....

然后还遇到一个非常纠结的问题:那就是session的过期时间。场景是这样的,以前做项目的时候我在session中存的数据几乎是在10秒内就消失了,比如我存登录用户的信息(User对象)到session中,如果一直刷新页面不会消失,但停留几秒钟,再刷新一次,数据就消失了,但是session并没有销毁。以前百度过很多资料,包括修改session过期时间,都没用,也有说是tomcat的配置问题,我就懒得改了。

直到做这个项目,我发现存在session中的登录用户信息、包括购物车里的数据同样是如此,过不了多久就消失了;但是存的其它的一些信息,比如字符串形式的数据,一直没有消失,在不关闭浏览器的情况下,那些数据一直都在;我就纠结了,难道消失的只是那些对象型数据?后面再找时间测试,如果你们知道问题所在,请告诉我,O(∩_∩)O谢谢!!!

-------------------------------------------------------------------------------------------------------------

附上源码:仅供学习,后台大部分没有做完!

文件包含:

地址:SSH商城系统(ebuy)

跟着视频做的SSH项目总结的更多相关文章

  1. 从零开始做SSH项目(二)

    使用hibernate测试加载数据.删除数据和修改数据等功能时,针对的是与数据库表user对应的User. 为了简化对其他数据表对应的实体类的持久化操作,可以在项目中创建一个BaseHibernate ...

  2. SSH项目(struts+spring+hibernate)搭建_代码简化

    在上篇讲到SSH框架的搭建后,为了有利于随时能熟练的把一个SSH的项目快速的搭建起来,我又进一步对其了解学习,对代码进行了简化,大家相互讨论学习. 为什么要简化:  如果要做一个大项目,假设项目的ac ...

  3. SSH项目整合教学Eclipse搭建SSH(Struts2+Spring3+Hibernate3)

    这篇博文的目的 尝试搭建一个完整的SSH框架项目. 给以后的自己,也给别人一个参考. 读博文前应该注意: 本文提纲:本文通过一个用户注册的实例讲解SSH的整合.创建Struts项目,整合Hiberna ...

  4. easyui小清新俺也晒晒 视频管理软件bs项目

    easyui小清新俺也晒晒 视频管理软件bs项目 针对设备的管理软件 这是我听到最多的话.视频管理软件bs项目.easyui 好与坏我不去评价 项目做了好几个月,其实代码看来也没用多少,但是做需求,时 ...

  5. 【SSH项目实战三】脚本密钥的批量分发与执行

    [SSH项目实战]脚本密钥的批量分发与执行 标签(空格分隔): Linux服务搭建-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品,允许转载, ...

  6. Myeclipse插件快速生成ssh项目并配置注解 在action层注入service的超详细过程

    最近发现,我对于ssh的 自动注入配置 还是不熟悉,于是整理了一下 终于做了一个 简单的 注入配置出来. 以前都是在applicationContext.xml 里面这样配 <bean id=& ...

  7. 使用eclipse整合ssh项目的例子--lljf(1)

    最近向自己单独做一个基于ssh的项目,来预习和巩固自己的Java基础.找了一个实际生活中的定做衣服的例子来做一做,放到博客上给大家一起分享学习,后边会持续更新项目编写时候遇到的困难和使用的技术等. 1 ...

  8. 转载:eclipse 搭建SSH项目(第二篇,有具体的项目例子)

    原文地址:http://blog.csdn.net/yeohcooller/article/details/9316923 读博文前应该注意: 本文提纲:本文通过一个用户注册的实例讲解SSH的整合.创 ...

  9. 【SSH项目实战】脚本密钥的批量分发与执行【转】

    [TOC] 前言 <项目实战>系列为<linux实战教学笔记>第二阶段内容的同步教学配套实战练习,每个项目循序衔接最终将组成<Linux实战教学笔记>第二阶段核心教 ...

随机推荐

  1. Java生成和操作Excel文件

    JAVA EXCEL API:是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容.创建新的Excel文件.更新已经存在的Excel文件.使用该API非Windows操作系统也可以通过 ...

  2. 20145320 《Java程序设计》第8周学习总结

    20145320 <Java程序设计>第8周学习总结 教材学习内容总结 15.1日志 java.util.logging包提供了日志功能相关类与接口,不必额外配置日志组件,就可以在标准ja ...

  3. 获取图片中感兴趣区域的信息(Matlab实现)

    内容提要 如果一幅图中只有一小部分图像你感兴趣(你想研究的部分),那么截图工具就可以了,但是如果你想知道这个区域在原图像中的坐标位置呢? 这可是截图工具所办不到的,前段时间我就需要这个功能,于是将其用 ...

  4. 同事的游戏项目--Robocode-学习链接

    Robocode机器人库学习链接:http://www.pudn.com/search_db.asp?keyword=Robocode 官网 :http://robocode.sourceforge. ...

  5. 循环生成sql文件。

    package com; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java ...

  6. java 静态函数锁对象说明

    在内存加载.class文件后,会自动创建一个对象,用于保存class的信息,与我们程序员手工创建的对象不一样.

  7. bzoj1977 [BeiJing2010组队]次小生成树 Tree

    和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...

  8. 2.1.5 计算机网络协议: TCP/IP

    应用程序阶段:妳打开浏览器,在浏览器上面输入网址列,按下 [Enter].此时网址列与相关数据会被浏览器包成一个数据, 并向下传给 TCP/IP 的应用层: 应用层:由应用层提供的 HTTP 通讯协议 ...

  9. ECMAScript 6教程 (二) 对象和函数

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文连接,博客地址为 http://www.cnblogs.com/jasonnode/ .该系列课程是 ...

  10. Redis的简介与安装

    1.简介 Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted ...