关于ssh开发的一点小结

   

废话 start

  

从学习ssh以来,忙碌了那么久,做了那么多实践开发项目,一直想总结一下,一直没时间和心思写,现在趁着上班打酱油的时间简单的总结一下吧!

他们说,跨的太大了就容易扯蛋!

废话 end

Struts2:

一,             struts.xml配置最简化

   namespace:是指访问路径的命名空间,默认情况是项目根路径。例如项目名称为news

   配置如下:

    <package name="default"namespace="/pages" extends="struts-default">

       <!-- 通过URL访问的路径是 /namesapce/Entity/method.do -->

       <action name="addNew" method="addNew"class="cn.ipanel.itime.action.NewAction">

           <result>/jsp/list.jsp</result>

       </action>

</package>

则访问URL为:http://xxx.xxx.xx:xx/news/pages/addNew.do

亦如配置:

    <package name="default"namespace="/pages/news" extends="struts-default">

       <!-- 通过URL访问的路径是 /namesapce/Entity/method.do -->

       <action name="addNew" method="addNew"class="cn.ipanel.itime.action.NewAction">

           <result>/jsp/list.jsp</result>

       </action>

</package>

则访问URL为:http://xxx.xxx.xx:xx/news/pages/news/addNew.do

虽然访问路径不一样但是请求的方法其实是一样的

  通配符使用:使用通配符*可以使得配置十分简化

   如配置:

 <package name="default"namespace="/pages " extends="struts-default">

       <!-- 通过URL访问的路径是 /namesapce/Entity/method.do -->

       <action name="add_*" method="add{1}"class="cn.ipanel.itime.action.{1}Action">

           <result>/jsp/list_{1}.jsp</result>

       </action>

</package>

   “*”代表所有,{1}代表第一个“*”,这样就可以节省配置,但是必须约定好命名规则。

视图结果定义到Action中:

   无论是在编写代码的时候还是在读代码的时候总会又到这样的烦恼,在action和strut文件之间来回切换,影响思维连贯性。所有试图将strut.xml的配置如下:

<package name="default" namespace="/pages" extends="struts-default">

       <!-- 通过URL访问的路径是 /namesapce/Entity/method.do -->

       <action name="*/*" method="{2}"class="cn.ipanel.itime.action.{1}Action">

           <result>${result}</result>

       </action>

</package>

${result}是action实例成员变量

Action学增加成员变量  result 并提供get和set方法

例如

public String result = "success";

public String getResult(){

       return result;

    }

    public void setResult(String result) {

       this.result = result;

}

public String addNews() throws Exception {

       result = /jsp/list_news.jsp;

       return super.execute();

}

这样struts.xml只需一次性配置好,以后只要按照规范命名就可以把注意力放在actionz中而不用不再理strut.xml了,也不会影响项目的可读性

 

二,             参数接受及类型转换

   Struts2剪掉了struts1的actionForm,剪掉了actionForm与Pojo的冗余

   其实不论是struts1的actionForm封装参数还是Struts2的直接用属性提供set方法接受参数都需要对参数进行类型转换,一般用的BeanUtils,而通常情况先Struts2模式是使用ognl进行类型转换的,定义在action中的非复合类型参数还可以,可是遇到复合类型接受参数的时候就容易出现问题,比如时间类型。如果你做个ssh的开发你应该都会在lib中看到这样的一个jar: 是apache下面的一个包,是一个常用的在对象之间复制数据和数据类型转换的工具类, struts就是依赖于它进行ActionForm的创建和类型的转换的。无论是struts1的actionform还是struts2的pojo接收参数,大概都会有这样的一个过程, org.apache.commons.beanutils.BeanUtils和org.apache.commons.beanutils.converters包中有一系列converter类是最用的,BeanUtils主要用于对象属性之间的复制,依赖于其对类型的识别,和转换。无论是struts1的actionForm的还是Struts2的pojo接收参数,大概都有这样的一个过程:1解析request获取参数,2 创建 actionForm或者pojo对象,3 org.apache.commons.beanutils.converters对参数进行类型识别和抓获,4 属性复制。前提是我们提前对类型转换器进行注册。

  类型转换器的注册:

