中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

手機網(wǎng)站制作大約多少錢網(wǎng)站建設公司業(yè)務

手機網(wǎng)站制作大約多少錢,網(wǎng)站建設公司業(yè)務,溫州微網(wǎng)站制作哪里有,石灣網(wǎng)站設計這篇文章我先和大家分析一下 RuoYi-Vue 腳手架中 DataScope 注解的實現(xiàn)原理,在 TienChin 項目視頻中到時候還會有深入講解。 1. 思路分析 首先我們先來捋一捋這里的權限實現(xiàn)的思路。 DataScope 注解處理的內(nèi)容叫做數(shù)據(jù)權限,就是說你這個用戶登錄后能夠…

這篇文章我先和大家分析一下 RuoYi-Vue 腳手架中 @DataScope 注解的實現(xiàn)原理,在 TienChin 項目視頻中到時候還會有深入講解。

1. 思路分析

首先我們先來捋一捋這里的權限實現(xiàn)的思路。

@DataScope 注解處理的內(nèi)容叫做數(shù)據(jù)權限,就是說你這個用戶登錄后能夠訪問哪些數(shù)據(jù)。傳統(tǒng)的做法就是根據(jù)當前認證用戶的 id 或者角色或者權限等信息去查詢,但是這種做法比較麻煩比較費事,每次查詢都要寫大量 SQL,而這些 SQL 中又有大量雷同的地方,所以我們希望能夠?qū)⒅M行統(tǒng)一處理,進而就引出了 @DataScope 注解。

在 RuoYi-Vue 腳手架中,將用戶的數(shù)據(jù)權限分為了五類,分別如下:

1:這個表示全部數(shù)據(jù)權限,也就是這個用戶登錄上來之后可以訪問所有的數(shù)據(jù),一般來說只有超級管理員具備此權限。
2:這個表示自定義數(shù)據(jù)權限,自定義數(shù)據(jù)權限就表示根據(jù)用戶的角色查找到這個用戶可以操作哪個部門的數(shù)據(jù),以此為依據(jù)進行數(shù)據(jù)查詢。
3:這個表示部門數(shù)據(jù)權限,這個簡單,就是這個用戶只能查詢到本部門的數(shù)據(jù)。
4:這個表示本部門及以下數(shù)據(jù)權限,這個意思就是用戶可以查詢到本部門以及本部門下面子部門的數(shù)據(jù)。
5:這個就表示這個用戶僅僅只能查看自己的數(shù)據(jù)。

在 TienChin 這個項目中,數(shù)據(jù)權限也基本上是按照這個腳手架的設計來的,我們只需要搞懂這里的實現(xiàn)思路,將來就可以隨心所欲的去自定義數(shù)據(jù)權限注解了。

2. 表結(jié)構(gòu)分析

捋清楚了思路,再來看看表結(jié)構(gòu)。

這里涉及到如下幾張表:

sys_user:用戶表
sys_role:角色表
sys_dept:部門表
sys_user_role:用戶角色關聯(lián)表
sys_role_dept:角色部門關聯(lián)表

這幾個表中有一些細節(jié)我來和大家梳理下。一個一個來看。

用戶表中有一個 dept_id 表示這個用戶所屬的部門 id,一個用戶屬于一個部門。

角色表中有一個字段叫做 data_scope,表示這個角色所對應的數(shù)據(jù)權限,取值就是 1-5,含義就是我們上面所列出來的含義,這個很重要哦。

部門表在設計的時候,有一個 ancestors 字段,通過這個字段可以非常方便的查詢一個部門的子部門。

最后兩張關聯(lián)表就沒啥好說了。

好了,這些都分析完了,我們就來看看具體的實現(xiàn)。

3. 具體實現(xiàn)

3.1 @DataScope

先來看數(shù)據(jù)權限注解的定義:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {/*** 部門表的別名*/public String deptAlias() default "";/*** 用戶表的別名*/public String userAlias() default "";
}

這個注解中有兩個屬性,一個是 deptAlias 和 userAlias。由于數(shù)據(jù)權限實現(xiàn)的核心思路就是在要執(zhí)行的 SQL 上動態(tài)追加查詢條件,那么動態(tài)追加的 SQL 必須要考慮到原本 SQL 定義時的部門表別名和用戶表別名。這兩個屬性就是用來干這事的。

所以小伙伴們可能也看出來,這個 @DataScope 跟我們以前的注解還不太一樣,以前自定義的其他注解跟業(yè)務耦合度比較小,這個 @DataScope 跟業(yè)務的耦合度則比較高,必須要看一下你業(yè)務 SQL 中對于部門表和用戶表取的別名是啥,然后配置到這個注解上。

因此,@DataScope 注解不算是一個特別靈活的注解,咱們就抱著學習的態(tài)度了解下他的實現(xiàn)方式就行了。

3.2 切面分析

注解定義好了,接下來就是切面分析了。
我把 RuoYi-Vue 腳手架中,解析這個注解的切面代碼列出來,咱們逐行進行分析。

@Aspect
@Component
public class DataScopeAspect {/*** 全部數(shù)據(jù)權限*/public static final String DATA_SCOPE_ALL = "1";/*** 自定數(shù)據(jù)權限*/public static final String DATA_SCOPE_CUSTOM = "2";/*** 部門數(shù)據(jù)權限*/public static final String DATA_SCOPE_DEPT = "3";/*** 部門及以下數(shù)據(jù)權限*/public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";/*** 僅本人數(shù)據(jù)權限*/public static final String DATA_SCOPE_SELF = "5";/*** 數(shù)據(jù)權限過濾關鍵字*/public static final String DATA_SCOPE = "dataScope";@Before("@annotation(controllerDataScope)")public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable {clearDataScope(point);handleDataScope(point, controllerDataScope);}protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope) {// 獲取當前的用戶LoginUser loginUser = SecurityUtils.getLoginUser();if (StringUtils.isNotNull(loginUser)) {SysUser currentUser = loginUser.getUser();// 如果是超級管理員,則不過濾數(shù)據(jù)if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) {dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),controllerDataScope.userAlias());}}}/*** 數(shù)據(jù)范圍過濾** @param joinPoint 切點* @param user      用戶* @param userAlias 別名*/public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) {StringBuilder sqlString = new StringBuilder();for (SysRole role : user.getRoles()) {String dataScope = role.getDataScope();if (DATA_SCOPE_ALL.equals(dataScope)) {sqlString = new StringBuilder();break;} else if (DATA_SCOPE_CUSTOM.equals(dataScope)) {sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,role.getRoleId()));} else if (DATA_SCOPE_DEPT.equals(dataScope)) {sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));} else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope)) {sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",deptAlias, user.getDeptId(), user.getDeptId()));} else if (DATA_SCOPE_SELF.equals(dataScope)) {if (StringUtils.isNotBlank(userAlias)) {sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));} else {// 數(shù)據(jù)權限為僅本人且沒有userAlias別名不查詢?nèi)魏螖?shù)據(jù)sqlString.append(" OR 1=0 ");}}}if (StringUtils.isNotBlank(sqlString.toString())) {Object params = joinPoint.getArgs()[0];if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {BaseEntity baseEntity = (BaseEntity) params;baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");}}}/*** 拼接權限sql前先清空params.dataScope參數(shù)防止注入*/private void clearDataScope(final JoinPoint joinPoint) {Object params = joinPoint.getArgs()[0];if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {BaseEntity baseEntity = (BaseEntity) params;baseEntity.getParams().put(DATA_SCOPE, "");}}
}
  1. 首先一上來就定義了五種不同的數(shù)據(jù)權限類型,這五種類型咱們前面已經(jīng)介紹過了,這里就不再贅述了。
  2. 接下來的 doBefore 方法是一個前置通知。由于 @DataScope 注解是加在 service 層的方法上,所以這里使用前置通知,為方法的執(zhí)行補充 SQL 參數(shù),具體思路是這樣:加了數(shù)據(jù)權限注解的 service 層方法的參數(shù)必須是對象,并且這個對象必須繼承自 BaseEntity,BaseEntity 中則有一個 Map 類型的 params 屬性,我們?nèi)绻枰獮?service 層方法的執(zhí)行補充一句 SQL,那么就把補充的內(nèi)容放到這個 params 變量中,補充內(nèi)容的 key 就是前面聲明的 dataScope,value 則是一句 SQL。在 doBefore 方法中先執(zhí)行 clearDataScope 去清除 params 變量中已有的內(nèi)容,防止 SQL 注入(因為這個 params 的內(nèi)容也可以從前端傳來);然后執(zhí)行 handleDataScope 方法進行數(shù)據(jù)權限的過濾。
  3. 在 handleDataScope 方法中,主要是查詢到當前的用戶,然后調(diào)用 dataScopeFilter 方法進行數(shù)據(jù)過濾,這個就是過濾的核心方法了。
  4. 由于一個用戶可能有多個角色,所以在 dataScopeFilter 方法中要先遍歷角色,不同的角色有不同的數(shù)據(jù)權限,這些不同的數(shù)據(jù)權限之間通過 OR 相連,最終生成的補充 SQL 的格式類似這樣 AND(xxx OR xxx OR xxx) 這樣,每一個 xxx 代表一個角色生成的過濾條件。
  5. 接下來就是根據(jù)各種不同的數(shù)據(jù)權限生成補充 SQL 了:如果數(shù)據(jù)權限為 1,則生成的 SQL 為空,即查詢 SQL 不添加限制條件;如果數(shù)據(jù)權限為 2,表示自定義數(shù)據(jù)權限,此時根據(jù)用戶的角色查詢出用戶的部門,生成查詢限制的 SQL;如果數(shù)據(jù)權限為 3,表示用戶的數(shù)據(jù)權限僅限于自己所在的部門,那么將用戶所屬的部門拎出來作為查詢限制;如果數(shù)據(jù)權限為 4,表示用戶的權限是自己的部門和他的子部門,那么就將用戶所屬的部門以及其子部門拎出來作為限制查詢條件;如果數(shù)據(jù)權限為 5,表示用戶的數(shù)據(jù)權限僅限于自己,即只能查看自己的數(shù)據(jù),那么就用用戶自身的 id 作為查詢的限制條件。最后,再把生成的 SQL 稍微處理下,變成 AND(xxx OR xxx OR xxx) 格式,這個就比較簡單了,就是字符串截取+字符串拼接。

好啦,大功告成,接下來我們通過幾個具體的查詢來看看這個切面的應用。

4. 案例分析

我們來看一下 @DataScope 注解三個具體的應用大家就明白了。

在 RuoYi-Vue 腳手架中,這個注解主要有三個使用場景:

查詢部門。
查詢角色。
查詢用戶。

假設我現(xiàn)在以 ry 這個用戶登錄,這個用戶的角色是普通角色,普通角色的數(shù)據(jù)權限是 2,即自定義數(shù)據(jù)權限,我們就來看看這個用戶是如何查詢數(shù)據(jù)的。

我們分別來看。

4.1 查詢部門

首先查詢部門的方法位于

org.javaboy.tienchin.system.service.impl.SysDeptServiceImpl#selectDeptList

位置,具體方法如下:

@Override
@DataScope(deptAlias = "d")
public List<SysDept> selectDeptList(SysDept dept) {return deptMapper.selectDeptList(dept);
}

這個參數(shù) SysDept 繼承自 BaseEntity,而 BaseEntity 中有一個 params 屬性,這個咱們前面也已經(jīng)介紹過了,不再贅述。

我們來看下這個 selectDeptList 方法對應的 SQL:

<sql id="selectDeptVo">select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time from sys_dept d
</sql>
<select id="selectDeptList" parameterType="SysDept" resultMap="SysDeptResult"><include refid="selectDeptVo"/>where d.del_flag = '0'<if test="deptId != null and deptId != 0">AND dept_id = #{deptId}</if><if test="parentId != null and parentId != 0">AND parent_id = #{parentId}</if><if test="deptName != null and deptName != ''">AND dept_name like concat('%', #{deptName}, '%')</if><if test="status != null and status != ''">AND status = #{status}</if><!-- 數(shù)據(jù)范圍過濾 -->${params.dataScope}order by d.parent_id, d.order_num
</select>

大家可以看到,在 SQL 的最后面有一句 ${params.dataScope},就是把在 DataScopeAspect 切面中拼接的 SQL 追加進來。

所以這個 SQL 最終的形式類似下面這樣:

select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time from sys_dept d where d.del_flag = '0' AND (d.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = 2 ) ) order by d.parent_id, d.order_num

可以看到,追加了最后面的 SQL 之后,就實現(xiàn)了數(shù)據(jù)過濾(這里是根據(jù)自定義數(shù)據(jù)權限進行過濾)。那么這里還涉及到一個細節(jié),前面 SQL 在定義時,用的表別名是什么,我們在 @DataScope 中指定的別名就要是什么。

4.2 查詢角色

首先查詢角色的方法位于 org.javaboy.tienchin.system.service.impl.SysRoleServiceImpl#selectRoleList 位置,具體方法如下:

@Override
@DataScope(deptAlias = "d")
public List<SysRole> selectRoleList(SysRole role) {return roleMapper.selectRoleList(role);
}

這個參數(shù) SysRole 繼承自 BaseEntity,而 BaseEntity 中有一個 params 屬性,這個咱們前面也已經(jīng)介紹過了,不再贅述。

我們來看下這個 selectRoleList 方法對應的 SQL:

<sql id="selectRoleVo">select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly,r.status, r.del_flag, r.create_time, r.remark from sys_role rleft join sys_user_role ur on ur.role_id = r.role_idleft join sys_user u on u.user_id = ur.user_idleft join sys_dept d on u.dept_id = d.dept_id
</sql>
<select id="selectRoleList" parameterType="SysRole" resultMap="SysRoleResult"><include refid="selectRoleVo"/>where r.del_flag = '0'<if test="roleId != null and roleId != 0">AND r.role_id = #{roleId}</if><if test="roleName != null and roleName != ''">AND r.role_name like concat('%', #{roleName}, '%')</if><if test="status != null and status != ''">AND r.status = #{status}</if><if test="roleKey != null and roleKey != ''">AND r.role_key like concat('%', #{roleKey}, '%')</if><if test="params.beginTime != null and params.beginTime != ''"><!-- 開始時間檢索 -->and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')</if><if test="params.endTime != null and params.endTime != ''"><!-- 結(jié)束時間檢索 -->and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')</if><!-- 數(shù)據(jù)范圍過濾 -->${params.dataScope}order by r.role_sort
</select>

大家可以看到,在 SQL 的最后面有一句 ${params.dataScope},就是把在 DataScopeAspect 切面中拼接的 SQL 追加進來。

所以這個 SQL 最終的形式類似下面這樣:

select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.menu_check_strictly, r.dept_check_strictly, r.status, r.del_flag, r.create_time, r.remark from sys_role r left join sys_user_role ur on ur.role_id = r.role_id left join sys_user u on u.user_id = ur.user_id left join sys_dept d on u.dept_id = d.dept_id where r.del_flag = '0' AND (d.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = 2 ) ) order by r.role_sort LIMIT ?

可以看到,追加了最后面的 SQL 之后,就實現(xiàn)了數(shù)據(jù)過濾(這里是根據(jù)自定義數(shù)據(jù)權限進行過濾)。

過濾的邏輯就是根據(jù)用戶所屬的部門 id 找到用戶 id,然后根據(jù)用戶 id 找到對應的角色 id,最后再把查詢到的角色返回。

其實我覺得查詢部門和查詢用戶進行數(shù)據(jù)過濾,這個都好理解,當前登錄用戶能夠操作哪些部門,能夠操作哪些用戶,這些都容易理解,能操作哪些角色該如何理解呢?特別是上面這個查詢 SQL 繞了一大圈,有的小伙伴可能會說,系統(tǒng)本來不就有一個 sys_role_dept 表嗎?這個表就是關聯(lián)角色信息和部門信息的,直接拿著用戶的部門 id 來這張表中查詢用戶能操作的角色 id 不就行行了?此言差矣!這里我覺得大家應該這樣來理解:用戶所屬的部門這是用戶所屬的部門,用戶能操作的部門是能操作的部門,這兩個之間沒有必然聯(lián)系。sys_user 表中的 dept_id 字段是表示這個用戶所屬的部門 id,而 sys_role_dept 表中是描述某一個角色能夠操作哪些部門,這是不一樣的,把這個捋清楚了,上面的 SQL 就好懂了。

4.3 查詢用戶

最后再來看查詢用戶。

查詢用戶的方法在 org.javaboy.tienchin.system.service.impl.SysUserServiceImpl#selectUserList 位置,對應的 SQL 如下

<select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user uleft join sys_dept d on u.dept_id = d.dept_idwhere u.del_flag = '0'<if test="userId != null and userId != 0">AND u.user_id = #{userId}</if><if test="userName != null and userName != ''">AND u.user_name like concat('%', #{userName}, '%')</if><if test="status != null and status != ''">AND u.status = #{status}</if><if test="phonenumber != null and phonenumber != ''">AND u.phonenumber like concat('%', #{phonenumber}, '%')</if><if test="params.beginTime != null and params.beginTime != ''"><!-- 開始時間檢索 -->AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')</if><if test="params.endTime != null and params.endTime != ''"><!-- 結(jié)束時間檢索 -->AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')</if><if test="deptId != null and deptId != 0">AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))</if><!-- 數(shù)據(jù)范圍過濾 -->${params.dataScope}
</select>

這個就比較容易了,根據(jù)部門查詢用戶或者就是查詢當前用戶。最終生成的 SQL 類似下面這樣(這是自定義數(shù)據(jù)權限,即根據(jù)用戶部門查找用戶):

select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u left join sys_dept d on u.dept_id = d.dept_id where u.del_flag = '0' AND (d.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = 2 ) ) LIMIT ?

5. 小結(jié)

好啦,通過上面的分析,大家對于 @DataScope 應該也認識的差不多了吧?

http://www.risenshineclean.com/news/9002.html

相關文章:

  • 建設銀行個人網(wǎng)上銀行app惠州seo外包
  • 網(wǎng)站開發(fā) 搜索北京網(wǎng)絡網(wǎng)站推廣
  • 東莞專業(yè)做網(wǎng)站公司建設網(wǎng)站的網(wǎng)站首頁
  • 自貢公司做網(wǎng)站新東方英語培訓機構(gòu)官網(wǎng)
  • 網(wǎng)站美工設計培訓學校注冊網(wǎng)站流程
  • 小說網(wǎng)站怎么建設seo網(wǎng)站優(yōu)化平臺
  • 查詢注冊過的網(wǎng)站許昌seo推廣
  • 網(wǎng)站提交了被收錄后改怎么做天津百度百科
  • 微信公眾號在線客服系統(tǒng)seo排名點擊器曝光行者seo
  • 網(wǎng)站開發(fā)難學嗎學生個人網(wǎng)頁優(yōu)秀模板
  • 網(wǎng)站開發(fā) 系統(tǒng)需求文檔專業(yè)制作網(wǎng)頁的公司
  • 制作網(wǎng)站需要哪些工具互聯(lián)網(wǎng)營銷方法有哪些
  • 紹興建設開發(fā)有限公司網(wǎng)站首頁優(yōu)化分析
  • 做網(wǎng)站前途百度權重是什么
  • 免費網(wǎng)站建設模版下載線下引流的八種推廣方式
  • 網(wǎng)站建設3要素關鍵詞優(yōu)化包含
  • 國內(nèi)做ebay用哪個網(wǎng)站杭州網(wǎng)絡整合營銷公司
  • 江岸區(qū)網(wǎng)站公司100個關鍵詞
  • 怎么創(chuàng)建網(wǎng)站頁面做一個網(wǎng)站要花多少錢
  • 三門網(wǎng)站建設百度搜一搜
  • 怎么做網(wǎng)站服務器嗎seo入門視頻
  • 想開民宿自己怎么做介紹的網(wǎng)站免費發(fā)布產(chǎn)品的網(wǎng)站
  • 如何做網(wǎng)站么google瀏覽器網(wǎng)頁版
  • 做網(wǎng)站包括備案嗎成都網(wǎng)站seo費用
  • 溫州網(wǎng)站排名優(yōu)化關鍵詞分析工具有哪些
  • 做網(wǎng)站軟文怎么弄什么是電商平臺推廣
  • 一個網(wǎng)站開發(fā)的流程怎么下載app到手機上
  • 樹脂工藝品網(wǎng)站建設公司北京優(yōu)化seo排名優(yōu)化
  • 網(wǎng)站建設優(yōu)化多少錢網(wǎng)站seo推廣排名
  • net和cn哪個做網(wǎng)站好哪個平臺視頻資源多