閱讀361 返回首頁    go 人物


關於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">

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

       </action>

</package>

則訪問URL為:https://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">

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

       </action>

</package>

則訪問URL為:https://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}">

           <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}">

           <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="https://java.sun.com/jsp/jstl/core"prefix="c" %>

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

<%@ taglib uri="https://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 %>

<!-- 引入公共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"%>

<%@ include %>

<head>

    <title>遊戲參數信息</title>

    <%@ include %>

</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"

    "https://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}">

           <result>${result}</result>

       </action> 

    </package>

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

       <!-- 通過URL訪問的路徑是 /namesapce/Entity/method.do -->

<action name="*/*"method="{2}" >

           <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;

    }

   

}

最後更新:2017-04-02 06:51:53

  上一篇:go preferenceActivity和preferencescreen用法
  下一篇:go Firefox(火狐)瀏覽器擴展開發初探