日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

Version:0.9 Starthtml:0000000105 EndHTML:0000064633 StartFragment:0000000141 EndFragment:0000064597

 

本文梳理了在搭建開發(fā)框架時的一些考量及具體的處理方法。

 

框架搭建目標

  • 整體代碼規(guī)范化
  • 重復(fù)代碼自動化
  • 復(fù)雜關(guān)系精簡化
  • 公共代碼統(tǒng)一化

盡量保證開發(fā)人員的核心關(guān)注點在業(yè)務(wù)邏輯。

盡量避免非業(yè)務(wù)問題影響開發(fā)進度。

整體代碼規(guī)范化

規(guī)范的作用不是為了規(guī)范而規(guī)范,也不是對不按規(guī)范的人做出懲罰。是為了方便溝通

  • 方便新員工能根據(jù)規(guī)范文檔快速熟悉代碼結(jié)構(gòu)
  • 方便接手其他人的代碼時,只需要了解業(yè)務(wù)就可以
  • 方便和其他人溝通時,不需要關(guān)注業(yè)務(wù)之外的內(nèi)容

可以從下面幾個方面做出規(guī)范:

  • 統(tǒng)一格式化
    • 一種方案是使用相同的IDE,一種方案是使用相同的格式化配置
    • 保證在代碼合并或代碼review時,不會因為代碼格式化問題導(dǎo)致沖突或難以對比
  • 統(tǒng)一三方庫的使用
    • 統(tǒng)一使用一種功能的庫,比如:持久化框架選定了Mybatis就不要再用Hibernate,安全框架選定了SpringSecurity就不要使用Shiro
    • 這會增加團隊成員的學(xué)習(xí)成本,以及后續(xù)的維護成本
  • 統(tǒng)一代碼風(fēng)格
    • 命名方式的統(tǒng)一:命名實際上是個很重要但是一直不被重視的工作。好的命名能極大的降低溝通成本。至少要保證包層級的名稱的語義。我接觸的項目里,對DTO來說,有的項目里叫PO,有的叫VO,導(dǎo)致一個開發(fā)人員接收另一個項目時,理解上就有了難度。
    • 職責區(qū)分:SRP是一個看起來簡單,但是很難做好的設(shè)計原則。比如:還是拿DTO來說,有的項目直接會直接將Entity作為DTO來使用,可以避免DTO與Entity直接的數(shù)據(jù)字段處理。實際上這里的DTO即做了DTO的工作,又做了Entity的工作。邏輯簡單時是比較爽,但是因為兩個對象的職責不一樣,進化頻率也不一樣。當DTO字段調(diào)整時,就會對后面的DAO操作產(chǎn)生影響。
    • RESTful規(guī)范化:現(xiàn)在大部分的項目都會使用RESTful。如果使用了RESTful,那就按照RESTful的規(guī)范來。盡量提高代碼語義,不要使用個四不像。比如:就使用POST和GET。
    • 非業(yè)務(wù)字段獨立:業(yè)務(wù)相關(guān)對象和非業(yè)務(wù)相關(guān)對象區(qū)分開。例如:對于查詢來說,可能需要進行分頁。對于分頁控制字段建議整合為PageInfo對象來統(tǒng)一處理,而不要作為獨立的字段加到DTO對象里。一是不方便管理,二是將不同場景的字段混合到了一起,不易于區(qū)分。
    • 接口攜帶版本號:接口攜帶版本號,可以基于版本來進行平滑升級。例如:可以保留/api/user/v1/login,同時發(fā)布/api/user/v2/login,待/api/user/v1/login不再使用后,在刪除/api/user/v1/login
  • 代碼架構(gòu)匹配
    • 架構(gòu)設(shè)計時,實際觸及到的是系統(tǒng)、子系統(tǒng)、層級、模塊;而具體到代碼,只體現(xiàn)了系統(tǒng)(一個個的服務(wù))和層級(Controller,Service,DAL)。模塊的映射關(guān)系消失了
    • 為了提高代碼與架構(gòu)的匹配度,降低溝通成本。可以在代碼層面通過添加一層包的方式,來映射模塊關(guān)系。
  • 接口與實現(xiàn)的層級關(guān)系(推薦)
    • 傳統(tǒng)MVC框架是按照Controller、Service和DAO的方式來分層的。如果有接口,一般情況下接口定義與實現(xiàn)是在同一層的,比如Service和ServiceImpl,都在Service層。實際上此種結(jié)構(gòu)是有問題的。
    • 假設(shè)現(xiàn)在有兩套Service的實現(xiàn),代碼在項目中如何存儲?
    • 實際上Service和ServiceImpl分屬不同的層,Service是接口層,ServiceImpl是實現(xiàn)層(雖然可能感覺不符合常識,不過確實如此)。兩套ServiceImpl對應(yīng)到Maven項目中,就是兩個模塊。當要替換實現(xiàn)時,通過Maven的項目結(jié)構(gòu)調(diào)整依賴即可。

重復(fù)代碼自動化

在代碼規(guī)范化的前提下,基于代碼生成工具(比如IDEA的EasyCode)構(gòu)建一套完整的代碼模板,基于代碼模板快速的生成對應(yīng)的代碼。提高開發(fā)效率。

對于庫表結(jié)構(gòu)調(diào)整后對代碼的影響,可以基于代碼結(jié)構(gòu)的調(diào)整來盡量減少對現(xiàn)有代碼的影響。假設(shè)使用Mybatis作為持久化框架,有三個方案:

  • 基于MybatisPlus(其實就是接口繼承,具體參考MybatisPlus文檔)
  • 基于MybatisProvider
  • 基于MApper接口繼承

基于MybatisProvider

  • 自動生成Mapper和Provider,Mapper不使用XML,而使用注解的方式來使用SQL
  • Provider中的方法對參數(shù)進行反射來處理字段信息,構(gòu)建對應(yīng)的sql
  • 當表結(jié)構(gòu)調(diào)整后,只需要調(diào)整對應(yīng)的Bean的字段即可

// Mapper

@SelectProvider(type = IssueProvider.class, method = "list")

Page<IssueVO> list(IssueVO issue);

// Provider

// Issue是對應(yīng)的Bean,字段調(diào)整后,在Issue中添加對應(yīng)的字段即可(可以生成,可以手動添加)

public String list(Issue issue) {

SQL sql = new SQL();

sql.SELECT("*");

sql.FROM("issue");

BeanMap beanMap = BeanMap.create(issue);

for (Object key : beanMap.keySet()) {

Object val = beanMap.get(key);

if (val != null) {

if (val instanceof String && ((String) val).contains("%")) {

sql.WHERE("`" + FieldUtils.camelToLine(key + "") + "`" + "like #{" + key + "}");

} else {

sql.WHERE("`" + FieldUtils.camelToLine(key + "") + "`" + "=#{" + key + "}");

}

}

}

return sql.toString();

}

  • 優(yōu)勢:
    • 改動量比較小
  • 劣勢:
    • 反射對性能的影響
    • 基于注解的方式,習(xí)慣性問題
    • IDEA對Provider的方式的支持沒有XML高,XML支持自動完成,Provider中不支持

基于Mapper接口繼承

  • Mybatis生成的Mapper和XML文件分別為獨立的目錄
  • 自定義的Mapper繼承生成的Mapper,在自定義Mapper中新增自定義接口方法,對應(yīng)的sql添加到對應(yīng)的自定義XML文件中
  • 自定義XML文件可以基于NameSpace來使用生成的XML文件的Result
  • 當表結(jié)構(gòu)調(diào)整后,重新生成對應(yīng)的Mapper和XML即可
  • 優(yōu)勢:
    • 符合習(xí)慣
  • 劣勢:
    • 改動量相對多一點,不過是生成的,所以基本可以忽略

復(fù)雜關(guān)系精簡化

一般項目中的庫表設(shè)計基本都是按照關(guān)聯(lián)表的方式進行設(shè)計的:

  • 主表+子表的關(guān)聯(lián)關(guān)系
  • 表中冗余其它表的字段

可以結(jié)合場景考慮,做一些結(jié)構(gòu)簡化和結(jié)構(gòu)化。簡化為對單表的操作,可以基于上面的模板來自動生成代碼。

主表+子表的關(guān)聯(lián)關(guān)系

此種方式適用于主表和子表需要單獨修改的場景。如果主表和子表是聚合關(guān)系,即子表依賴于主表存在,且需要一起調(diào)整,甚至子表不需要調(diào)整,實際可以簡化此種關(guān)聯(lián)關(guān)系。

因為此種關(guān)聯(lián)關(guān)系涉及到了聯(lián)表查詢,聯(lián)表查詢是無法基于工具生成的。通過簡化此種關(guān)系,可以基于工具來提高開發(fā)效率。

表中冗余其它表的字段

有些情況下,可能會將兩個邏輯上分離的對象整合為一個對象來處理,簡化操作負責度。例如訂單中可能直接就包含購買的應(yīng)用信息。此種情況實際是為了操作的便利性,同時兼顧數(shù)據(jù)庫特性,將結(jié)構(gòu)化的數(shù)據(jù)扁平化了。

數(shù)據(jù)扁平化本身問題不大,不過弱化了代碼語義。在正常理解里,訂單包含訂單明細,訂單明細中是商品信息。

可以通過下面的方法來解決上面提到的兩個問題。

解決方案

MySQL5.7開始支持Json。上述兩種情況,都可以基于Json的方式來處理。即數(shù)據(jù)庫字段可以使用json類型。

// 支持基于json的查詢,請自行g(shù)oogle

create table order

(

......

item_info_json json not null comment 'json',

);

public class Order {

private ItemInfo itemInfoJson;

}

在Mybatis層面,通過TypeHandler來處理Json與對象之間的自動轉(zhuǎn)換。

public interface OrderDao {

// 配置轉(zhuǎn)換handler

@Results(id = "jsonResult", value = {

@Result(property = "itemInfoJson", column = "item_info_json", typeHandler = JsonTypeHandler.class)

})

@Select("select * from order where rec_id = #{recId}")

Order selectByPrimaryKey(@Param("recId") String recId);

@InsertProvider(type = OrderProvider.class, method = "insert")

void insert(Order model);

 

......

}

 

public class OrderProvider {

public String insert(Order order) {

SQL sql = new SQL();

sql.INSERT_INTO("order");

BeanMap beanMap = BeanMap.create(order);

for (Object key : beanMap.keySet()) {

Object val = beanMap.get(key);

if (val != null) {

if ((key + "").endsWith("Json")) { // 根據(jù)后綴判定是否需要轉(zhuǎn)換

sql.VALUES("`" + FieldUtils.camelToLine(key + "") + "`", "#{" + key + ", typeHandler=com.iwhalecloud.common.mybatis.JsonTypeHandler}");

} else {

sql.VALUES("`" + FieldUtils.camelToLine(key + "") + "`", "#{" + key + "}");

}

}

}

return sql.toString();

}

轉(zhuǎn)換類處理邏輯:

public class JsonTypeHandler<T> extends BaseTypeHandler<T> {

private static final Gson gson = new Gson();

private Class<T> clazz;

public JsonTypeHandler(Class<T> clazz) {

if (clazz == null) {

throw new IllegalArgumentException("Type argument cannot be null");

} else {

this.clazz = clazz;

}

}

public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {

ps.setString(i, this.toJson(parameter));

}

public T getNullableResult(ResultSet rs, String columnName) throws SQLException {

return this.toObject(rs.getString(columnName), this.clazz);

}

public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {

return this.toObject(rs.getString(columnIndex), this.clazz);

}

public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {

return this.toObject(cs.getString(columnIndex), this.clazz);

}

private String toJson(T object) {

try {

return object instanceof String ? (String)object : gson.toJson(object);

} catch (Exception var3) {

throw new RuntimeException(var3);

}

}

private T toObject(String content, Class<?> clazz) {

if (content != null && !content.isEmpty()) {

try {

return clazz == String.class ? content : gson.fromJson(content, clazz);

} catch (Exception var4) {

throw new RuntimeException(var4);

}

} else {

return null;

}

}

}

公共代碼統(tǒng)一化

對于多個項目中使用到的代碼,需要根據(jù)場景進行公共化統(tǒng)一管理,避免公共代碼散落在各個服務(wù)中,難以維護。

根據(jù)場景的不同,可以有幾種管理方式:

  • 基于公共jar包的管理
  • 基于git源代碼的管理
  • 基于公共服務(wù)的管理

基于公共jar包的管理

此方案是最常規(guī)的方案,如果幾個服務(wù)中使用到了公共的代碼,比如:一些工具類。這種情況下就可以將這些類獨立為公共項目,通過jar包的方式來進行管理。

基于git源代碼的管理

如果公共的代碼修改頻率比較高,可以基于git的subtree來處理公共代碼的管理問題。

  • 創(chuàng)建一個項目,用于存放需要公用的代碼,正常創(chuàng)建即可
  • 在需要使用同步代碼的項目中執(zhí)行如下命令(只需要執(zhí)行一次):

# module是取的別名

git remote add -f module ${上面的項目git地址}

# 將這個項目拉取到 src/module目錄下

git subtree add --prefix=src/module module master --squash

  • 在公共項目中修改模塊代碼后,正常push即可
  • 需要同步的項目,執(zhí)行如下命令(如果需要同步共享代碼,則執(zhí)行):

git subtree pull --prefix=src/module module master

開發(fā)框架搭建考量

 

基于公共服務(wù)的管理

如果公用的邏輯是一個獨立的功能,后續(xù)可以作為服務(wù)對外提供服務(wù)。那可以考慮將這些代碼獨立為服務(wù)來對外提供服務(wù)。

總結(jié)

本文從幾個維度來考量在搭建一個項目框架時需要考慮的問題,以及對應(yīng)的解決方案。

分享到:
標簽:框架 開發(fā)
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定