在可以再服务器启动时进行注册,注册之后,类型转换器就存在内存中,等待需要的时候调用

static{

ConvertUtils.register(new StringConverter(), String.class);

ConvertUtils.register(new StringConverter(),String.class);

       //date

ConvertUtils.register(new DateConverter(null),java.util.Date.class);

ConvertUtils.register(newSqlDateConverter(null),java.sql.Date.class);

ConvertUtils.register(new SqlTimeConverter(null),Time.class);

ConvertUtils.register(newSqlTimestampConverter(null),Timestamp.class);

       //number

ConvertUtils.register(new BooleanConverter(null), Boolean.class);

ConvertUtils.register(new ShortConverter(null), Short.class);

ConvertUtils.register(new IntegerConverter(null), Integer.class);

ConvertUtils.register(new LongConverter(null), Long.class);

ConvertUtils.register(new FloatConverter(null), Float.class);

ConvertUtils.register(new DoubleConverter(null), Double.class);

ConvertUtils.register(newBigDecimalConverter(null), BigDecimal.class);

ConvertUtils.register(newBigIntegerConverter(null),BigInteger.class);

}

 

三,             关于requestAware、sessionAware、applicationAware

Aware,意识的意思,request意识,session意识…

requestAware、sessionAware、applicationAware是封装在strut2的核心包里面的几个接口,

Struts2解除了与actionServlet的耦合,但很多时候我们还是会用的request,session这几个对象的,为此根据需要我们可以选择性的实现requestAware、sessionAware、applicationAware这几个接口,当然我们用的最多的还是requestAware接口;例如:

public abstract class BaseStruts2Action extends ActionSupport implementsRequestAware {

    protected Map requestMap = null;

    public String result = "success";

    static {

       //注册converters

       ConvertRegisterHelper.registerConverters();

        }

    //实现requestAware的方法

@Override

    public void setRequest(Map request) {

       this.requestMap = request;

    }

    public String delete(){

       request.put("message", "删除成功");

       return "/commons/message.jsp";

    }

 

}

Action中实现RequestAware,SessionAware,ApplicationAware接口,

实现这些接口,都会有相对应的setXXX()方法.就是说谁来执行这个action中的相应方法,谁就对这些个对象进行初始化(Spring中的注入).也就是Struts2为我们进行了初始化,所以这三个值都不需要自己初始化. 通过request.put("message", "删除成功")就相当于办消息存到了request的Attribut里面了,在message.jsp里面可以通过${message}取到值。

 

Hibernate 3.2

一,             ORM, 选择annotation

最初接触hibernate的时候进行or映射的时候都是通过xml,文件来映射的,一个pojo对应一个xml文件。Hibernate3.2提供了强大的注解机制,觉得通过annotation的方式进行or映射,就得代码可变得更高,提高内聚性,一不用在pojo和xml文件直接来回切换。例如:

@Entity

@Table(name = "tb_gate")

public class TbGate implements java.io.Serializable{

    private static final long serialVersionUID = 5454155825314635342L;

   

    @Length(max=30)

    private java.lang.String gateModeid;

    private java.lang.Integer gateId;

    //columns END

    public TbGate(){

    }

    public TbGate(

       java.lang.Integer gateId

    ){

       this.gateId = gateId;

    }

    public void setGateId(java.lang.Integer value) {

       this.gateId = value;

    }

    @Id @GeneratedValue(generator="custom-id")

    @GenericGenerator(name="custom-id", strategy = "assigned")

    @Column(name = "gate_id", unique = true, nullable = false, insertable = true, updatable = true, length = 10)

    public java.lang.Integer getGateId() {

       return this.gateId;

    }

    @Column(name = "gate_modeid", unique = false, nullable = true, insertable = true, updatable = true, length = 30)

    public java.lang.String getGateModeid() {

       return this.gateModeid;

    }

    public void setGateModeid(java.lang.String value) {

       this.gateModeid = value;

    }

   

    private TbMode tbMode;

    public void setTbMode(TbMode tbMode){

       this.tbMode = tbMode;

    }

    @ManyToOne(cascade = {}, fetch = FetchType.LAZY)

    @JoinColumns({

       @JoinColumn(name = "gate_modeid",nullable = false, insertable = false, updatable = false)

    })

    public TbMode getTbMode() {

       return tbMode;

  }

}

 

通过注解分别指明了映射的表名称,字段名称关联等信息。在sessionfactory的配置中指明映射的pojo:

-    --  --

<!-- 映射持久化类-->

    <mapping class="cn.serup.model.TbGate " />

</session-factory>

</hibernate-configuration>

二,            QBC(Query By Criteria)

最初用hibernate做项目的时候多是使用的hql语句进行对象检索,后来在一个团队项目中看到同事代码使用了Criteria,看着挺陌生的,但是代码挺简洁的,百度了一下才知道这就是著名的QBC检索方式, Hibernate中共提供了三种检索方式:HQL(Hibernate Query Language)、QBC、QBE(QueryBy Example)。Criteria提供了灵活的查询条件的组装。Hibernate 设计了 CriteriaSpecification 作为 Criteria 的父接口,下面提供了 Criteria和DetachedCriteria 。
   Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所以它是由 Hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需 Session,DetachedCriteria 提供了 2 个静态方法 forClass(Class) 或 forEntityName(Name)
进行DetachedCriteria 实例的创建。 Spring 的框架提供了getHibernateTemplate
().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria 来返回查询结果。Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 设置查询条件。可以设置 FetchMode( 联合查询抓取的模式 ) ,设置排序方式。对于 Criteria 还可以设置 FlushModel (冲刷 Session 的方式)和 LockMode (数据库锁模式)。 下面对 Criterion 和 Projection 进行详细说明。    Criterion 是 Criteria 的查询条件。Criteria 提供了 add(Criterion criterion) 方法来添加查询条件。     Criterion 接口的主要实现包括: Example 、 Junction 和 SimpleExpression 。而 Junction 的实际使用是它的两个子类 conjunction 和 disjunction ,分别是使用 AND 和 OR 操作符进行来联结查询条件集合。    Criterion 的实例可以通过 Restrictions 工具类来创建,Restrictions 提供了大量的静态方法,如 eq (等于)、 ge (大于等于)、 between 等来方法的创建 Criterion 查询条件 (SimpleExpression 实例)。除此之外, Restrictions 还提供了方法来创建 conjunction 和 disjunction 实例,通过往该实例的 add(Criteria) 方法来增加查询条件形成一个查询条件集合,

例如:

DetachedCriteria criteria = DetachedCriteria.forClass(Channel.class);

criteria.add(Restrictions.ne("wrap", 0));

criteria.add(Restrictions.eq("categoryId", 1));

criteria.add(Restrictions.like("name", "%频道%"));

List l = getHibernateTemplate().findByCriteria(criteria,(curPage - 1) * pageSize,pageSize);

 

Spring

 使用注解,简化配置

基于注释(Annotation)的配置有越来越流行的趋势,Spring 2.5以后 顺应这种趋势,提供了完全基于注释配置 Bean、装配 Bean 的功能,您可以使用基于注释的 Spring IoC 替换原来基于 XML 的配置。本文通过实例详细讲述了 Spring 2.5 基于注释 IoC 功能的使用,使用Annotation后我们可以把spring的配置简化到极致,几乎之用一行配置代码就看代替原来的所有

例如配置:

       <!-- component-scan自动搜索@Component , @Controller , @Service , @Repository等标注的类 -->

       <context:component-scan base-package="cn.**.dao"/>

<context:component-scanbase-package="cn.**.service" />

