Topfox 1.2.4 發布,快速開發框架

←手機掃碼閱讀     admin @ 2019-07-25 , reply:0

1. 用戶使用手冊 - 目錄

1.1. 必備

1.2. topfox 介紹

在 srpingboot2.x.x 和MyBatis 的基礎上只做增強不做改變,為簡化開發、提高效率而生。

編程規範參考《阿里巴巴Java開發手冊》

借鑒mybaties plus部分思想

特性:

  • 無侵入:只做增強不做改變,引入它不會對現有工程產生影響

  • 損耗小:啟動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作

  • 集成Redis緩存: 自帶Redis緩存功能, 支持多主鍵模式, 自定義redis-key. 實現對資料庫的所有操作, 自動更新到Redis, 而不需要你自己寫任何代碼; 當然也可以針對某個表關閉.

  • 強大的 CRUD 操作:內置通用 Mapper、通用 Service,僅僅通過少量配置即可實現單表大部分 CRUD 操作,更有強大的條件構造器,滿足各類使用需求

  • 支持 Lambda 形式調用:通過 Lambda 表達式,方便的編寫各類查詢條件,無需再擔心欄位寫錯

  • 支持主鍵自動生成:可自由配置,充分利用Redis提高性能, 完美解決主鍵問題. 支持多主鍵查詢、修改等

  • 內置分頁實現:基於 MyBatis 物理分頁,開發者無需關心具體操作,寫分頁等同於普通查詢

  • 支持devtools/jrebel熱部署

  • 熱載入 支持在不使用devtools/jrebel的情況下, 熱載入 mybatis的mapper文件

  • 內置全局、局部攔截插件:提供delete、update 自定義攔截功能

  • 擁有預防Sql注入攻擊功能

  • 無縫支持spring cloud: 後續提供分散式調用的例子

2. 更新日誌

2.1. 版本1.2.4 更新日誌 2019-07-24

  • 全局緩存參數開關


新增 一級緩存開關 top.service.thread-cache

新增 二級緩存開關 top.service.redis-cache

刪除 top.service.open-redis

  • 多主鍵的支持, 包括: 更新, 刪除, 查詢, 數據校驗組件, 修改日誌組件;

  • java遠程調用返回空對象的處理;

  • 技術文檔修改

3. 快速入門

3.1. 入門例子: 以用戶表為例, 開發者只需要完成以下4步的代碼, 就能實現很多複雜的功能

3.1.1. 新建實體對象 UserDTO



@Setter

@Getter

@Accessors(chain = true)

@Table(name = "users", cnName = "用戶表")

public class UserDTO extends DataDTO {

@Id private Integer id;

private String code;

private String name;

private String password;

private String sex;

private Integer age;

...等

}


3.1.2. 新建查詢條件對象Query( 即UserQTO )



@Setter

@Getter

@Accessors(chain = true)

@Table(name = "users")

public class UserQTO extends DataQTO {

private String id;

private String code;

private String name;

private String nameOrEq;

private String sex;

private Date lastDateFrom;

private Date lastDateTo;

}


3.1.3. 新建UserDao



@Component

public interface UserDao extends BaseMapper<UserDTO> {

/**

* 自定方法 mapper.xml 代碼略

* @param qto

* @return

*/

UserDTO test(UserQTO qto);

}


3.1.4. 新建 UserService



@Service

public class userService extends SimpleService<UserDao, UserDTO> {

@Override

public int insert(UserDTO dto) {

return super.insert(dto);

}



@Override

public int update(UserDTO dto) {

return super.update(dto);

}



@Override

public int deleteByIds(Number... ids) {

return super.deleteByIds(ids);

}



@Override

public int deleteByIds(String... ids) {

return super.deleteByIds(ids);

}

//以上4個方法的代碼可以刪除, 沒什麼邏輯, 這裡只是告訴讀者有這些方法, 但父類的方法遠遠不止這4個



/**

* 自定的方法

* @param qto

* @return

*/

public List<userDTO> test(UserQTO qto) {

return baseMapper.test(qto);

}

}


實現哪些具體的功能呢, 詳見後面的章節

3.2. 功能強大的查詢

3.2.1. 條件匹配器Condition 查詢一

以下僅僅是條件匹配器的部分功能, 更多功能等待用戶挖掘.



@RestController

@RequestMapping("/condition")

