之前開源了一款項目骨架mall-tiny尼荆,完整繼承了mall項目的整個技術(shù)棧∵罂眩總感覺mall-tiny集成了太多中間件捅儒,過于復雜了。這次對其進行了簡化和升級振亮,使它成為了一款擁有完整權(quán)限管理功能的快速開發(fā)腳手架巧还,希望對大家有所幫助!
簡介
mall-tiny是一款基于SpringBoot+MyBatis-Plus的快速開發(fā)腳手架坊秸,擁有完整的權(quán)限管理功能麸祷,可對接Vue前端,開箱即用褒搔。
項目演示
mall-tiny項目可無縫對接mall-admin-web前端項目阶牍,秒變權(quán)限管理系統(tǒng)喷面。
技術(shù)選型
數(shù)據(jù)庫表結(jié)構(gòu)
- 化繁為簡,僅保留了權(quán)限管理功能相關(guān)的9張表磕瓷,方便自由定制咬像;
使用流程
環(huán)境搭建
簡化依賴服務,只需安裝最常用的MySql和Redis服務即可生宛,數(shù)據(jù)庫中需要導入mall_tiny.sql腳本。
開發(fā)規(guī)約
項目包結(jié)構(gòu)
src
├── common -- 用于存放通用代碼| ├── api -- 通用結(jié)果集封裝類
| ├── config -- 通用配置類
| ├── domain -- 通用封裝對象
| ├── exception -- 全局異常處理相關(guān)類
| └── service -- 通用業(yè)務類
├── config -- SpringBoot中的Java配置
├── domain -- 共用封裝對象
├── generator -- MyBatis-Plus代碼生成器
├── modules -- 存放業(yè)務代碼的基礎包
| └── ums -- 權(quán)限管理模塊業(yè)務代碼
| ├── controller -- 該模塊相關(guān)接口
| ├── dto -- 該模塊數(shù)據(jù)傳輸封裝對象
| ├── mapper -- 該模塊相關(guān)Mapper接口
| ├── model -- 該模塊相關(guān)實體類
| └── service -- 該模塊相關(guān)業(yè)務處理類
└── security -- SpringSecurity認證授權(quán)相關(guān)代碼
├── annotation -- 相關(guān)注解
├── aspect -- 相關(guān)切面
├── component -- 認證授權(quán)相關(guān)組件
├── config -- 相關(guān)配置
└── util -- 相關(guān)工具類
資源文件說明
resources
├── mapper -- MyBatis中mapper.xml存放位置
├── application.yml -- SpringBoot通用配置文件
├── application-dev.yml -- SpringBoot開發(fā)環(huán)境配置文件
├── application-prod.yml -- SpringBoot生產(chǎn)環(huán)境配置文件
└── generator.properties -- MyBatis-Plus代碼生成器配置
接口定義規(guī)則
- 創(chuàng)建表記錄:POST /{控制器路由名稱}/create
- 修改表記錄:POST /{控制器路由名稱}/update/{id}
- 刪除指定表記錄:POST /{控制器路由名稱}/delete/{id}
- 分頁查詢表記錄:GET /{控制器路由名稱}/list
- 獲取指定記錄詳情:GET /{控制器路由名稱}/{id}
- 具體參數(shù)及返回結(jié)果定義可以運行代碼查看Swagger-UI的Api文檔:http://localhost:8080/swagger-ui.html
項目運行
直接運行啟動類MallTinyApplication的main函數(shù)即可陷舅。
業(yè)務代碼開發(fā)流程
創(chuàng)建業(yè)務表
創(chuàng)建好pms模塊的所有表,需要注意的是一定要寫好表字段的注釋审洞,這樣實體類和接口文檔中就會自動生成字段說明了莱睁。
使用代碼生成器
運行MyBatisPlusGenerator類的main方法來生成代碼芒澜,可直接生成controller仰剿、service、mapper痴晦、model南吮、mapper.xml的代碼,無需手動創(chuàng)建誊酌。
- 代碼生成器支持兩種模式部凑,一種生成單表的代碼,比如只生成pms_brand表代碼可以先輸入pms碧浊,后輸入pms_brand涂邀;
- 生成代碼結(jié)構(gòu)一覽箱锐;
- 另一種直接生成整個模塊的代碼,比如生成pms模塊代碼可以先輸入pms驹止,后輸入pms_*浩聋。
編寫業(yè)務代碼
單表查詢
由于MyBatis-Plus提供的增強功能相當強大臊恋,單表查詢幾乎不用手寫SQL赡勘,直接使用ServiceImpl和BaseMapper中提供的方法即可。
比如我們的菜單管理業(yè)務實現(xiàn)類UmsMenuServiceImpl中的方法都直接使用了這些方法捞镰。
/**
* 后臺菜單管理Service實現(xiàn)類
* Created by macro on 2020/2/2.
*/
@Service
public class UmsMenuServiceImpl extends ServiceImpl<UmsMenuMapper,UmsMenu>implements UmsMenuService {
@Override
public boolean create(UmsMenu umsMenu) {
umsMenu.setCreateTime(new Date());
updateLevel(umsMenu); return save(umsMenu);
} @Override
public boolean update(Long id, UmsMenu umsMenu) {
umsMenu.setId(id); updateLevel(umsMenu); return updateById(umsMenu);
} @Override
public Page<UmsMenu> list(Long parentId, Integer pageSize, Integer pageNum) {
Page<UmsMenu> page = new Page<>(pageNum,pageSize);
QueryWrapper<UmsMenu> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(UmsMenu::getParentId,parentId) .orderByDesc(UmsMenu::getSort); return page(page,wrapper);
} @Override
public List<UmsMenuNode> treeList() {
List<UmsMenu> menuList = list(); List<UmsMenuNode> result = menuList.stream() .filter(menu -> menu.getParentId().equals(0L))
.map(menu -> covertMenuNode(menu, menuList)).collect(Collectors.toList()); return result;
} @Override
public boolean updateHidden(Long id, Integer hidden) {
UmsMenu umsMenu = new UmsMenu();
umsMenu.setId(id); umsMenu.setHidden(hidden); return updateById(umsMenu);
}}
分頁查詢
對于分頁查詢MyBatis-Plus原生支持闸与,不需要再整合其他插件毙替,直接構(gòu)造Page對象,然后調(diào)用ServiceImpl中的page方法即可践樱。
/**
* 后臺菜單管理Service實現(xiàn)類
* Created by macro on 2020/2/2.
*/
@Servicepublic class UmsMenuServiceImpl extends ServiceImpl<UmsMenuMapper,UmsMenu>implements UmsMenuService {
@Override public Page<UmsMenu> list(Long parentId, Integer pageSize, Integer pageNum) {
Page<UmsMenu> page = new Page<>(pageNum,pageSize);
QueryWrapper<UmsMenu> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(UmsMenu::getParentId,parentId) .orderByDesc(UmsMenu::getSort); return page(page,wrapper);
}}
多表查詢
對于多表查詢厂画,我們需要手寫mapper.xml中的SQL實現(xiàn),由于之前我們已經(jīng)生成了mapper.xml文件拷邢,所以我們直接在Mapper接口中定義好方法袱院,然后在mapper.xml寫好SQL實現(xiàn)即可。
- 比如說我們需要寫一個根據(jù)用戶ID獲取其分配的菜單的方法瞭稼,首先我們在UmsMenuMapper接口中添加好getMenuList方法忽洛;
/**
* <p>
* 后臺菜單表 Mapper 接口
* </p>
*
* @author macro
* @since 2020-08-21
*/
public interface UmsMenuMapper extends BaseMapper<UmsMenu> {
/**
* 根據(jù)后臺用戶ID獲取菜單
*/
List<UmsMenu> getMenuList(@Param("adminId") Long adminId);
}
- 然后在UmsMenuMapper.xml添加該方法的對應SQL實現(xiàn)即可。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.macro.mall.tiny.modules.ums.mapper.UmsMenuMapper">
<select id="getMenuList" resultType="com.macro.mall.tiny.modules.ums.model.UmsMenu">
SELECT m.id id, m.parent_id parentId, m.create_time createTime, m.title title, m.level level, m.sort sort, m.name name, m.icon icon, m.hidden hidden FROM ums_admin_role_relation arr LEFT JOIN ums_role r ON arr.role_id = r.id LEFT JOIN ums_role_menu_relation rmr ON r.id = rmr.role_id LEFT JOIN ums_menu m ON rmr.menu_id = m.id WHERE arr.admin_id = #{adminId} AND m.id IS NOT NULL GROUP BY m.id </select>
</mapper>
項目部署
mall-tiny已經(jīng)集成了Docker插件环肘,可以打包成Docker鏡像來部署
其他說明
SpringSecurity相關(guān)
由于使用了SpringSecurity來實現(xiàn)認證和授權(quán)欲虚,部分接口需要token才可以訪問,訪問需要認證授權(quán)接口流程如下悔雹。
- 訪問Swagger-UI接口文檔
- 調(diào)用登錄接口獲取token复哆;
點擊右上角Authorize按鈕輸入token腌零,然后訪問相關(guān)接口即可梯找。
請求參數(shù)校驗
默認集成了Jakarta Bean Validation參數(shù)校驗框架益涧,只需在參數(shù)對象屬性中添加javax.validation.constraints包中的注解注解即可實現(xiàn)校驗功能锈锤,這里以登錄參數(shù)校驗為例。
- 首先在登錄請求參數(shù)中添加@NotEmpty注解闲询;
/**
* 用戶登錄參數(shù)
* Created by macro on 2018/4/26.
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UmsAdminLoginParam { @NotEmpty
@ApiModelProperty(value = "用戶名",required = true)
private String username; @NotEmpty
@ApiModelProperty(value = "密碼",required = true)
private String password;}
- 然后在登錄接口中添加@Validated注解開啟參數(shù)校驗功能即可牙咏。
/**
* 后臺用戶管理
* Created by macro on 2018/4/26.
*/
@Controller
@Api(tags = "UmsAdminController", description = "后臺用戶管理")
@RequestMapping("/admin")
public class UmsAdminController {
@ApiOperation(value = "登錄以后返回token")
@RequestMapping(value = "/login", method = RequestMethod.POST)
@ResponseBody
public CommonResult login(@Validated @RequestBody UmsAdminLoginParam umsAdminLoginParam) {
String token = adminService.login(umsAdminLoginParam.getUsername(), umsAdminLoginParam.getPassword()); if (token == null) {
return CommonResult.validateFailed("用戶名或密碼錯誤");
} Map<String, String> tokenMap = new HashMap<>(); tokenMap.put("token", token);
tokenMap.put("tokenHead", tokenHead);
return CommonResult.success(tokenMap);
}}