我的平臺功能介紹

主體架構

主體採用Struts2 Spring3 Hibernate3.3架構。

 

Spring和Hibernate都採用Annotation方式省去了大量Bean的配置和ORM映射文件。

界面展示用JSP結合 Struts2 tags的方式。

 

主要模塊的頁面採用form,和list兩個頁面,前者負責新增、編輯、查看,後者負責數據列表展現。

 

權限管理

平臺採用基於角色的訪問控制RBAC模型,通過給角色授予訪問某資源(模塊,URL),再將角色分配給用戶,使用戶獲得訪問某些資源的權限。

 

對應的領域模型有“用戶”User,“角色”Role,“模塊”Module,“部門”Department。

 

權限採用Spring Security。

郵件發送組件

系統已在com.epro.crm.util.message.EmailHelper工具類中集成了JavaMail, 並在EmailService內置在了CommonBaseService中。如果業務需要發送郵件,只需在將郵件內容寫在EmailServiceImpl中,然後在Service中直接調用即可。系統將異步調用EmailHelper.sendEmail(…)方法,將郵件發出。

 

參考:com.epro.crm.service.system.impl.UserServiceImpl.add(User)

註冊用戶時,系統將註冊成功信息,異步的發送至用戶的註冊郵箱中。

protected void sendEmail(final List<String> recipientAccounts,final String message, final String subject){
		//判斷 系統設置 (是否已開啓 發送郵件模塊)
		if(Constants.YES.equals(Configurations.SEND_EMAIL)){
			//異步發送
			taskExecutor.execute(new Runnable() {
				public void run() {
					EmailHelper.sendEmail(recipientAccounts,message, subject);
				}
			});
		} else {
			log.info("系統郵件發送功能未開啓,無法發送短信");
		}
	}

界面表單驗證

使用了jQuery validate 表單驗證框架

參考 /page/user/user_form.jsp

jQuery(function(){
	$("#submitForm").validate({
		rules: {
			name: "required",
			username: {
				required: true,
				minlength: 4
				//remote:"UserAction!validateUsername"
			},
			phone:"digits",
			birthDay: "dateISO",
			email: {
				required: true,
				email: true
			}
		},
		success: function(label) {
            label.text('').addClass("success");
        },
		messages: {
			name: "請輸入用戶的姓名",
			phone:"電話號碼必須是數字",
			username: {
				required: "請輸入該用戶的登錄名(登錄賬號)",
				minlength: "登錄名最短4位"
			},
			birthDay: "請輸入合法日期格式 如:2011-3-11",
			email: "請輸入合法email格式"
		}
	});
	
});

增刪改查封裝

 

普通的數據訪問對象(Dao)接口應繼承於com.epro.crm.dao.base.CommonDaoInterface<T>,其默認已有增刪改查的接口。其實現類應繼承於com.epro.crm.dao.base.CommonBaseDao<T>,默認已有增刪改查等基本操作的實現,並可通過HibernateTemplate擴展其他的操作。如果需要按自定義的條件查詢,可以重寫CommonBaseDao類的String appendConditionHQL(T t)方法。

                    

參考:com.epro.crm.dao.system.impl.UserDaoImpl

 

增加

public void add(T t) {
		String stateStr = null;
		try {
			if (t instanceof DeletedByLogic ) {
				stateStr = BeanUtils.getProperty(t, "state");
				if(stateStr == null){
					BeanUtils.setProperty(t, "state",Constants.STATE_VALID);
				}
				hibernateTemplate.save(t);
			} else if (t instanceof DeletedByPhysics) {
				hibernateTemplate.save(t);
			} else {
				hibernateTemplate.save(t);
			}
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			throw new CrmSystemException("新增數據出錯",e);
		} 
	}
刪除
public void delete(T t) {
		try {
			String idStr = BeanUtils.getProperty(t, "id");
			long id = Long.parseLong(idStr);
			Object delObject = hibernateTemplate.get(t.getClass(), id);
			if (t instanceof DeletedByLogic) {
				BeanUtils.setProperty(delObject, "state",
						Constants.STATE_DELETED);
			} else if (t instanceof DeletedByPhysics) {
				hibernateTemplate.delete(delObject);
			} else {
				throw new CrmSystemException("實體類 " + t.getClass().getName()
						+ " 既不是物理刪除,也不是邏輯刪除");
			}
		} catch (Exception e) {
			log.error(e.getMessage(),e);
			throw new CrmSystemException("刪除對象" + t + "時,系統異常");
			
		}
	}

 查詢

	public List<T> getList(T t, final int offset, final int length) {
		final String hql = getListHQL(t);
		List<T> list = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
						Query query = session.createQuery(hql);
						query.setFirstResult(offset);
						query.setMaxResults(length);
						List<T> list = query.list();
						return list;
					}

					
				});
		return list;
	}
	
	
	
	/**
	 * 子類需要重寫HQL時,可繼承重寫該方法
	 * @param t
	 * @return
	 */
	protected String getListHQL(T t){
		String className = t.getClass().getSimpleName();
		StringBuffer hqlBuffer = new StringBuffer("from " + className + " as t " + (appendJoinHQL(t)==null?"":appendJoinHQL(t)) + " where 1 = 1 ");
		String appender = appendConditionHQL(t);
		if(appender != null){
			hqlBuffer.append(appender);
		}
		if(t instanceof DeletedByLogic){
			hqlBuffer.append(" and t.state != '" + Constants.STATE_DELETED + "'");
		}
		hqlBuffer.append(" order by " + getOrderByHQL()+ " " );
		String hql = hqlBuffer.toString();
		return hql;
	}