public class ConditionController {

@Autowired

UserService userService;



/**

* 條件匹配器的一個例子

*/

@GetMapping("/query1")

public List<UserDTO> query1(){

//**查詢 返回對象 */

List<UserDTO> listUsers = userService.listObjects(

Condition.create() //創建條件匹配器對象

.between("age",10,20) //生成 age BETWEEN 10 AND 20

.eq("sex","男") //生成 AND(sex = '男')

.eq("name","C","D","E")//生成 AND(name = 'C' OR name = 'D' OR name = 'E')

.like("name","A", "B") //生成 AND(name LIKE '%A%' OR name LIKE '%B%')

//不等

.ne("name","張三","李四")



//等同於 .eq("substring(name,2)","平")

.add("substring(name,2)='平' ")//自定義條件



.le("loginCount",1)//小於等於

.lt("loginCount",2)//小於

.ge("loginCount",4)//大於等於

.gt("loginCount",3)//大於



.isNull("name")

.isNotNull("name")

);

return listUsers;

}



}


生成的WHERE條件如下:



SELECT id,code,name,password,sex,age,amount,mobile,isAdmin,loginCount,lastDate,deptId,createUser,updateUser

FROM users a

WHERE age BETWEEN 10 AND 20

AND (sex = '男')

AND (name = 'C' OR name = 'D' OR name = 'E')

AND (name LIKE '%A%' OR name LIKE '%B%')

AND (name <> '張三' AND name <> '李四')

AND substring(name,2)='平'

AND (loginCount <= 1)

AND (loginCount < 2)

AND (loginCount >= 4)

AND (loginCount > 3)

AND name is null

AND name is not null

LIMIT 0,6666


3.2.2. 條件匹配器Condition 查詢二



@RestController

@RequestMapping("/condition")

public class ConditionController {

@Autowired

UserService userService;

@GetMapping("/query2")

public List<UserDTO> query2(){

//**查詢 返回對象 */

List<UserDTO> listUsers = userService.listObjects(

userService.where() // 等同於 Condition.create() 創建一個條件匹配器對象

.eq("concat(name,id)","A1") //生成 (concat(name,id) = 'A1')

.eq("concat(name,id)","C1","D2","E3")//生成 AND (concat(name,id) = 'C1' OR concat(name,id) = 'D2' OR concat(name,id) = 'E3' )

);

return listUsers;

}

}


生成的WHERE條件如下:



SELECT id,code,name,password,sex,age,amount,mobile,isAdmin,loginCount,lastDate,deptId,createUser,updateUser

FROM users a

WHERE (concat(name,id) = 'A1')

AND (concat(name,id) = 'C1'

OR concat(name,id) = 'D2'

OR concat(name,id) = 'E3' )


3.3. 高級查詢 帶分組, 排序, 自定select 后欄位, 指定分頁的查詢

利用查詢構造器 EntitySelect 和 Condition的查詢

實體查詢構造器



/**

* 核心使用 繼承了 topfox 的SimpleService

*/

@Service

public class CoreService extends SimpleService<UserDao, UserDTO> {

public List<UserDTO> demo2(){

List<UserDTO> listUsers=listObjects(

select("name, count('*')") //通過調用SimpleService.select() 獲得或創建一個新的 EntitySelect 對象,並返回它

.where() //等同於 Condition.create()

.eq("sex","男") //條件匹配器自定義條件 返回對象 Condition

.endWhere() //條件結束 返回對象 EntitySelect

.orderBy("name") //設置排序的欄位 返回對象 EntitySelect

.groupBy("name") //設置分組的欄位 返回對象 EntitySelect

.setPage(10,5) //設置分頁(查詢第10頁, 每頁返回5條記錄)



);

return listUsers;

}

}


輸出sql如下:



SELECT name, count('*')

FROM users a

WHERE (sex = '男')

GROUP BY name

ORDER BY name

LIMIT 45,5


3.4. 查詢時如何才能不讀取緩存

TopFox 實現了緩存處理, 當前線程的緩存 為一級緩存, redis為二級緩存.

通過設置 readCache 為false, 能實現在開啟一級/二級緩存的情況下又不讀取緩存, 從而保證讀取出來的數據和資料庫中的一模一樣, 下面通過5個例子來說明.





@RestController

@RequestMapping("/demo")

public class DemoController {

@Autowired

UserService userService;



@TokenOff

@GetMapping("/test1")

public Object test1(UserQTO userQTO) {

//例1: 根據id查詢, 通過第2個參數傳false 就不讀取一二級緩存了

UserDTO user = userService.getObject(1, false);



//例2: 根據多個id查詢, 要查詢的id放入Set容器中

Set setIds = new HashSet();

setIds.add(1);

setIds.add(2);

//通過第2個參數傳false 就不讀取一二級緩存了

List<UserDTO> list = userService.listObjects(setIds, false);



//例3: 通過QTO 設置不讀取緩存

list = userService.listObjects(

userQTO.readCache(false) //禁用從緩存讀取(注意不是讀寫) readCache 設置為 false, 返回自己(QTO)

);

//或者寫成:

userQTO.readCache(false);

list = userService.listObjects(userQTO);



//例4: 通過條件匹配器Condition 設置不讀取緩存

list = userService.listObjects(

Condition.create() //創建條件匹配器

.readCache(false) //禁用從緩存讀取

);



return list;

}

}


3.5. 查詢 緩存開關 thread-cache redis-cache與readCache區別

請讀者先閱讀 章節 《TopFox配置參數》



一級緩存 top.service.thread-cache 大於 readCache

二級緩存 top.service.redis-cache 大於 readCache


也就說, 把一級二級緩存關閉了, readCache設置為true, 也不會讀取緩存. 所有方式的查詢也不會讀取緩存.

3.6. 查詢 一級緩存的效果

  • 一級緩存默認是關閉的

只打開某個 service的操作的一級緩存



@Service

public class UserService extends AdvancedService<UserDao, UserDTO> {

@Override

public void init() {

sysConfig.setThreadCache(true); //打開一級緩存

}


全局開啟一級緩存, 項目配置文件 application.properties 增加



top.service.thread-cache=true

  • 開啟一級緩存后
  1. 一級緩存是只當前線程級別的, 線程結束則緩存消失

  2. 下面的例子, 在開啟一級緩后 user1,user2和user3是一個實例的

  3. 一級緩存的效果我們借鑒了Hibernate框架的數據實體對象持久化的思想



@RestController

@RequestMapping("/demo")

public class DemoController {

@Autowired

UserService userService;



@TokenOff

@GetMapping("/test2")

public UserDTO test2() {

UserDTO user1 = userService.getObject(1);//查詢后 會放入一級 二級緩存

UserDTO user2 = userService.getObject(1);//會從一級緩存中獲取到

userService.update(user2.setName("張三"));

UserDTO user3 = userService.getObject(1);//會從一級緩存中獲取到

return user3;

}

}


3.7. QTO後綴增強查詢

我們修改 UserQTO 的源碼如下:



@Setter

@Getter

@Table(name = "users")

public class UserQTO extends DataQTO {

private String id; //用戶id, 與數據欄位名一樣的



private String name; //用戶姓名name, 與數據欄位名一樣的

private String nameOrEq; //用戶姓名 後綴OrEq

private String nameAndNe; //用戶姓名 後綴AndNe

private String nameOrLike; //用戶姓名 後綴OrLike

private String nameAndNotLike;//用戶姓名 後綴AndNotLike

...

}

  • 欄位名 後綴OrEq

當 nameOrEq 寫值為 "張三,李四" 時, 源碼如下:



package com.test.service;



/**

* 核心使用 demo1 源碼 集成了 TopFox 的 SimpleService類

*/

@Service

public class CoreService extends SimpleService<UserDao, UserDTO> {

public List<UserDTO> demo1(){

UserQTO userQTO = new UserQTO();

userQTO.setNameOrEq("張三,李四");//這裡賦值

//依據QTO查詢 listObjects會自動生成SQL, 不用配置 xxxMapper.xml

List<UserDTO> listUsers = listObjects(userQTO);

return listUsers;

}

}


則生成SQL:



SELECT ...

FROM SecUser

WHERE (name = '張三' OR name = '李四')

  • 欄位名 後綴AndNe

當 nameAndNe 寫值為 "張三,李四" 時, 則生成SQL:



SELECT ...

FROM SecUser

WHERE (name <> '張三' AND name <> '李四')

  • 欄位名 後綴OrLike

當 nameOrLike 寫值為 "張三,李四" 時, 則將生成SQL:



SELECT ...

FROM SecUser

WHERE (name LIKE CONCAT('%','張三','%') OR name LIKE CONCAT('%','李四','%'))