这样spring,在服务器启动的时候,spring就自动到匹配cn.**.dao和cn.**.service的中扫描发现有@Repository, @Component, @Controller , @Service , @Repository等标准的类就将其加入到ioc容器中

如:

@Repository

public class AdminDao {

    @SuppressWarnings("unchecked")

    public void method(String adminName) {

}

@Transactional

public class AdminService implements IAdminService {

    @Resource

    private AdminDao adminDao;

   

    public Admin findByAdminName(String adminName) {

       // TODO Auto-generatedmethod stub

       return this.adminDao.findByAdminName(adminName);

    }

}

 

Spring会根据@Repository和@Transactional注解将AdminDao和AdminService装配到bean工厂中(默认情况下id为类名的首字母小写),并通过@Resource标注将adminDao注入给adminService

 

三大框架ssh

一、  jsp层设计
文件结构:

 

良好的jsp文件结构的设计在一定程度也可简化设计,增强内聚性:

如图,把一下常用的公用的写到一个文件,在别的文件include进来即可

 

例如:

Taglibs.jsp

<%@ page contentType="text/html;charset=UTF-8"%>

<%@ taglib uri="http://java.sun.com/jsp/jstl/core"prefix="c" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"prefix="fmt" %>

<%@ taglib uri="http://java.sun.com/jsp/jstl/functions"prefix="fn" %>

<%@ taglib uri="/struts-tags"prefix="s" %>

<c:set var="ctx" value="${pageContext.request.contextPath}"/>

meta.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<%@ include file="/commons/taglibs.jsp"%>

<!-- 引入公共CSS和JS -->

<scripttype="text/javascript"src="${ctx}/js/jquery.min.js"></script>

<script type="text/javascript" src="${ctx}/js/page.js"></script>

<link href="${ctx}/css/reset.css" rel="stylesheet" type="text/css" />

<link href=${ctx}/css/page.css" rel="stylesheet" type="text/css" />

 

在其他页面中只需

<%@ page contentType="text/html;charset=UTF-8"%>

<%@ includefile="/commons/taglibs.jsp" %>

<head>

    <title>游戏参数信息</title>

    <%@ includefile="/commons/style.jsp" %>

</head>

加入红色部分即可。

 

 

二、  Action

提取重复动作和公用属性

在做项目的时候常常会发现有些动作常常在每个action中的不断的重复出现,例如对request等web元素的获取,返回结构的定义等等,所以应该把公用的动作或者属性提取出来写到一个共同的父类中,如:

public abstract class BaseAction extends ActionSupport implements RequestAware {

    protected Map requestMap = null;

    public String result = "success";

public voidcopyProperties(Object target,Object source) throws IllegalAccessException,InvocationTargetException {

        BeanUtils.copyProperties(target, source);

    }

    public void setRequest(Map request) {

        this.requestMap = request;

    }

    public HttpServletRequest getRequest() {

        return ServletActionContext.getRequest();

    }

    public HttpServletResponse getResponse() {

        return ServletActionContext.getResponse();

    }

    public String getResult() {

        return result;

    }

    public void setResult(String result) {

        this.result = result;

    }

   

}

 

实现Preparable,ModelDriven接口

 

   通常情况下在action里面少不了对一个pojo的增删查该等操作,无论是那种操作,都少不了对这个pojo的初始化这个步骤,也就是领域对象。 Strut2提供了Preparable接口,该接口提供了一个Preparable()方法,实现了该接口的action,执行方法之前都会先执行Preparable()方法,于是我们就可以再Preparable()方法中做领域对象的初始化了。

实现了modelDriven接口可以在action中直接获得例如User对象,它会将Object getModel()取得的User放到ValueStack中。可以理解为将这个User的属性追加到Action中。它主要是作用是实现类似Struts的FormBean功能。

在struts2中,提供了一种直接使用领域对象的方式,就是让action实现com.opensymphony.xwork2.ModelDriven接口,ModelDriven让你可以直接操作应用程序中的领域对象,允许你在web层和业务层使用相同的对象。

ModelDriven接口只有一个方法

       public Object getModel() {
return user;
}

该方法返回一个用于接收用户输入数据的对象模型,在这个模型对象中的属性可以直接通过(属性名)userName来访问,而不需要使用(对象名.属 性名)user.userName这种格式来访问了,在action也不需要对对象提供getter和setter方法了。

       Preparable、ModelDriven这两个接口通常是结合起来使用的,但是这里有个问题:默认的拦截器栈会先执行Preparable,再执行parma参数的获取,使得我们的领域模型不能正常初始化,我们想要的顺序应该是:先执行parma参数的获取,再执行Preparable方法,怎么办?我们可以改变连接器栈的顺序,strut提供了<interceptor-refname="paramsPrepareParamsStack"/>这个拦截器栈,从paramsPrepareParamsStack这个名字就可以知道提提供给我们的顺序,先prams参数获取再执行Prepare,最后将Param参数保存到valueStacks中。例如:

 

Action中代码:

public class AdminAction extends BaseAction implements Preparable,ModelDriven{

   

    private AdminManager adminManager;

    private Admin admin;

    java.lang.Integer id = null;

    public void prepare() throws Exception {

       if (id== null) {

           admin = new Admin();

       } else {

           admin = (Admin)adminManager.getById(id);

       }

    }

    public void setAdminManager(AdminManager manager) {

       this.adminManager = manager;

    }  

   

    public Object getModel() {

       return admin;

    }

   

    public void setAdminId(java.lang.Integer val) {

       this.id = val;

    }

    public String execute()throws Exception{

         this.result = “success.jsp”;

         return super.execute();

    }

}

 

Struts.xml:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC

    "-//ApacheSoftware Foundation//DTD Struts Configuration 2.0//EN"

    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <constant name="struts.devMode"value="true" />

    <constant name="struts.enable.SlashesInActionNames"value="true" />

    <package name="custom-default" extends="struts-default">

        <interceptors>

            <interceptor-stack name="customDefaultCrudStack">

                <interceptor-refname="paramsPrepareParamsStack"/>

            </interceptor-stack>

        </interceptors>

<package name="itime" namespace="/pages"extends=" customDefaultCrudStack ">

<action name="*/*"method="{2}"class="cn.ipanel.itime.action.{1}Action">

           <result>${result}</result>

       </action> 

    </package>

     <package name="terminal" namespace="/terminal"extends="struts-default">

       <!-- 通过URL访问的路径是 /namesapce/Entity/method.do -->

<action name="*/*"method="{2}" class="cn.ipanel.itime.action.{1}Action">

           <result>${result}</result>

       </action> 

    </package>

</struts>

   AdminAction在响应的时候:1 先获取adminId,如果有则id=adminId,没有则id=null;2 再执行Preprare方法,根据id是否为空分别对admin进行两种方式初始化;3 然后再获取admin属性对应的相关参数,有则执行admin里面的setXxx()方法。4 响应结束即excute方法处理完成之后 getModel()方法执行,将admin返回放入值栈中。

 

三、  Service、DAO

  很多时候,我们搭建ssh项目框架的时候,在做service层和dao层的都会用一个借口一个实现类,一对一的形式,如:

    

   刚开始学习做ssh项目的时候也是照着这么做的,也没去问个究竟,还来看了rapid-framWork的项目,有看了有位仁兄的一篇文章,叫做《关于接口的滥用问题》,感觉写得颇有道理。

   仔细观察一下,所以的service或者dao接口定义的方法都差不多,无法就是一些增删改查的方法,只是操作的对象不一样而已,那么何不把对象抽象一下,所有的接口写成一个接口,在写一个实现这个接口的抽象类,这样不减少接口的数量,增强了内聚性,还提供的代码的复用率,dao接口及抽象类写一次就可以再整个项目中使用。在这里泛型得到了很好的应用,例如:

 

 统一的dao接口,E,entity的抽象,pk,identity的抽象。

public interface EntityDao<E,PK extends Serializable>{

    public Object getById(PK id) throws DataAccessException;

    public void deleteById(PK id) throws DataAccessException;

    /** 插入数据 */

    public void save(E entity) throws DataAccessException;

    /** 更新数据 */

    public void update(E entity) throws DataAccessException;

    /** 根据id检查是否插入或是更新数据 */

    public void saveOrUpdate(E entity) throws DataAccessException;

    public boolean isUnique(E entity, String uniquePropertyNames) throwsDataAccessException;

    /** 用于hibernate.flush() 有些dao实现不需要实现此类  */

    public void flush() throws DataAccessException;

    public List<E> findAll() throws DataAccessException;

   

}

 

统一的dao抽象类,E,entity的抽象,pk,identity的抽象。

  public abstract class BaseHibernateDao<E,PK extends Serializable> extendsHibernateDaoSupport implements EntityDao<E,PK>{

    public abstract Class getEntityClass();

    public void save(E entity) {

       getHibernateTemplate().save(entity);

    }

   /*查询所以对象*/

    public List<E> findAll() {

       return getHibernateTemplate().loadAll(getEntityClass());

    }

    /*根据id查询对象*/

    public E getById(PK id) {

       return (E)getHibernateTemplate().get(getEntityClass(),id);

    }

    /*删除对象*/

    public void delete(Objectentity) {

       getHibernateTemplate().delete(entity);

    }

    public void delete(Serializable entity) {

       getHibernateTemplate().delete(entity);

    }

    /*根据id删除对象*/

    public void deleteById(PK id) {

       Object entity = getById(id);

       if(entity == null) {

           throw new ObjectRetrievalFailureException(getEntityClass(),id);

       }

       getHibernateTemplate().delete(entity);

    }

    /*更新对象*/

    public void update(E entity) {

       getHibernateTemplate().update(entity);

    }

    /*更新或保存对象*/

    public void saveOrUpdate(E entity) {

       getHibernateTemplate().saveOrUpdate(entity);

    }

 

具体的对象的Dao,E明朗化

@Repository

public class AdminDao extends BaseHibernateDao<Admin,java.lang.Integer>{

    public Class getEntityClass() {

       return Admin.class;

    }

 

}

 

 

Servic的结构和dao的结构也差不多,省去了接口,一个抽象类就ok了

例如:

 

统一的service抽象类,E,entity的抽象,pk,identity的抽象

@Transactional

public abstract class BaseService <E,PK extends Serializable>{

    protected Log log = LogFactory.getLog(getClass());

    protected abstract EntityDao getEntityDao();

    @Transactional(readOnly=true)

    public E getById(PK id) throws DataAccessException{

       return (E)getEntityDao().getById(id);

    }

    @Transactional(readOnly=true)

    public List<E> findAll() throws DataAccessException{

       return getEntityDao().findAll();

    }

    public void saveOrUpdate(E entity) throws DataAccessException{

       getEntityDao().saveOrUpdate(entity);

    }

    public void save(E entity) throws DataAccessException{

       getEntityDao().save(entity);

    }

    public void removeById(PK id) throws DataAccessException{

       getEntityDao().deleteById(id);

    }

    public void update(E entity) throws DataAccessException{

       getEntityDao().update(entity);

    }

    @Transactional(readOnly=true)

    public boolean isUnique(E entity, String uniquePropertyNames) throwsDataAccessException {

       return getEntityDao().isUnique(entity,uniquePropertyNames);

    }

}

 

 

具体的对象的servic,E明朗化

@Service

@Transactional

public class AdminServic extends BaseService<Admin,java.lang.Integer>{

    private AdminDao adminDao;

    public void setAdminDao(AdminDao dao) {

       this.adminDao = dao;

    }

    public EntityDao getEntityDao() {

       return this.adminDao;

    }

   

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值