統計條數
public int getCount(T t, int offset, int length) {
		String className = t.getClass().getSimpleName();
		StringBuffer hqlBuffer = new StringBuffer("select count(*) from " + className + " as t where 1=1 ");
		String appender = appendConditionHQL(t);
		if(appender != null){
			hqlBuffer.append(appender);
		}
		if(t instanceof DeletedByLogic){
			hqlBuffer.append(" and t.state != '" + Constants.STATE_DELETED + "'");
		}
		final String hql = hqlBuffer.toString();
		Object uniqueResult = createQuery(hql).uniqueResult();
		return Integer.parseInt(uniqueResult.toString());
	
	}


普通的業務處理對象(Service)接口應繼承於com.epro.crm.service.base.CommonServiceInterface<T>,其默認已有增刪改查的接口。其實現類應繼承於com.epro.crm.service.base.CommonBaseService<T>,該類有增刪改查,日誌等功能。

 參考:com.epro.crm.service.system.impl.UserServiceImpl

public PageModel<T> getPageModel(T sample, PageModel<T> pageModel){
		if(sample == null)
			sample = getNewEntity();
		List<T> dataList = getCommonDao().getList(sample, pageModel.getOffset(), pageModel.getPageSize());
		Integer total =  getCommonDao().getCount(sample, pageModel.getOffset(), pageModel.getPageSize());
		pageModel.setDataList(dataList);
		pageModel.setTotalItemNumber(total);
		return pageModel;
	}

分頁模型

頁面上採用pager-taglib 標籤進行分頁頁碼顯示及偏移量計算,由分頁模型對象com.epro.crm.model.util.PageModel<T>接收偏移量offset,頁大小,在DAO層由com.epro.crm.dao.base.CommonBaseDao.getList(T,int, int)方法將分頁查詢的結果放在PageModel對象中,在頁面通過Struts-tag顯示。

public class PageModel<T> {
	/** 
     * 總記錄數 
     */  
    private Integer totalItemNumber;  
    /** 
     * 當前頁結果集 
     */  
    private List<T> dataList;
    
    /** 
     * 偏移量:當前頁第一條記錄,在總記錄數中的序號
     */
    private Integer offset = 0; 
    /**
     * 每頁顯示記錄數
     */
    private Integer pageSize = Configurations.DEFAULT_PAGE_SIZE;
    /**
     * 頁碼
     */
    private Integer pageNumber = null;
    /**
     * 總頁碼
     */
    private Integer totalPageNumber = null;

    /** getters and setters **/
} 


數據字典

數據字典由“數據字典類型”com.epro.crm.model.system.DataDictType以及“數據字典項”com.epro.crm.model.system.DataDictItem組成。

 

在數據庫中添加了數據字典類型,及對應的數據字典項後。在Action層中,通過DataDictTypeService準備數據字典內容。在界面中可通過

<s:select list="allTaskTypes" name="taskType.id" headerKey="" headerValue="請選擇.." listKey="id" listValue="name" value="taskType.id" cssClass="required"></s:select>

的Struts標籤,即可顯示數據字典列表。


系統日誌/操作日誌    

平臺提供兩種日誌方式。

 

系統日誌:系統日誌由log4j記錄,輸出至/crm_log.html文件中。程序中可通過以下方式獲得日誌記錄對象。

 

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


 

操作日誌:操作日誌是由平臺提供用來將用戶的重要操作記錄到數據庫中,以及日誌的顯示模塊。記錄的內容包括操作時間,操作者用戶名,IP,以及操作描述。見com.epro.crm.model.system.Log

 

已經在BaseAction中封裝,所以可以在Action中直接使用logService.log(“”)記錄。

 

參考:

 

public void log(String summary, String description){
       Log log = new Log((User)sessionMap.get(Constants.SESSION_USER),getIpAddr(),
              summary, description);
       logService.add(log);
    }

平臺中的領域對象刪除後的狀態支持兩種模式。

 

邏輯刪除是採用一個標記字段表示該記錄的狀態,如已刪除,則修改標記字段爲刪除狀態,查詢時將其忽略。物理刪除即爲普通delete刪除。

 

採用物理刪除的類中實現com.epro.crm.model.base.DeletedByPhysics接口即可。

採用邏輯刪除的類中實現com.epro.crm.model.base.DeletedByLogic接口即可。

 

CommonBaseDao在刪除和查詢對象時,會根據類所表明的模式,進行判斷。

 

參考:com.epro.crm.model.system.User

 


上傳下載  

Struts 2 的常用方式,有待封裝

見 ResumeAction:111

Json支持

由於使用Struts2 Json plugin 時,response默認content type爲”text/json”,部分瀏覽器對該格式解析不正確,產生下載頁面。

所以本平臺採用另外一種手動設置的方式

	   this.getResponse().setContentType("text/html");
           this.getResponse().setCharacterEncoding("GBK");
           PrintWriter out = this.getResponse().getWriter();
           ajaxResult = "{error: '簡歷上傳成功!但無法提取信息,請手動填寫表單!',msg:'',filename:'"+ resumeFileFileName + "',filepath : ' " + targetDirectory+ "/" + targetFileName + " '}";
           out.write(ajaxResult);
           out.flush();

見 ResumeAction:111




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章