  • 欄位名 後綴AndNotLike

當 nameAndNotLike 寫值為 "張三,李四" 時, 則生成SQL:



SELECT ...

FROM SecUser

WHERE (name NOT LIKE CONCAT('%','張三','%') AND name NOT LIKE CONCAT('%','李四','%'))


以上例子是TopFox全自動生成的SQL

3.8. 更多的查詢方法

  • Response< List < DTO > > listPage(EntitySelect entitySelect)

  • List< Map < String, Object > > selectMaps(DataQTO qto)

  • List< Map < String, Object > > selectMaps(Condition where)

  • List< Map < String, Object > > selectMaps(EntitySelect entitySelect)

  • selectCount(Condition where)

  • selectMax(String fieldName, Condition where)

  • 等等

3.9. 自定條件更新 updateBatch

  • @param xxxDTO 要更新的數據, 不為空的欄位才會更新. Id欄位不能傳值

  • @param where 條件匹配器

  • @return List< DTO >更新的dto集合



@Service

public class UnitTestService {

@Autowired UserService userService;



public void test(){

UserDTO dto = new UserDTO();

dto.setAge(99);

dto.setDeptId(11);

dto.addNullFields("mobile, isAdmin");//將指定的欄位更新為null



List<UserDTO> list userService.updateBatch(dto, where().eq("sex","男"));

// list為更新過得記錄

}

}


生成的Sql語句如下:



UPDATE users

SET deptId=11,age=99,mobile=null,isAdmin=null

WHERE (sex = '男')


3.10. 更多的 插入 和更新的代碼例子



@Service

public class UnitTestService {

@Autowired UserService userService;

...



public void insert(){

//Id為資料庫自增, 新增可以獲得Id

UserDTO dto = new UserDTO();

dto.setName("張三");

dto.setSex("男");

userService.insertGetKey(dto);

logger.debug("新增用戶的Id 是 {}", dto.getId());

}



public void update(){

UserDTO user1 = new UserDTO();

user1.setAge(99);

user1.setId(1);

user1.setName("Luoping");



//將指定的欄位更新為null, 允許有空格

user1.addNullFields(" sex , lastDate , loginCount");

// //這樣寫也支持

// user1.addNullFields("sex","lastDate");

// //這樣寫也支持

// user1.addNullFields("sex, lastDate","deptId");



userService.update(user1);//只更新有值的欄位

}



public void update1(){

UserDTO user1 = new UserDTO();

user1.setAge(99);

user1.setId(1);

user1.setName("Luoping");



userService.update(user1);//只更新有值的欄位

}



public void updateList(){

UserDTO user1 = new UserDTO();

user1.setAge(99);

user1.setId(1);

user1.setName("張三");

user1.addNullFields("sex, lastDate");



UserDTO user2 = new UserDTO();

user2.setAge(88);

user2.setId(2);

user2.setName("李四");

user2.addNullFields("mobile, isAdmin");



List list = new ArrayList();

list.add(user1);

list.add(user2);

userService.updateList(list);//只更新有值的欄位

}


數據校驗組件之實戰- 重複檢查

假如用戶表中已經有一條用戶記錄的 手機號是 13588330001, 然後我們再新增一條手機號相同的用戶, 或者將其他某條記錄的手機號更新為這個手機號, 此時我們希望 程序能檢查出這個錯誤, CheckData對象就是干這個事的.

檢查用戶手機號不能重複有如下多種寫法:

3.10.1. 示例一



@Service

public class CheckData1Service extends AdvancedService<UserDao, UserDTO> {

@Override

public void beforeInsertOrUpdate(List<UserDTO> list) {

//多行記錄時只執行一句SQL完成檢查手機號是否重複, 並拋出異常

checkData(list) // 1. list是要檢查重複的數據

// 2.checkData 為TopFox在 SimpleService裡面定義的 new 一個 CheckData對象的方法

.addField("mobile", "手機號") //自定義 有異常拋出的錯誤信息的欄位的中文標題

.setWhere(where().ne("mobile","*")) //自定檢查的附加條件, 可以不寫(手機號為*的值不參與檢查)

.excute();// 生成檢查SQL, 並執行, 有結果記錄(重複)則拋出異常, 回滾事務

}

}


控制台 拋出異常 的日誌記錄如下:





##這是 inert 重複檢查 TopFox自動生成的SQL:

SELECT concat(mobile) result

FROM SecUser a

WHERE (mobile <> '*')

AND (concat(mobile) = '13588330001')

LIMIT 0,1



14:24|49.920 [4] DEBUG 182-com.topfox.util.CheckData | mobile {13588330001}

提交數據{手機號}的值{13588330001}不可重複

at com.topfox.common.CommonException$CommonString.text(CommonException.java:164)

at com.topfox.util.CheckData.excute(CheckData.java:189)

at com.topfox.util.CheckData.excute(CheckData.java:75)

at com.sec.service.UserService.beforeInsertOrUpdate(UserService.java:74)

at com.topfox.service.AdvancedService.beforeSave2(AdvancedService.java:104)

at com.topfox.service.SimpleService.updateList(SimpleService.java:280)

at com.topfox.service.SimpleService.save(SimpleService.java:451)

at com.sec.service.UserService.save(UserService.java:41)

