GoFramework框架開發指南


服務層規范

java文件分類

文件類型 說明
枚舉 目前枚舉多由工具生成,如果需要進行數據庫操作,則需要實現org.go.api.core.enums.BaseEnum接口
dto 目前同時做為請求及響應參數,與數據模型關聯密切
request 對應渠道側的頁面級請求,當dto模型不能滿足頁面請求時,需要新增request類型
response 對應接口的最終返回結果,該類型代表接口的最終結果,一般不能做為集合中的元素返回。
item 對應集合中的元素,當dto模型不能直接做元素使用時,可以使用通過定義item類型來解決
facade 分為直接操作數據庫的簡單服務,以及進行服務組合或復雜運算的高級服務。高級服務需要在名稱中增加Prof關鍵字來區分。
bo 對應數據庫表或視圖的實體,在mybatis中做為請求或響應參數來使用。目前要求除非數據返回的是基礎類型如Integer,Long,String等,則必須使用bo類來承載返回結果。
dto 定義mybatis接口及xml文件
facade實現類 含義如同其名。

錯誤碼:
1、錯誤碼存放在ResCode類中,由一位字母加四位數字組成,系統的不同模塊錯誤碼可以定義不同的錯誤碼前綴。
2、接口全局錯誤碼,針對錯誤碼配置太繁瑣的問題,將一個接口定義成一個錯誤碼,並結合1.0.1+的注解進行使用,暫定類名稱為R。如下:

public class R {

    public static final String gridInfoProfFacade = "R0101";// 網格點高級服務
    public static final String unitInfoProfFacade = "R0102";// 單位高級服務
    public static final String generatePdfFacade = "R0103";// 單位高級服務
    public static final String unitDeviceProfFacade = "R0104";// 單位設備高級服務
    ....
}

3、要求每個接口都需要指定錯誤碼及信息(可以共用)。為了避免拋出未知異常,接口中必須要做異常處理。如下:

   @Override
    public List<FormElement> getFormElementList(FormElementListGetRequest request) throws PendingException {
        try {
            // 對請求參數進行校驗
            AbstractBaseRequestDto.validateThrow(request);
            // 查詢緩存用戶信息
            User user = userCache.get(request.getUserId());
            // 查詢表單元素列表
            ....
            return formElementList;
        } catch (Exception ex) {
            // 對異常進行處理
            throw transferException(ex, ResCode.formElementListGetFailed);
        }
    }
	    

如果使用1.0.1框架及以上,也可以使用注解方式,減少代碼量

    @Override
    @RpcMethod("部門下的文書及風險項選項列表查詢")
    public List<FormElementOptionItem> queryDeptDocRiskOptionList(DepartmentIdRequest request) throws PendingException {
        // 對請求參數進行校驗
        validateThrow(request);
        // 從緩存中進行查詢
        return deptDocRiskOptionCache.get(request.getDepartmentId());
    }

上述前提需要給接口所在服務類配置全局錯誤碼,如下

@Service(version = "1.0.0")
@RpcClass(R.departmentInfoProfFacade)
public class DepartmentInfoProfFacadeImpl extends AbstractDubboIntegrationService implements DepartmentInfoProfFacade {
    ....
}

數據庫自定義查詢開發流程

結構組成:
request類:數據庫查詢時所需要的請求參數類。但如果請求參數只有一個基礎類型,或者能找到合適的dto模型,則可以省掉本類。

bo類:數據庫查詢結果的映射類型,如果返回結果是基礎類型如Integer|String等,則可以省略。

dto類:最終接口返回的數據模型,與bo類對應。注:本處bo和dto僅做返回結果的映射,請求則交給request類。

dao接口及xml:mybatis的必要組件

facade及實現類:看情況決定使用現有類型還是新增

開發過程

(1)編寫request類。可使用Dto工具生成校驗部分的代表,如下圖:

(2)編寫bo類,與數據庫查詢返回結果對應。
(3)利用bo類生成dto類及mybatis map的代碼片斷。如下圖:

(4)在dao的xml文件中寫查詢塊。請求參數直接使用request類,響應參數使用bo類的Map。
(5)使用工具生成dao接口、facade及實現類的方法內容並復制回相應類。如下圖:

事務開發流程

需要使用到newTransactionTemplate模板類。
(1)1.0.0版本寫法

    @Override
    public void saveInspectRecord(InspectRecordSaveRequest request) throws PendingException {
        try {
           ....

            // 事務處理
            newTransactionTemplate.execute(status -> {
                try {

                    ....

                    return inspectRecord;
                } catch (Exception ex) {
                    // 對數據庫事務進行回滾
                    status.setRollbackOnly();
                    // 對異常進行處理
                    throw new GoRuntimeException(transferException(ex, ResCode.inspectRecordSaveFailed));
                }
            });
        } catch (Exception ex) {
            // 對異常進行處理
            throw transferException(ex, ResCode.inspectRecordSaveFailed);
        }
    }