  • 異常信息的 "手機號" 是 .addField("mobile", "手機號") 指定的中文名稱

  • 假如用戶表用兩條記錄, 第一條用戶id為001的記錄手機號為13588330001, 第一條用戶id為002的記錄手機號為13588330002.

<br>如果我們把第2條記錄用戶的手機號13588330002改為13588330001, 則會造成了 數據重複, TopFox執行的檢查重複的SQL語句為:





##這是 update時重複檢查 TopFox自動生成的SQL:

SELECT concat(mobile) result

FROM SecUser a

WHERE (mobile <> '*')

AND (concat(mobile) = '13588330001')

AND (id <> '002') ## 修改用戶手機號那條記錄的用戶Id

LIMIT 0,1


通過這個例子, 希望讀者能理解 新增和更新 TopFox 生成SQL不同的原因.

3.10.2. 更多例子請參考 << 數據校驗組件>> 章節

3.11. 更新日誌組件 ChangeManager 分散式事務 回滾有用哦

獲得修改日誌可寫入到 mongodb中, 控制分散式事務 回滾有用哦

讀取修改日誌的代碼很簡單, 共寫了2個例子, 如下:



@Service

public class UserService extends AdvancedService<UserDao, UserDTO> {

@Override

public void afterInsertOrUpdate(UserDTO userDTO, String state) {

if (DbState.UPDATE.equals(state)) {

// 例一:

ChangeManager changeManager = changeManager(userDTO)

.addFieldLabel("name", "用戶姓名") //設置該欄位的日誌輸出的中文名

.addFieldLabel("mobile", "手機號"); //設置該欄位的日誌輸出的中文名



//輸出 方式一 參數格式

logger.debug("修改日誌:{}", changeManager.output().toString() );

// 輸出樣例:

/**

修改日誌:

id:000000, //用戶的id

用戶姓名:開發者->開發者2,

手機號:13588330001->1805816881122

*/



// 輸出 方式二 JSON格式

logger.debug("修改日誌:{}", changeManager.outJSONString() );

// 輸出樣例: c是 current的簡寫, 是當前值, 新值; o是 old的簡寫, 修改之前的值

/**

修改日誌:

{

"appName":"sec",

"executeId":"1561367017351_14",

"id":"000000",

"data":{

"version":{"c":"207","o":206},

"用戶姓名":{"c":"開發者2","o":"開發者"},

"手機號":{"c":"1805816881122","o":"13588330001"}

}

}

*/



//************************************************************************************

// 例二 沒有用 addFieldLabel 設置欄位輸出的中文名, 則data中的keys輸出全部為英文

logger.debug("修改日誌:{}", changeManager(userDTO).outJSONString() );

// 輸出 JSON格式

/**

修改日誌:

{

"appName":"sec",

"executeId":"1561367017351_14",

"id":"000000",

"data":{

"version":{"c":"207","o":206},

"name":{"c":"開發者2","o":"開發者"},

"mobile":{"c":"1805816881122","o":"13588330001"}

}

}

*/

//************************************************************************************

}

}

}


3.12. 流水號生成器 等等更多功能這裡不在描述





[admin ]

來源:OsChina
連結:https://www.oschina.net/news/108522/topfox-1-2-4-released
Topfox 1.2.4 發布,快速開發框架已經有30次圍觀

http://coctec.com/news/all/show-post-210769.html