(2)1.0.1+版本寫法,去掉了最外層的try catch,及不需要單獨定義錯誤碼

    @Override
    @RpcMethod("新增單位信息")
    public void addUnit(UnitAddRequest unitAddRequest) throws PendingException {
        
        ...

        newTransactionTemplate.execute(
                status -> {
                    try {

                        ....

                        return true;
                    } catch (Exception ex) {
                        // 事務回滾
                        status.setRollbackOnly();
                        // 轉換成運行時異常
                        throw toRuntime(ex);
                    }
                }
        );

web端接口開發流程

前提:在1.0.0及以上版本框架中,web端可以做SPI實現,並實現請求參數的部分會話字段自動注入及校驗的功能。如下:

package com.yc.clouds.web.spi;

import com.google.gson.Gson;
import com.yc.clouds.api.business.constants.QUser;
import com.yc.clouds.api.core.constants.ResCode;
import com.yc.clouds.web.bean.session.SessionUser;
import com.yc.clouds.web.constants.SessionKey;
import org.go.framework.core.exception.PendingException;
import org.go.framework.web.aop.spi.IInjectFieldFetcher;

import javax.servlet.http.HttpServletRequest;

/**
 * MVC字段注入的Fetcher實現類
 */
public class InjectFieldFetcherImpl implements IInjectFieldFetcher {

    @Override
    public Object getValue(HttpServletRequest request, String fieldName) throws PendingException {
        // 獲取會話用戶信息
        SessionUser sessionUser = getSessionUser(request);
        // 如果會話用戶不存在
        if(sessionUser == null){
            throw ResCode.SESSION_AUTH_FAILED.toException();
        }
        // 根據屬性名字進行注入
        switch (fieldName) {
            case QUser.appId:
                return sessionUser.getAppId();
            case QUser.userId:
                return sessionUser.getUserId();
            case QUser.realName:
                return sessionUser.getRealName();
            case QUser.phone:
                return sessionUser.getPhone();
            case QUser.roleType:
                return sessionUser.getRoleType();
            case QUser.privilegeType:
                return sessionUser.getPrivilegeType();
            default:
                throw ResCode.injectFieldInvalid.toException();
        }
    }

    /**
     * 獲取用戶會話信息
     * @param request
     * @return
     */
    private SessionUser getSessionUser(HttpServletRequest request) {
        String jsonStr = (String) request.getSession().getAttribute(SessionKey.SESSION_KEY);
        return jsonStr == null ? null : new Gson().fromJson(jsonStr, SessionUser.class);
    }
}

(1)在controller類的mvc方法中,盡量使用request類型做請求參數,可以寫參數校驗邏輯,以及對參數字段做各種注解標識。應避免直接使用工具生成的dto類。

public class BackstageUnitPageRequest extends AbstractBasePageRequestDto {

    /**
     * 應用id
     */
    @MvcInject
    private Long appId;

    /**
     * 一級網格點Id
     */
    @MvcOptional
    private Long gridId;

    /**
     * 單位整體資質情況
     */
    @MvcIgnore
    private UnitQualificationStatus unitQualificationStatus;

    ....
}

mvc字段注解說明:

MvcInject:字段值自動注入,可以指定會話對象的字段名,如不指定就使用屬性名進行匹配。當字段使用該注解后,接口文檔中將忽視該字段。

MvcOptional:標記字段為可選,在生成接口文檔時會增加可選標記。

MvcIgnore:說明該字段並非由接口傳遞值,而是后期通過運算生成。接口文檔中會忽視該字段。

(2)若需要使用上述注解的自動注入功能。需要在controller的mvc方法中增加org.go.framework.base.annotation.MvcValidate注解。如

    @RequestMapping(value = "/registerValidate.do", method = RequestMethod.POST)
    @MvcValidate
    public ResDto<?> registerValidate(HttpServletRequest request, @RequestBody RegisterValidateRequest registerValidateRequest) throws PendingException {
        ....
        return new ResDto<>();
    }

其它SPI實現:會話注入

package com.yc.clouds.web.spi;

import com.yc.clouds.web.constants.SessionKey;
import org.go.framework.web.interceptor.spi.ISessionUserInjector;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 會話用戶注入的實現
 * @author 素閑人
 *
 */
public class SessionUserInjectorImpl implements ISessionUserInjector {

	@Override
	public String getSessionUserJson(HttpServletRequest request) {
		return  (String) getHttpRequest().getSession().getAttribute(SessionKey.SESSION_KEY);
	}
	
	private HttpServletRequest getHttpRequest() {
		return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	}

}

實現該SPI方法,可以在dubbo調用時,把會話信息通過dubbo的上下文傳遞到服務側。即使接口中沒有用戶參數,也可以通過上下文獲得。如下面工具類:

package com.yc.clouds.api.business.utils;

import com.google.gson.Gson;
import com.yc.clouds.api.business.bean.session.RpcSessionUser;
import com.yc.clouds.api.core.constants.ResCode;
import org.go.framework.core.Context;
import org.go.framework.core.exception.GoRuntimeException;

/**
 * 會話用戶信息上下文
 *
 * @author 素閑人
 */
public class SessionUserContext {

    /**
     * 獲取會話用戶信息
     *
     * @return
     */
    public static RpcSessionUser get() {
        // 從context中獲取會話信息的json字符串
        RpcSessionUser rpcSessionUser = new Gson().fromJson(Context.getRequestInfo().getSessionUser(), RpcSessionUser.class);
        // 若用戶會話信息不存在則拋出異常
        if (Context.getRequestInfo().getSessionUser() == null) {
            throw new GoRuntimeException(ResCode.RPC_SESSION_GET_FAILED.toException());
        }
        return rpcSessionUser;
    }

}

在適當的接口中可以使用上述工具類來獲取會話用戶信息:

    @Override
    @RpcMethod("APP單位首頁信息查詢")
    public UnitAppHomePageResponse getAppHomePageData(UnitIdRequest unitIdRequest) throws PendingException {
        // 對請求參數進行校驗
        validateThrow(unitIdRequest);
        // 查詢單位緩存信息
        UnitCacheItem unitCacheItem = unitItemCache.get(unitIdRequest.getUnitId());
        // 獲取會話用戶信息
        RpcSessionUser sessionUser = SessionUserContext.get();
      
        ....        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM